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

diff -urN linux-2.5.8-pre2/Documentation/DocBook/Makefile linux-2.5.8-pre3/Documentation/DocBook/Makefile
--- linux-2.5.8-pre2/Documentation/DocBook/Makefile	Tue Apr  9 18:35:00 2002
+++ linux-2.5.8-pre3/Documentation/DocBook/Makefile	Tue Apr  9 18:35:17 2002
@@ -104,8 +104,8 @@
 		$(TOPDIR)/sound/sound_firmware.c \
 		$(TOPDIR)/drivers/net/wan/syncppp.c \
 		$(TOPDIR)/drivers/net/wan/z85230.c \
-		$(TOPDIR)/drivers/usb/hcd.c \
-		$(TOPDIR)/drivers/usb/usb.c \
+		$(TOPDIR)/drivers/usb/core/hcd.c \
+		$(TOPDIR)/drivers/usb/core/usb.c \
 		$(TOPDIR)/drivers/video/fbmem.c \
 		$(TOPDIR)/drivers/video/fbcmap.c \
 		$(TOPDIR)/drivers/video/fbcon.c \
diff -urN linux-2.5.8-pre2/Documentation/DocBook/kernel-api.tmpl linux-2.5.8-pre3/Documentation/DocBook/kernel-api.tmpl
--- linux-2.5.8-pre2/Documentation/DocBook/kernel-api.tmpl	Tue Apr  9 18:35:00 2002
+++ linux-2.5.8-pre3/Documentation/DocBook/kernel-api.tmpl	Tue Apr  9 18:35:17 2002
@@ -282,7 +282,7 @@
     </sect1>
 
     <sect1><title>USB Core APIs</title>
-!Edrivers/usb/usb.c
+!Edrivers/usb/core/usb.c
     </sect1>
 
     <sect1><title>Host Controller APIs</title>
@@ -290,7 +290,7 @@
     most of which implement standard register interfaces such as
     EHCI, OHCI, or UHCI.
     </para>
-!Edrivers/usb/hcd.c
+!Edrivers/usb/core/hcd.c
     </sect1>
 
   </chapter>
diff -urN linux-2.5.8-pre2/Documentation/filesystems/Locking linux-2.5.8-pre3/Documentation/filesystems/Locking
--- linux-2.5.8-pre2/Documentation/filesystems/Locking	Tue Apr  9 18:35:00 2002
+++ linux-2.5.8-pre3/Documentation/filesystems/Locking	Tue Apr  9 18:35:18 2002
@@ -65,7 +65,7 @@
 readlink:	no	no
 follow_link:	no	no
 truncate:	no	yes		(see below)
-setattr:	yes	if ATTR_SIZE
+setattr:	no	yes
 permission:	yes	no
 getattr:				(see below)
 revalidate:	no			(see below)
diff -urN linux-2.5.8-pre2/Documentation/filesystems/devfs/ChangeLog linux-2.5.8-pre3/Documentation/filesystems/devfs/ChangeLog
--- linux-2.5.8-pre2/Documentation/filesystems/devfs/ChangeLog	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/Documentation/filesystems/devfs/ChangeLog	Tue Apr  9 18:35:18 2002
@@ -1885,3 +1885,23 @@
 - Cleaned up declaration of <stat_read>
 
 - Updated README from master HTML file
+===============================================================================
+Changes for patch v209
+
+- Updated README from master HTML file
+
+- Removed silently introduced calls to lock_kernel() and
+  unlock_kernel() due to recent VFS locking changes. BKL isn't
+  required in devfs 
+
+- Changed <devfs_rmdir> to allow later additions if not yet empty
+
+- Added calls to <devfs_register_partitions> in drivers/block/blkpc.c
+  <add_partition> and <del_partition>
+
+- Fixed bug in <devfs_alloc_unique_number>: was clearing beyond
+  bitfield
+
+- Fixed bitfield data type for <devfs_*alloc_devnum>
+
+- Made major bitfield type and initialiser 64 bit safe
diff -urN linux-2.5.8-pre2/Documentation/filesystems/devfs/README linux-2.5.8-pre3/Documentation/filesystems/devfs/README
--- linux-2.5.8-pre2/Documentation/filesystems/devfs/README	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/Documentation/filesystems/devfs/README	Tue Apr  9 18:35:18 2002
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-24-JAN-2002
+4-APR-2002
 
 
 Document languages:
@@ -803,12 +803,19 @@
 
 add the following lines to your /etc/devfsd.conf file:
 
-REGISTER	^pt[sy]/.*	IGNORE
-CHANGE		^pt[sy]/.*	IGNORE
+REGISTER	^pt[sy]		IGNORE
+CREATE		^pt[sy]		IGNORE
+CHANGE		^pt[sy]		IGNORE
+DELETE		^pt[sy]		IGNORE
 REGISTER	.*		COPY	/dev-state/$devname $devpath
-CHANGE		.*		COPY	$devpath /dev-state/$devname
 CREATE		.*		COPY	$devpath /dev-state/$devname
+CHANGE		.*		COPY	$devpath /dev-state/$devname
+DELETE		.*		CFUNCTION GLOBAL unlink /dev-state/$devname
+RESTORE		/dev-state
 
+Note that the sample devfsd.conf file contains these lines,
+as well as other sample configurations you may find useful. See the
+devfsd distribution
 
 
 reboot.
@@ -872,7 +879,8 @@
 (for example, by starting with /etc/fstab), and then limiting the
 compatibility entries that devfsd creates.
 
-MAKE SURE YOU INSTALL DEVFSD BEFORE YOU BOOT A DEVFS-ENABLED KERNEL!
+IF YOU CONFIGURE TO MOUNT DEVFS AT BOOT, MAKE SURE YOU INSTALL DEVFSD
+BEFORE YOU BOOT A DEVFS-ENABLED KERNEL!
 
 Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of
 reports back. Many of these are because people are trying to run
@@ -1565,6 +1573,24 @@
 the existence of the entry should be relied upon.
 
 
+When I start devfsd, I see the error:
+Error opening file: ".devfsd"   No such file or directory?
+
+This means that devfs is not mounted. Make sure you have devfs mounted.
+
+
+How do I mount devfs?
+
+First make sure you have devfs compiled into your kernel (see
+above). Then you will either need to:
+
+set CONFIG_DEVFS_MOUNT=y in your kernel config
+pass devfs=mount to your boot loader
+mount devfs manually in your boot scripts with:
+mount -t none devfs /dev
+
+
+
 
 
 
@@ -1760,6 +1786,15 @@
 
 
 
+make sure you have enabled debugging output when configuring your
+kernel. You will need to set (at least) the following config options:
+
+CONFIG_DEVFS_DEBUG=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+
+
+
 please make sure you have the latest devfs patches applied. The
 latest kernel version might not have the latest devfs patches applied
 yet (Linus is very busy)
@@ -1768,7 +1803,10 @@
 save a copy of your complete kernel logs (preferably by
 using the dmesg programme) for later inclusion in your bug
 report. You may need to use the -s switch to increase the
-internal buffer size so you can capture all the boot messages
+internal buffer size so you can capture all the boot messages.
+Don't edit or trim the dmesg output
+
+
 
 
 try booting with devfs=dall passed to the kernel boot
@@ -1925,7 +1963,7 @@
 
 A Korean translation by viatoris@nownuri.net is available at
 
-http://viatoris.new21.org/devfs/devfs.html
+http://your.destiny.pe.kr/devfs/devfs.html
 
 
 
diff -urN linux-2.5.8-pre2/Documentation/filesystems/porting linux-2.5.8-pre3/Documentation/filesystems/porting
--- linux-2.5.8-pre2/Documentation/filesystems/porting	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/Documentation/filesystems/porting	Tue Apr  9 18:35:18 2002
@@ -116,3 +116,10 @@
 	FS_SINGLE is gone (actually, that had happened back when ->get_sb()
 went in - and hadn't been documented ;-/).  Just remove it from fs_flags
 (and see ->get_sb() entry for other actions).
+
+---
+[mandatory]
+
+->setattr() is called without BKL now.  Caller _always_ holds ->i_sem, so
+watch for ->i_sem-grabbing code that might be used by your ->setattr().
+Callers of notify_change() need ->i_sem now.
diff -urN linux-2.5.8-pre2/Documentation/i810_rng.txt linux-2.5.8-pre3/Documentation/i810_rng.txt
--- linux-2.5.8-pre2/Documentation/i810_rng.txt	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/Documentation/i810_rng.txt	Tue Apr  9 18:35:18 2002
@@ -70,6 +70,10 @@
 
 Change history:
 
+	Version 0.9.7:
+	* Support other i8xx chipsets too (by adding 82801BA(M) and
+	  82801CA(M) detection)
+
 	Version 0.9.6:
 	* Internal driver cleanups, prep for 1.0.0 release.
 
diff -urN linux-2.5.8-pre2/MAINTAINERS linux-2.5.8-pre3/MAINTAINERS
--- linux-2.5.8-pre2/MAINTAINERS	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/MAINTAINERS	Tue Apr  9 18:35:18 2002
@@ -1386,6 +1386,13 @@
 M:	mingo@redhat.com
 S:	Maintained
 
+SIS 5513 IDE CONTROLLER DRIVER
+P:      Lionel Bouton
+M:      Lionel.Bouton@inet6.fr
+W:      http://inet6.dyn.dhs.org/sponsoring/sis5513/index.html
+W:      http://gyver.homeip.net/sis5513/index.html
+S:      Maintained
+
 SIS 900/7016 FAST ETHERNET DRIVER
 P:	Ollie Lho
 M:	ollie@sis.com.tw
diff -urN linux-2.5.8-pre2/Makefile linux-2.5.8-pre3/Makefile
--- linux-2.5.8-pre2/Makefile	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/Makefile	Tue Apr  9 18:35:18 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 8
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.5.8-pre2/arch/i386/defconfig linux-2.5.8-pre3/arch/i386/defconfig
--- linux-2.5.8-pre2/arch/i386/defconfig	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/defconfig	Tue Apr  9 18:35:18 2002
@@ -826,13 +826,15 @@
 # CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI_ALT=y
 # CONFIG_USB_OHCI is not set
+CONFIG_USB_HOST=y
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -842,8 +844,6 @@
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
 
 #
 # USB Human Interface Devices (HID)
@@ -871,19 +871,28 @@
 #
 # USB Multimedia devices
 #
+# CONFIG_USB_DABUSB is not set
 
 #
 #   Video4Linux support is needed for USB Multimedia device support
 #
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
 
 #
 # USB Network adaptors
 #
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
 
 #
@@ -927,9 +936,10 @@
 #
 # USB Miscellaneous drivers
 #
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
 
 #
 # Kernel hacking
diff -urN linux-2.5.8-pre2/arch/i386/kernel/acpi.c linux-2.5.8-pre3/arch/i386/kernel/acpi.c
--- linux-2.5.8-pre2/arch/i386/kernel/acpi.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/acpi.c	Tue Apr  9 18:35:18 2002
@@ -48,6 +48,10 @@
 
 #define PREFIX			"ACPI: "
 
+extern struct acpi_boot_flags	acpi_boot;
+
+int				acpi_mp_config = 0;
+
 
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
@@ -104,13 +108,15 @@
 
 /* From mpparse.c */
 extern void __init MP_processor_info(struct mpc_config_processor *);
+extern void __init MP_ioapic_info (struct mpc_config_ioapic *);
+extern void __init MP_lintsrc_info(struct mpc_config_lintsrc *);
 
 int __init
 acpi_parse_lapic (
 	acpi_table_entry_header *header)
 {
 	struct acpi_table_lapic	*cpu = NULL;
-	struct mpc_config_processor proc_entry;
+	struct mpc_config_processor processor;
 
 	cpu = (struct acpi_table_lapic*) header;
 	if (!cpu)
@@ -134,21 +140,21 @@
 	 * the processor ID.  Processor features aren't present in
 	 * the table.
 	 */
-	proc_entry.mpc_type = MP_PROCESSOR;
-	proc_entry.mpc_apicid = cpu->id;
-	proc_entry.mpc_cpuflag = CPU_ENABLED;
+	processor.mpc_type = MP_PROCESSOR;
+	processor.mpc_apicid = cpu->id;
+	processor.mpc_cpuflag = CPU_ENABLED;
 	if (cpu->id == boot_cpu_physical_apicid) {
 		/* TBD: Circular reference trying to establish BSP */
-		proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR;
+		processor.mpc_cpuflag |= CPU_BOOTPROCESSOR;
 	}
-	proc_entry.mpc_cpufeature = (boot_cpu_data.x86 << 8)
+	processor.mpc_cpufeature = (boot_cpu_data.x86 << 8)
 		| (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
-	proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0];
-	proc_entry.mpc_reserved[0] = 0;
-	proc_entry.mpc_reserved[1] = 0;
-	proc_entry.mpc_apicver = 0x10;	/* integrated APIC */
+	processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
+	processor.mpc_reserved[0] = 0;
+	processor.mpc_reserved[1] = 0;
+	processor.mpc_apicver = 0x10;	/* Integrated APIC */
 
-	MP_processor_info(&proc_entry);
+	MP_processor_info(&processor);
 
 	total_cpus++;
 
@@ -184,7 +190,7 @@
 
 	acpi_table_print_madt_entry(header);
 
-	/* TBD: Support local APIC NMI entries */
+	/* TBD: Support lapic_nmi entries */
 
 	return 0;
 }
@@ -199,18 +205,102 @@
 	acpi_table_entry_header *header)
 {
 	struct acpi_table_ioapic *ioapic = NULL;
-	
+	/*
+	struct mpc_config_ioapic mp_ioapic;
+	struct IO_APIC_reg_01	reg_01;
+	*/
+
 	ioapic = (struct acpi_table_ioapic*) header;
 	if (!ioapic)
 		return -EINVAL;
+ 
+	acpi_table_print_madt_entry(header);
+ 
+	/*
+	 * Cobble up an entry for the IOAPIC (just as we do for LAPIC entries).
+	 * Note that we aren't doing anything with ioapic->vector, and 
+	 * mpc_apicver gets read directly from ioapic.
+	 */
+
+	/*
+	 * TBD: Complete I/O APIC support.
+	 *
+	mp_ioapic.mpc_type = MP_IOAPIC;
+	mp_ioapic.mpc_apicid = ioapic->id;
+	mp_ioapic.mpc_flags = MPC_APIC_USABLE;
+	mp_ioapic.mpc_apicaddr = ioapic->address;
+	set_fixmap_nocache(nr_ioapics + FIX_IO_APIC_BASE_0,
+		mp_ioapic.mpc_apicaddr);
+
+	printk("mapped IOAPIC to %08lx (%08lx)\n",
+		__fix_to_virt(nr_ioapics), mp_ioapic.mpc_apicaddr);
+
+	*(int *)&reg_01 = io_apic_read(nr_ioapics, 1);
+	mp_ioapic.mpc_apicver = reg_01.version;
+	MP_ioapic_info(&mp_ioapic);
+	 */
+
+	return 0;
+}
+
+
+int __init
+acpi_parse_int_src_ovr (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_int_src_ovr *int_src_ovr = NULL;
+	/*
+	struct mpc_config_intsrc my_intsrc;
+	int			i = 0;
+	*/
+
+	int_src_ovr = (struct acpi_table_int_src_ovr*) header;
+	if (!int_src_ovr)
+		return -EINVAL;
 
 	acpi_table_print_madt_entry(header);
 
-	/* TBD: Support ioapic entries */
+	/*
+	 * TBD: Complete I/O APIC support.
+	 *
+	my_intsrc.mpc_type = MP_INTSRC;
+	my_intsrc.mpc_irqtype = mp_INT;
+	my_intsrc.mpc_irqflag = *(unsigned short*)(&(int_src_ovr->flags));
+	my_intsrc.mpc_srcbus = int_src_ovr->bus;
+	my_intsrc.mpc_srcbusirq = int_src_ovr->bus_irq;
+	my_intsrc.mpc_dstapic = 0;
+	my_intsrc.mpc_dstirq = int_src_ovr->global_irq;
+
+	for (i = 0; i < mp_irq_entries; i++) {
+		if (mp_irqs[i].mpc_srcbusirq == my_intsrc.mpc_srcbusirq) {
+			mp_irqs[i] = my_intsrc;
+			break;
+		}
+	}
+	 */
+
+	return 0;
+}
+
+
+int __init
+acpi_parse_nmi_src (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_nmi_src *nmi_src = NULL;
+
+	nmi_src = (struct acpi_table_nmi_src*) header;
+	if (!nmi_src)
+		return -EINVAL;
+
+	acpi_table_print_madt_entry(header);
+
+	/* TBD: Support nimsrc entries */
 
 	return 0;
 }
 
+
 #endif /*CONFIG_X86_IO_APIC*/
 
 
@@ -288,14 +378,115 @@
 }
 
 
-#endif /*CONFIG_ACPI_BOOT*/
+int __init
+acpi_boot_init (
+	char			*cmdline)
+{
+	int			result = 0;
 
+	/* Initialize the ACPI boot-time table parser */
+	result = acpi_table_init(cmdline);
+	if (0 != result)
+		return result;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_IO_APIC
+
+	/* 
+	 * MADT
+	 * ----
+	 * Parse the Multiple APIC Description Table (MADT), if exists.
+	 * Note that this table provides platform SMP configuration 
+	 * information -- the successor to MPS tables.
+	 */
+
+	if (!acpi_boot.madt) {
+		printk(KERN_INFO PREFIX "MADT parsing disabled via command-line\n");
+		return 0;
+	}
+
+	result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+	if (0 == result) {
+		printk(KERN_WARNING PREFIX "MADT not present\n");
+		return 0;
+	}
+	else if (0 > result) {
+		printk(KERN_ERR PREFIX "Error parsing MADT\n");
+		return result;
+	}
+	else if (1 < result) 
+		printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n");
+
+	/* Local APIC */
+
+	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr);
+	if (0 > result) {
+		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
+		return result;
+	}
+
+	result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic);
+	if (1 > result) {
+		printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries!\n");
+		return -ENODEV;
+	}
+
+	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi);
+	if (0 > result) {
+		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
+		return result;
+	}
+
+	/* I/O APIC */
+
+	result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic);
+	if (1 > result) {
+		printk(KERN_ERR PREFIX "Error parsing MADT - no IOAPIC entries!\n");
+		return -ENODEV;
+	}
+
+	acpi_mp_config = 1;
+
+	/*
+	 * TBD: Complete I/O APIC support.
+	 *
+	construct_default_ACPI_table();
+	 */
+
+	result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr);
+	if (0 > result) {
+		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
+		return result;
+	}
+
+	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);
+	if (0 > result) {
+		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
+		return result;
+	}
+
+	/* Make boot-up look pretty */
+	printk("%d CPUs total\n", total_cpus);
+
+#endif /*CONFIG_X86_IO_APIC*/
+#endif /*CONFIG_X86_LOCAL_APIC*/
+
+#ifdef CONFIG_SERIAL_ACPI
+	/*
+	 * TBD: Need phased approach to table parsing (only do those absolutely
+	 *      required during boot-up).  Recommend expanding concept of fix-
+	 *      feature devices (ACPI Bus driver) to include table-based devices 
+	 *      such as serial ports, EC, SMBus, etc.
+	 */
+	/* acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);*/
+#endif /*CONFIG_SERIAL_ACPI*/
+
+	return 0;
+}
+
+#endif /*CONFIG_ACPI_BOOT*/
 
-/* --------------------------------------------------------------------------
-                            PCI Interrupt Routing Support
-   -------------------------------------------------------------------------- */
 
-#ifdef CONFIG_ACPI_PCI
 int __init
 acpi_get_interrupt_model (
 	int		*type)
@@ -304,15 +495,13 @@
 		return -EINVAL;
 
 #ifdef CONFIG_X86_IO_APIC
-	if (io_apic_assign_pci_irqs)
-		*type = ACPI_PCI_ROUTING_IOAPIC;
-	else
+	*type = ACPI_INT_MODEL_IOAPIC;
+#else
+	*type = ACPI_INT_MODEL_PIC;
 #endif
-		*type = ACPI_PCI_ROUTING_PIC;
 
 	return 0;
 }
-#endif
 
 
 /* --------------------------------------------------------------------------
diff -urN linux-2.5.8-pre2/arch/i386/kernel/acpi_wakeup.S linux-2.5.8-pre3/arch/i386/kernel/acpi_wakeup.S
--- linux-2.5.8-pre2/arch/i386/kernel/acpi_wakeup.S	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/acpi_wakeup.S	Tue Apr  9 18:35:18 2002
@@ -18,6 +18,8 @@
 
 	addw	$(wakeup_data - wakeup_code) >> 4, %ax
 	movw	%ax, %ds
+	movw	%ax, %ss
+	mov	$(wakeup_stack - wakeup_data), %sp		# Private stack is needed for ASUS board
 
 	# set up page table
 	movl	(real_save_cr3 - wakeup_data), %eax
diff -urN linux-2.5.8-pre2/arch/i386/kernel/apic.c linux-2.5.8-pre3/arch/i386/kernel/apic.c
--- linux-2.5.8-pre2/arch/i386/kernel/apic.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/apic.c	Tue Apr  9 18:35:18 2002
@@ -637,7 +637,7 @@
 		printk("Could not enable APIC!\n");
 		return -1;
 	}
-	set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability);
+	set_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
 	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
 	boot_cpu_physical_apicid = 0;
 	if (nmi_watchdog != NMI_NONE)
diff -urN linux-2.5.8-pre2/arch/i386/kernel/bluesmoke.c linux-2.5.8-pre3/arch/i386/kernel/bluesmoke.c
--- linux-2.5.8-pre2/arch/i386/kernel/bluesmoke.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/bluesmoke.c	Tue Apr  9 18:35:18 2002
@@ -284,7 +284,7 @@
 	 *	Check for MCE support
 	 */
 
-	if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) )
+	if( !test_bit(X86_FEATURE_MCE, c->x86_capability) )
 		return;	
 	
 	/*
@@ -314,7 +314,7 @@
 	 *	Check for PPro style MCA
 	 */
 	 		
-	if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
+	if( !test_bit(X86_FEATURE_MCA, c->x86_capability) )
 		return;
 		
 	/* Ok machine check is available */
diff -urN linux-2.5.8-pre2/arch/i386/kernel/entry.S linux-2.5.8-pre3/arch/i386/kernel/entry.S
--- linux-2.5.8-pre2/arch/i386/kernel/entry.S	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/entry.S	Tue Apr  9 18:35:18 2002
@@ -47,6 +47,7 @@
 #include <asm/errno.h>
 #include <asm/segment.h>
 #include <asm/smp.h>
+#include <asm/irq_vectors.h>
 
 EBX		= 0x00
 ECX		= 0x04
@@ -94,12 +95,12 @@
 
 #ifdef CONFIG_PREEMPT
 #define preempt_stop cli
-#define init_ret_intr \
-	cli; \
-	decl TI_PRE_COUNT(%ebx);
+#define INC_PRE_COUNT(reg) incl TI_PRE_COUNT(reg);
+#define DEC_PRE_COUNT(reg) decl TI_PRE_COUNT(reg);
 #else
 #define preempt_stop
-#define init_ret_intr
+#define INC_PRE_COUNT(reg)
+#define DEC_PRE_COUNT(reg)
 #define resume_kernel restore_all
 #endif
 
@@ -210,9 +211,9 @@
 
 	# userspace resumption stub bypassing syscall exit tracing
 	ALIGN
-ENTRY(ret_from_intr)
-	GET_THREAD_INFO(%ebx)
-	init_ret_intr
+ret_from_intr:
+	preempt_stop
+	DEC_PRE_COUNT(%ebx)
 ret_from_exception:
 	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
 	movb CS(%esp), %al
@@ -335,6 +336,67 @@
 	movl $-ENOSYS,EAX(%esp)
 	jmp resume_userspace
 
+/*
+ * Build the entry stubs and pointer table with
+ * some assembler magic.
+ */
+.data
+ENTRY(interrupt)
+.text
+
+vector=0
+ENTRY(irq_entries_start)
+.rept NR_IRQS
+	ALIGN
+1:	pushl $vector-256
+	jmp common_interrupt
+.data
+	.long 1b
+.text
+vector=vector+1
+.endr
+
+	ALIGN
+common_interrupt:
+	SAVE_ALL
+	GET_THREAD_INFO(%ebx)
+	INC_PRE_COUNT(%ebx)
+	call SYMBOL_NAME(do_IRQ)
+	jmp ret_from_intr
+
+#define BUILD_INTERRUPT(name, nr)	\
+ENTRY(name)				\
+	pushl $nr-256;			\
+	SAVE_ALL			\
+	GET_THREAD_INFO(%ebx);		\
+	INC_PRE_COUNT(%ebx)		\
+	call SYMBOL_NAME(smp_/**/name);	\
+	jmp ret_from_intr;
+
+/*
+ * The following vectors are part of the Linux architecture, there
+ * is no hardware IRQ pin equivalent for them, they are triggered
+ * through the ICC by us (IPIs)
+ */
+#ifdef CONFIG_SMP
+BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
+BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
+BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
+#endif
+
+/*
+ * every pentium local APIC has two 'local interrupts', with a
+ * soft-definable vector attached to both interrupts, one of
+ * which is a timer interrupt, the other one is error counter
+ * overflow. Linux uses the local APIC timer interrupt to get
+ * a much simpler SMP time architecture:
+ */
+#ifdef CONFIG_X86_LOCAL_APIC
+BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
+BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
+BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
+#endif
+
 ENTRY(divide_error)
 	pushl $0			# no error code
 	pushl $ SYMBOL_NAME(do_divide_error)
@@ -717,6 +779,8 @@
 	.long SYMBOL_NAME(sys_tkill)
 	.long SYMBOL_NAME(sys_sendfile64)
 	.long SYMBOL_NAME(sys_futex)		/* 240 */
+	.long SYMBOL_NAME(sys_sched_setaffinity)
+	.long SYMBOL_NAME(sys_sched_getaffinity)
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -urN linux-2.5.8-pre2/arch/i386/kernel/i8259.c linux-2.5.8-pre3/arch/i386/kernel/i8259.c
--- linux-2.5.8-pre2/arch/i386/kernel/i8259.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/i8259.c	Tue Apr  9 18:35:18 2002
@@ -25,102 +25,6 @@
 #include <linux/irq.h>
 
 /*
- * Common place to define all x86 IRQ vectors
- *
- * This builds up the IRQ handler stubs using some ugly macros in irq.h
- *
- * These macros create the low-level assembly IRQ routines that save
- * register context and call do_IRQ(). do_IRQ() then does all the
- * operations that are needed to keep the AT (or SMP IOAPIC)
- * interrupt-controller happy.
- */
-
-BUILD_COMMON_IRQ()
-
-#define BI(x,y) \
-	BUILD_IRQ(x##y)
-
-#define BUILD_16_IRQS(x) \
-	BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
-	BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
-	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
-	BI(x,c) BI(x,d) BI(x,e) BI(x,f)
-
-/*
- * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
- * (these are usually mapped to vectors 0x20-0x2f)
- */
-BUILD_16_IRQS(0x0)
-
-#ifdef CONFIG_X86_IO_APIC
-/*
- * The IO-APIC gives us many more interrupt sources. Most of these 
- * are unused but an SMP system is supposed to have enough memory ...
- * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
- * across the spectrum, so we really want to be prepared to get all
- * of these. Plus, more powerful systems might have more than 64
- * IO-APIC registers.
- *
- * (these are usually mapped into the 0x30-0xff vector range)
- */
-		   BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
-BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
-BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
-BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
-#endif
-
-#undef BUILD_16_IRQS
-#undef BI
-
-
-/*
- * The following vectors are part of the Linux architecture, there
- * is no hardware IRQ pin equivalent for them, they are triggered
- * through the ICC by us (IPIs)
- */
-#ifdef CONFIG_SMP
-BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
-BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
-BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
-#endif
-
-/*
- * every pentium local APIC has two 'local interrupts', with a
- * soft-definable vector attached to both interrupts, one of
- * which is a timer interrupt, the other one is error counter
- * overflow. Linux uses the local APIC timer interrupt to get
- * a much simpler SMP time architecture:
- */
-#ifdef CONFIG_X86_LOCAL_APIC
-BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
-BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
-BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
-#endif
-
-#define IRQ(x,y) \
-	IRQ##x##y##_interrupt
-
-#define IRQLIST_16(x) \
-	IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
-	IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
-	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
-	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
-
-void (*interrupt[NR_IRQS])(void) = {
-	IRQLIST_16(0x0),
-
-#ifdef CONFIG_X86_IO_APIC
-			 IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
-	IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
-	IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
-	IRQLIST_16(0xc), IRQLIST_16(0xd)
-#endif
-};
-
-#undef IRQ
-#undef IRQLIST_16
-
-/*
  * This is the 'legacy' 8259A Programmable Interrupt Controller,
  * present in the majority of PC/AT boxes.
  * plus some generic x86 specific things if generic specifics makes
diff -urN linux-2.5.8-pre2/arch/i386/kernel/io_apic.c linux-2.5.8-pre3/arch/i386/kernel/io_apic.c
--- linux-2.5.8-pre2/arch/i386/kernel/io_apic.c	Mon Mar 18 12:37:11 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/io_apic.c	Tue Apr  9 18:35:18 2002
@@ -597,7 +597,6 @@
 	return current_vector;
 }
 
-extern void (*interrupt[NR_IRQS])(void);
 static struct hw_interrupt_type ioapic_level_irq_type;
 static struct hw_interrupt_type ioapic_edge_irq_type;
 
diff -urN linux-2.5.8-pre2/arch/i386/kernel/mpparse.c linux-2.5.8-pre3/arch/i386/kernel/mpparse.c
--- linux-2.5.8-pre2/arch/i386/kernel/mpparse.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/mpparse.c	Tue Apr  9 18:35:18 2002
@@ -14,7 +14,6 @@
 
 #include <linux/mm.h>
 #include <linux/irq.h>
-#include <linux/acpi.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/config.h>
@@ -24,6 +23,7 @@
 #include <linux/mc146818rtc.h>
 
 #include <asm/smp.h>
+#include <asm/acpi.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
@@ -31,9 +31,6 @@
 /* Have we found an MP table */
 int smp_found_config;
 
-/* Have we found an ACPI MADT table */
-int acpi_found_madt = 0;
-
 /*
  * Various Linux-internal data structures created from the
  * MP-table.
@@ -41,8 +38,6 @@
 int apic_version [MAX_APICS];
 int mp_bus_id_to_type [MAX_MP_BUSSES];
 int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_local [MAX_MP_BUSSES];
-int quad_local_to_mp_bus_id [NR_CPUS/4][4];
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
 
@@ -69,19 +64,6 @@
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
 
-/* ACPI MADT entry parsing functions */
-#ifdef CONFIG_ACPI_BOOT
-extern struct acpi_boot_flags acpi_boot;
-#ifdef CONFIG_X86_LOCAL_APIC
-extern int acpi_parse_lapic (acpi_table_entry_header *header);
-extern int acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header);
-extern int acpi_parse_lapic_nmi (acpi_table_entry_header *header);
-#endif /*CONFIG_X86_LOCAL_APIC*/
-#ifdef CONFIG_X86_IO_APIC
-extern int acpi_parse_ioapic (acpi_table_entry_header *header);
-#endif /*CONFIG_X86_IO_APIC*/
-#endif /*CONFIG_ACPI_BOOT*/
-
 /*
  * Intel MP BIOS table parsing routines:
  */
@@ -139,7 +121,7 @@
 	return n;
 }
 
-/*
+/* 
  * Have to match translation table entries to main table entries by counter
  * hence the mpc_record variable .... can't see a less disgusting way of
  * doing this ....
@@ -255,17 +237,13 @@
 static void __init MP_bus_info (struct mpc_config_bus *m)
 {
 	char str[7];
-	int quad;
 
 	memcpy(str, m->mpc_bustype, 6);
 	str[6] = 0;
 	
 	if (clustered_apic_mode) {
-		quad = translation_table[mpc_record]->trans_quad;
-		mp_bus_id_to_node[m->mpc_busid] = quad;
-		mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
-		quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid;
-		printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad);
+		mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad;
+		printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]);
 	} else {
 		Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
 	}
@@ -342,14 +320,13 @@
 
 static void __init MP_translation_info (struct mpc_config_translation *m)
 {
-	printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local);
+	printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, 
+		m->trans_quad, m->trans_global, m->trans_local);
 
 	if (mpc_record >= MAX_MPC_ENTRY) 
 		printk("MAX_MPC_ENTRY exceeded!\n");
 	else
 		translation_table[mpc_record] = m; /* stash this for later */
-	if (m->trans_quad+1 > numnodes)
-		numnodes = m->trans_quad+1;
 }
 
 /*
@@ -439,11 +416,11 @@
 
 	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
 
-	/*
-	 * Save the local APIC address, it might be non-default,
-	 * but only if we're not using the ACPI tables
+	/* 
+	 * Save the local APIC address (it might be non-default), but only 
+	 * if we're not using the ACPI tables.
 	 */
-	if (!acpi_found_madt)
+	if (!acpi_mp_config)
 		mp_lapic_addr = mpc->mpc_lapic;
 
 	if (clustered_apic_mode && mpc->mpc_oemptr) {
@@ -464,7 +441,7 @@
 					(struct mpc_config_processor *)mpt;
 
 				/* ACPI may already have provided this one for us */
-				if (!acpi_found_madt)
+				if (!acpi_mp_config)
 					MP_processor_info(m);
 				mpt += sizeof(*m);
 				count += sizeof(*m);
@@ -515,6 +492,10 @@
 		}
 		++mpc_record;
 	}
+	if (clustered_apic_mode && nr_ioapics > 2) {
+		/* don't initialise IO apics on secondary quads */
+		nr_ioapics = 2;
+	}
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
@@ -686,20 +667,6 @@
 {
 	struct intel_mp_floating *mpf = mpf_found;
 
-#ifdef CONFIG_ACPI_BOOT
-	/*
-	 * Check if the MADT exists, and if so, use it to get processor
-	 * information (ACPI_MADT_LAPIC).  The MADT supports the concept
-	 * of both logical (e.g. HT) and physical processor(s); where the
-	 * MPS only supports physical.
-	 */
-	if (acpi_boot.madt) {
-		acpi_found_madt = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
-		if (acpi_found_madt > 0)
-			acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic);
-	}
-#endif /*CONFIG_ACPI_BOOT*/
-	
 	printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
 	if (mpf->mpf_feature2 & (1<<7)) {
 		printk("    IMCR and PIC compatibility mode.\n");
diff -urN linux-2.5.8-pre2/arch/i386/kernel/mtrr.c linux-2.5.8-pre3/arch/i386/kernel/mtrr.c
--- linux-2.5.8-pre2/arch/i386/kernel/mtrr.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/mtrr.c	Tue Apr  9 18:35:18 2002
@@ -387,7 +387,7 @@
 	 return;
 
     /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
-    if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) ) {
+    if ( test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability) ) {
 	ctxt->cr4val = read_cr4();
 	write_cr4(ctxt->cr4val & (unsigned char) ~(1<<7));
     }
@@ -448,7 +448,7 @@
     write_cr0( read_cr0() & 0xbfffffff );
 
     /*  Restore value of CR4  */
-    if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) )
+    if ( test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability) )
 	write_cr4(ctxt->cr4val);
 
     /*  Re-enable interrupts locally (if enabled previously)  */
@@ -2122,7 +2122,7 @@
 
 static int __init mtrr_setup(void)
 {
-    if ( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ) {
+    if ( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) ) {
 	/* Intel (P6) standard MTRRs */
 	mtrr_if = MTRR_IF_INTEL;
 	get_mtrr = intel_get_mtrr;
@@ -2166,14 +2166,14 @@
 		break;
 	}
 
-    } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) {
+    } else if ( test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) ) {
 	/* Pre-Athlon (K6) AMD CPU MTRRs */
 	mtrr_if = MTRR_IF_AMD_K6;
 	get_mtrr = amd_get_mtrr;
 	set_mtrr_up = amd_set_mtrr_up;
 	size_or_mask  = 0xfff00000; /* 32 bits */
 	size_and_mask = 0;
-    } else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) {
+    } else if ( test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) ) {
 	/* Cyrix ARRs */
 	mtrr_if = MTRR_IF_CYRIX_ARR;
 	get_mtrr = cyrix_get_arr;
@@ -2182,7 +2182,7 @@
 	cyrix_arr_init();
 	size_or_mask  = 0xfff00000; /* 32 bits */
 	size_and_mask = 0;
-    } else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) {
+    } else if ( test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability) ) {
 	/* Centaur MCRs */
 	mtrr_if = MTRR_IF_CENTAUR_MCR;
 	get_mtrr = centaur_get_mcr;
diff -urN linux-2.5.8-pre2/arch/i386/kernel/pci-irq.c linux-2.5.8-pre3/arch/i386/kernel/pci-irq.c
--- linux-2.5.8-pre2/arch/i386/kernel/pci-irq.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/pci-irq.c	Tue Apr  9 18:35:18 2002
@@ -540,6 +540,18 @@
 		pirq_router_dev->slot_name);
 }
 
+static struct irq_info *pirq_get_info(struct pci_dev *dev)
+{
+	struct irq_routing_table *rt = pirq_table;
+	int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+	struct irq_info *info;
+
+	for (info = rt->slots; entries--; info++)
+		if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
+			return info;
+	return NULL;
+}
+
 static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
 }
@@ -557,55 +569,77 @@
 	/* TBD: Select IRQ from possible to improve routing performance. */
 
 	result = acpi_prt_get_irq(dev, pin, &irq);
-	if ((0 != result) || !irq) {
-		printk(KERN_ERR "PCI: Unable to resolve IRQ for device %s\n",
-			dev->slot_name);
+	if (!irq)
+		result = -ENODEV;
+	if (0 != result) {
+		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s\n",
+		       'A'+pin, dev->slot_name);
 		return result;
 	}
 
-	printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", irq, 
-		dev->slot_name);
-
 	dev->irq = irq;
 
-	pirq_penalty[irq]++;
+	if (!assign) {
+		/* only check for the IRQ */
+		printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", irq, 
+		       dev->slot_name);
+		return 1;
+	}
+
+	/* also assign an IRQ */
+	if (irq && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
+		result = acpi_prt_set_irq(dev, pin, irq);
+		if (0 != result) {
+			printk(KERN_WARNING "PCI: Could not assign IRQ %d to device %s\n", irq, dev->slot_name);
+			return result;
+		}
+
+		eisa_set_level_irq(irq);
+
+		printk(KERN_INFO "PCI: Assigned IRQ %d for device %s\n", irq, dev->slot_name);
+	}
 
 	return 1;
 }
 
 #endif /* CONFIG_ACPI_PCI */
 
-static struct irq_info *pirq_get_info(struct pci_dev *dev)
+static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
 {
-	struct irq_routing_table *rt = pirq_table;
-	int entries = (rt->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+	u8 pin;
 	struct irq_info *info;
-
-	for (info = rt->slots; entries--; info++)
-		if (info->bus == dev->bus->number && PCI_SLOT(info->devfn) == PCI_SLOT(dev->devfn))
-			return info;
-	return NULL;
-}
-
-static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
-{
+	int i, pirq, newirq;
+	int irq = 0;
+	u32 mask;
 	struct irq_router *r = pirq_router;
-	struct irq_info *info;
-	int  newirq, pirq, i, irq = 0;
 	struct pci_dev *dev2;
 	char *msg = NULL;
-	u32 mask;
 
-	if (!pirq_table)
+	/* Find IRQ pin */
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (!pin) {
+		DBG(" -> no interrupt pin\n");
 		return 0;
+	}
+	pin = pin - 1;
 
+#ifdef CONFIG_ACPI_PCI
+	/* Use ACPI to lookup IRQ */
+	if (pci_use_acpi_routing)
+		return acpi_lookup_irq(dev, pin, assign);
+#endif
+
+	/* Find IRQ routing entry */
+
+	if (!pirq_table)
+		return 0;
+	
 	DBG("IRQ for %s:%d", dev->slot_name, pin);
 	info = pirq_get_info(dev);
 	if (!info) {
 		DBG(" -> not found in routing table\n");
 		return 0;
 	}
-
 	pirq = info->irq[pin].link;
 	mask = info->irq[pin].bitmap;
 	if (!pirq) {
@@ -629,10 +663,6 @@
 	 * reported by the device if possible.
 	 */
 	newirq = dev->irq;
-	if (!((1 << newirq) & mask)) {
-		if ( pci_probe & PCI_USE_PIRQ_MASK) newirq = 0;
-		else printk(KERN_WARNING "PCI: IRQ %i for device %s doesn't match PIRQ mask - try pci=usepirqmask\n", newirq, dev->slot_name);
-	}
 	if (!newirq && assign) {
 		for (i = 0; i < 16; i++) {
 			if (!(mask & (1 << i)))
@@ -651,8 +681,7 @@
 		irq = pirq & 0xf;
 		DBG(" -> hardcoded IRQ %d\n", irq);
 		msg = "Hardcoded";
-	} else if ( r->get && (irq = r->get(pirq_router_dev, dev, pirq)) && \
-	((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((1 << irq) & mask)) ) {
+	} else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) {
 		DBG(" -> got IRQ %d\n", irq);
 		msg = "Found";
 	} else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) {
@@ -686,9 +715,7 @@
 			continue;
 		if (info->irq[pin].link == pirq) {
 			/* We refuse to override the dev->irq information. Give a warning! */
-		    	if ( dev2->irq && dev2->irq != irq && \
-			(!(pci_probe & PCI_USE_PIRQ_MASK) || \
-			((1 << dev2->irq) & mask)) ) {
+		    	if (dev2->irq && dev2->irq != irq) {
 		    		printk(KERN_INFO "IRQ routing conflict for %s, have irq %d, want irq %d\n",
 				       dev2->slot_name, dev2->irq, irq);
 		    		continue;
@@ -702,38 +729,20 @@
 	return 1;
 }
 
-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
-{
-	u8 pin;
-
-	/* Find IRQ routing entry */
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-	if (!pin) {
-		DBG("PCI: %s: no interrupt pin\n", dev->slot_name);
-		return 0;
-	}
-	pin -= 1;
-
-#ifdef CONFIG_ACPI_PCI
-	if (pci_use_acpi_routing)
-		return acpi_lookup_irq(dev, pin, assign);
-	else
-#endif
-		return pirq_lookup_irq(dev, pin, assign);
-}
-
 void __init pcibios_irq_init(void)
 {
 	DBG("PCI: IRQ init\n");
 
 #ifdef CONFIG_ACPI_PCI
-	if (acpi_prts.count && !(pci_probe & PCI_NO_ACPI_ROUTING)) {
-		printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-		pci_use_acpi_routing = 1;
-		return;
+	if (!(pci_probe & PCI_NO_ACPI_ROUTING)) {
+		if (acpi_prts.count) {
+			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+			pci_use_acpi_routing = 1;
+			return;
+		}
+		else
+			printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
 	}
-	if (!acpi_prts.count)
-		printk(KERN_INFO "PCI: Invalid acpi_prts [%d]\n", acpi_prts.count);
 #endif
 
 	pirq_table = pirq_find_routing_table();
diff -urN linux-2.5.8-pre2/arch/i386/kernel/setup.c linux-2.5.8-pre3/arch/i386/kernel/setup.c
--- linux-2.5.8-pre2/arch/i386/kernel/setup.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/i386/kernel/setup.c	Tue Apr  9 18:35:18 2002
@@ -612,7 +612,7 @@
 				to--;
 			if (!memcmp(from+4, "nopentium", 9)) {
 				from += 9+4;
-				clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);
+				clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability);
 			} else if (!memcmp(from+4, "exactmap", 8)) {
 				from += 8+4;
 				e820.nr_map = 0;
@@ -1121,7 +1121,7 @@
 
 	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
 	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-	clear_bit(0*32+31, &c->x86_capability);
+	clear_bit(0*32+31, c->x86_capability);
 	
 	r = get_model_name(c);
 
@@ -1132,8 +1132,8 @@
 			{
 				/* Based on AMD doc 20734R - June 2000 */
 				if ( c->x86_model == 0 ) {
-					clear_bit(X86_FEATURE_APIC, &c->x86_capability);
-					set_bit(X86_FEATURE_PGE, &c->x86_capability);
+					clear_bit(X86_FEATURE_APIC, c->x86_capability);
+					set_bit(X86_FEATURE_PGE, c->x86_capability);
 				}
 				break;
 			}
@@ -1213,7 +1213,7 @@
 				/*  Set MTRR capability flag if appropriate */
 				if (c->x86_model == 13 || c->x86_model == 9 ||
 				   (c->x86_model == 8 && c->x86_mask >= 8))
-					set_bit(X86_FEATURE_K6_MTRR, &c->x86_capability);
+					set_bit(X86_FEATURE_K6_MTRR, c->x86_capability);
 				break;
 			}
 			break;
@@ -1226,12 +1226,12 @@
 			 * here.
 			 */
 			if (c->x86_model == 6 || c->x86_model == 7) {
-				if (!test_bit(X86_FEATURE_XMM, &c->x86_capability)) {
+				if (!test_bit(X86_FEATURE_XMM, c->x86_capability)) {
 					printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
 					rdmsr(MSR_K7_HWCR, l, h);
 					l &= ~0x00008000;
 					wrmsr(MSR_K7_HWCR, l, h);
-					set_bit(X86_FEATURE_XMM, &c->x86_capability);
+					set_bit(X86_FEATURE_XMM, c->x86_capability);
 				}
 			}
 			break;
@@ -1348,12 +1348,12 @@
 
 	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
 	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-	clear_bit(0*32+31, &c->x86_capability);
+	clear_bit(0*32+31, c->x86_capability);
 
 	/* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */
-	if ( test_bit(1*32+24, &c->x86_capability) ) {
-		clear_bit(1*32+24, &c->x86_capability);
-		set_bit(X86_FEATURE_CXMMX, &c->x86_capability);
+	if ( test_bit(1*32+24, c->x86_capability) ) {
+		clear_bit(1*32+24, c->x86_capability);
+		set_bit(X86_FEATURE_CXMMX, c->x86_capability);
 	}
 
 	do_cyrix_devid(&dir0, &dir1);
@@ -1400,7 +1400,7 @@
 		} else             /* 686 */
 			p = Cx86_cb+1;
 		/* Emulate MTRRs using Cyrix's ARRs. */
-		set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
+		set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
 		/* 6x86's contain this bug */
 		c->coma_bug = 1;
 		break;
@@ -1444,7 +1444,7 @@
 			p = Cx86_cb+2;
 			c->x86_model = (dir1 & 0x20) ? 1 : 2;
 #ifndef CONFIG_CS5520
-			clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+			clear_bit(X86_FEATURE_TSC, c->x86_capability);
 #endif
 		}
 		break;
@@ -1466,7 +1466,7 @@
 	 	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
 			(c->x86_model)++;
 		/* Emulate MTRRs using Cyrix's ARRs. */
-		set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
+		set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
 		break;
 
 	case 0xf:  /* Cyrix 486 without DEVID registers */
@@ -1765,7 +1765,7 @@
 
 	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
 	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-	clear_bit(0*32+31, &c->x86_capability);
+	clear_bit(0*32+31, c->x86_capability);
 
 	switch (c->x86) {
 
@@ -1776,7 +1776,7 @@
 				fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK;
 				fcr_clr=DPDC;
 				printk(KERN_NOTICE "Disabling bugged TSC.\n");
-				clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+				clear_bit(X86_FEATURE_TSC, c->x86_capability);
 #ifdef CONFIG_X86_OOSTORE
 				winchip_create_optimal_mcr();
 				/* Enable
@@ -1855,12 +1855,12 @@
 				printk(KERN_INFO "Centaur FCR is 0x%X\n",lo);
 			}
 			/* Emulate MTRRs using Centaur's MCR. */
-			set_bit(X86_FEATURE_CENTAUR_MCR, &c->x86_capability);
+			set_bit(X86_FEATURE_CENTAUR_MCR, c->x86_capability);
 			/* Report CX8 */
-			set_bit(X86_FEATURE_CX8, &c->x86_capability);
+			set_bit(X86_FEATURE_CX8, c->x86_capability);
 			/* Set 3DNow! on Winchip 2 and above. */
 			if (c->x86_model >=8)
-				set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
+				set_bit(X86_FEATURE_3DNOW, c->x86_capability);
 			/* See if we can find out some more. */
 			if ( cpuid_eax(0x80000000) >= 0x80000005 ) {
 				/* Yes, we can. */
@@ -1878,8 +1878,8 @@
 					lo |= (1<<1 | 1<<7);	/* Report CX8 & enable PGE */
 					wrmsr (MSR_VIA_FCR, lo, hi);
 
-					set_bit(X86_FEATURE_CX8, &c->x86_capability);
-					set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
+					set_bit(X86_FEATURE_CX8, c->x86_capability);
+					set_bit(X86_FEATURE_3DNOW, c->x86_capability);
 
 					get_model_name(c);
 					display_cacheinfo(c);
@@ -1973,7 +1973,7 @@
 		"movl $0x2333313a, %%edx\n\t"
 		"cpuid\n\t" : : : "eax", "ebx", "ecx", "edx"
 	);
-	set_bit(X86_FEATURE_CX8, &c->x86_capability);
+	set_bit(X86_FEATURE_CX8, c->x86_capability);
 }
 
 
@@ -2123,7 +2123,7 @@
 
 	/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */
 	if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 )
-		clear_bit(X86_FEATURE_SEP, &c->x86_capability);
+		clear_bit(X86_FEATURE_SEP, c->x86_capability);
 	
 	/* Names for the Pentium II/Celeron processors 
 	   detectable only by also checking the cache size.
@@ -2153,7 +2153,7 @@
 		strcpy(c->x86_model_id, p);
 	
 #ifdef CONFIG_SMP
-	if (test_bit(X86_FEATURE_HT, &c->x86_capability)) {
+	if (test_bit(X86_FEATURE_HT, c->x86_capability)) {
 		extern	int phys_proc_id[NR_CPUS];
 		
 		u32 	eax, ebx, ecx, edx;
@@ -2322,7 +2322,7 @@
 
 static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
 {
-	if( test_bit(X86_FEATURE_PN, &c->x86_capability) &&
+	if( test_bit(X86_FEATURE_PN, c->x86_capability) &&
 	    disable_x86_serial_nr ) {
 		/* Disable processor serial number */
 		unsigned long lo,hi;
@@ -2330,7 +2330,7 @@
 		lo |= 0x200000;
 		wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
 		printk(KERN_NOTICE "CPU serial number disabled.\n");
-		clear_bit(X86_FEATURE_PN, &c->x86_capability);
+		clear_bit(X86_FEATURE_PN, c->x86_capability);
 
 		/* Disabling the serial number may affect the cpuid level */
 		c->cpuid_level = cpuid_eax(0);
@@ -2496,8 +2496,9 @@
 
 		/* Intel-defined flags: level 0x00000001 */
 		if ( c->cpuid_level >= 0x00000001 ) {
-			cpuid(0x00000001, &tfms, &junk, &junk,
-			      &c->x86_capability[0]);
+			u32 capability;
+			cpuid(0x00000001, &tfms, &junk, &junk, &capability);
+			c->x86_capability[0] = capability;
 			c->x86 = (tfms >> 8) & 15;
 			c->x86_model = (tfms >> 4) & 15;
 			c->x86_mask = tfms & 15;
@@ -2523,7 +2524,7 @@
 		}
 	}
 
-	printk(KERN_DEBUG "CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n",
+	printk(KERN_DEBUG "CPU: Before vendor init, caps: %08lx %08lx %08lx, vendor = %d\n",
 	       c->x86_capability[0],
 	       c->x86_capability[1],
 	       c->x86_capability[2],
@@ -2588,7 +2589,7 @@
 
 	}
 
-	printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
+	printk(KERN_DEBUG "CPU: After vendor init, caps: %08lx %08lx %08lx %08lx\n",
 	       c->x86_capability[0],
 	       c->x86_capability[1],
 	       c->x86_capability[2],
@@ -2602,13 +2603,13 @@
 	/* TSC disabled? */
 #ifndef CONFIG_X86_TSC
 	if ( tsc_disable )
-		clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+		clear_bit(X86_FEATURE_TSC, c->x86_capability);
 #endif
 
 	/* FXSR disabled? */
 	if (disable_x86_fxsr) {
-		clear_bit(X86_FEATURE_FXSR, &c->x86_capability);
-		clear_bit(X86_FEATURE_XMM, &c->x86_capability);
+		clear_bit(X86_FEATURE_FXSR, c->x86_capability);
+		clear_bit(X86_FEATURE_XMM, c->x86_capability);
 	}
 
 	/* Disable the PN if appropriate */
@@ -2631,7 +2632,7 @@
 
 	/* Now the feature flags better reflect actual CPU features! */
 
-	printk(KERN_DEBUG "CPU:     After generic, caps: %08x %08x %08x %08x\n",
+	printk(KERN_DEBUG "CPU:     After generic, caps: %08lx %08lx %08lx %08lx\n",
 	       c->x86_capability[0],
 	       c->x86_capability[1],
 	       c->x86_capability[2],
@@ -2649,7 +2650,7 @@
 			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
 	}
 
-	printk(KERN_DEBUG "CPU:             Common caps: %08x %08x %08x %08x\n",
+	printk(KERN_DEBUG "CPU:             Common caps: %08lx %08lx %08lx %08lx\n",
 	       boot_cpu_data.x86_capability[0],
 	       boot_cpu_data.x86_capability[1],
 	       boot_cpu_data.x86_capability[2],
@@ -2759,7 +2760,7 @@
 	else
 		seq_printf(m, "stepping\t: unknown\n");
 
-	if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
+	if ( test_bit(X86_FEATURE_TSC, c->x86_capability) ) {
 		seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n",
 			cpu_khz / 1000, (cpu_khz % 1000));
 	}
@@ -2789,7 +2790,7 @@
 		     c->wp_works_ok ? "yes" : "no");
 
 	for ( i = 0 ; i < 32*NCAPINTS ; i++ )
-		if ( test_bit(i, &c->x86_capability) &&
+		if ( test_bit(i, c->x86_capability) &&
 		     x86_cap_flags[i] != NULL )
 			seq_printf(m, " %s", x86_cap_flags[i]);
 
diff -urN linux-2.5.8-pre2/arch/ppc/Config.help linux-2.5.8-pre3/arch/ppc/Config.help
--- linux-2.5.8-pre2/arch/ppc/Config.help	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/arch/ppc/Config.help	Tue Apr  9 18:35:18 2002
@@ -1033,6 +1033,16 @@
   Include in-kernel hooks for the xmon kernel monitor/debugger
   supported by the PPC port.
 
+Include BDI2000 debugger support
+CONFIG_BDI_SWITCH
+  Include in-kernel support for the Abatron BDI2000 debugger.
+
+Add additional CFLAGS to the kernel build
+CONFIG_MORE_COMPILE_OPTIONS
+  If you want to add additional CFLAGS to the kernel build, such as
+  -g for KGDB, XMON or the BDI2000, enable this option and then
+  enter what you would like to add in the next question.
+
 CONFIG_ADVANCED_OPTIONS
   This option will enable prompting for a variety of advanced kernel
   configuration options.  These options can cause the kernel to not
diff -urN linux-2.5.8-pre2/arch/ppc/config.in linux-2.5.8-pre3/arch/ppc/config.in
--- linux-2.5.8-pre2/arch/ppc/config.in	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/arch/ppc/config.in	Tue Apr  9 18:35:18 2002
@@ -24,27 +24,27 @@
 	 iSeries		CONFIG_PPC_ISERIES"	6xx
 
 if [ "$CONFIG_6xx" = "y" ]; then
-  bool 'MPC8260 CPM Support' CONFIG_8260
+   bool 'MPC8260 CPM Support' CONFIG_8260
 fi
 
 if [ "$CONFIG_POWER3" = "y" ]; then
-  define_bool CONFIG_PPC64BRIDGE y
-  define_bool CONFIG_ALL_PPC y
+   define_bool CONFIG_PPC64BRIDGE y
+   define_bool CONFIG_ALL_PPC y
 fi
 
 if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
-  define_bool CONFIG_PPC64BRIDGE y
+   define_bool CONFIG_PPC64BRIDGE y
 fi
 
 if [ "$CONFIG_6xx" = "y" -o "$CONFIG_POWER3" = "y" ]; then
-  define_bool CONFIG_PPC_STD_MMU y
+   define_bool CONFIG_PPC_STD_MMU y
 else
-  define_bool CONFIG_PPC_STD_MMU n
+   define_bool CONFIG_PPC_STD_MMU n
 fi
 
 if [ "$CONFIG_8260" = "y" ]; then
-  define_bool CONFIG_SERIAL_CONSOLE y
-  choice 'Machine Type'	\
+   define_bool CONFIG_SERIAL_CONSOLE y
+   choice 'Machine Type'	\
 	"EST8260	CONFIG_EST8260	\
 	 SBS8260	CONFIG_SBS8260	\
 	 RPXSUPER	CONFIG_RPX6	\
@@ -66,10 +66,10 @@
 fi
 
 if [ "$CONFIG_8xx" = "y" ]; then
-  define_bool CONFIG_SERIAL_CONSOLE y
-  define_bool CONFIG_NOT_COHERENT_CACHE y
+   define_bool CONFIG_SERIAL_CONSOLE y
+   define_bool CONFIG_NOT_COHERENT_CACHE y
 
-  choice 'Machine Type'		\
+   choice 'Machine Type'		\
 	"RPX-Lite	CONFIG_RPXLITE		\
 	 RPX-Classic	CONFIG_RPXCLASSIC	\
 	 BSE-IP		CONFIG_BSEIP		\
@@ -92,18 +92,18 @@
 	 MBX		CONFIG_MBX		\
 	 WinCept	CONFIG_WINCEPT"		RPX-Lite
 
-  if [ "$CONFIG_TQM823L" = "y" -o \
+   if [ "$CONFIG_TQM823L" = "y" -o \
        "$CONFIG_TQM850L" = "y" -o \
        "$CONFIG_FPS850L" = "y" -o \
        "$CONFIG_TQM855L" = "y" -o \
        "$CONFIG_TQM860L" = "y" -o \
        "$CONFIG_SM850"   = "y" ]; then
- 	define_bool	CONFIG_TQM8xxL	y
-  fi
+      define_bool CONFIG_TQM8xxL y
+   fi
 fi
 
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ]; then
-  choice 'Machine Type'		\
+   choice 'Machine Type'		\
 	"CHRP/PowerMac/PReP	CONFIG_ALL_PPC		\
 	 Amiga-APUS		CONFIG_APUS		\
 	 Cogent-Willow		CONFIG_WILLOW		\
@@ -125,133 +125,130 @@
 	 Zynx-ZX4500		CONFIG_ZX4500"		CHRP/PowerMac/PReP
 fi
 
-if [ "$CONFIG_PCORE" = "y" \
-  -o "$CONFIG_POWERPMC250" = "y" ]; then
-  define_bool CONFIG_FORCE y
+if [ "$CONFIG_PCORE" = "y" -o "$CONFIG_POWERPMC250" = "y" ]; then
+   define_bool CONFIG_FORCE y
 fi
 
-if [ "$CONFIG_FORCE" = "y" \
-  -o "$CONFIG_MENF1" = "y" \
-  -o "$CONFIG_SANDPOINT" = "y" \
-  -o "$CONFIG_ZX4500" = "y" ]; then
-  bool 'Enable MPC10x store gathering' CONFIG_MPC10X_STORE_GATHERING
+if [ "$CONFIG_FORCE" = "y" -o "$CONFIG_MENF1" = "y" \
+     -o "$CONFIG_SANDPOINT" = "y" -o "$CONFIG_ZX4500" = "y" ]; then
+   bool 'Enable MPC10x store gathering' CONFIG_MPC10X_STORE_GATHERING
 fi
 
 if [ "$CONFIG_EV64260" = "y" ]; then
-  define_bool CONFIG_GT64260 y
-  define_int CONFIG_SERIAL_CONSOLE_BAUD 115200
+   define_bool CONFIG_GT64260 y
+   define_int CONFIG_SERIAL_CONSOLE_BAUD 115200
 fi
 
 if [ "$CONFIG_K2" = "y" ]; then
-  bool 'Enable CPC710 data gathering' CONFIG_CPC710_DATA_GATHERING
+   bool 'Enable CPC710 data gathering' CONFIG_CPC710_DATA_GATHERING
 fi
 
 if [ "$CONFIG_MVME5100" = "y" ]; then
-  bool 'MVME5100 configured with an IPMC761' CONFIG_MVME5100_IPMC761_PRESENT
+   bool 'MVME5100 configured with an IPMC761' CONFIG_MVME5100_IPMC761_PRESENT
 fi
 
 if [ "$CONFIG_SANDPOINT" = "y" ]; then
-  bool 'Sandpoint X3' CONFIG_SANDPOINT_X3
-  if [ "$CONFIG_SANDPOINT_X3" = "y" ]; then
-    define_bool CONFIG_EPIC_SERIAL_MODE y
-  fi
+   bool 'Sandpoint X3' CONFIG_SANDPOINT_X3
+   if [ "$CONFIG_SANDPOINT_X3" = "y" ]; then
+      define_bool CONFIG_EPIC_SERIAL_MODE y
+   fi
 fi
 
 if [ "$CONFIG_SPRUCE" = "y" ]; then
-  bool 'Spruce baud clock support' CONFIG_SPRUCE_BAUD_33M
+   bool 'Spruce baud clock support' CONFIG_SPRUCE_BAUD_33M
 fi
 
 if [ "$CONFIG_PPC_STD_MMU" != "y" ]; then
-  define_bool CONFIG_ALL_PPC n
+   define_bool CONFIG_ALL_PPC n
 fi
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_SMP" = "y" ]; then
-  bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
+   bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
 fi
 define_bool CONFIG_PREEMPT n
 
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
-  bool 'AltiVec Support' CONFIG_ALTIVEC
-  bool 'Thermal Management Support' CONFIG_TAU
-  if [ "$CONFIG_TAU" = "y" ]; then
-    bool '    Interrupt driven TAU driver (DANGEROUS)' CONFIG_TAU_INT
-    bool '    Average high and low temp' CONFIG_TAU_AVERAGE
-  fi
+   bool 'AltiVec Support' CONFIG_ALTIVEC
+   bool 'Thermal Management Support' CONFIG_TAU
+   if [ "$CONFIG_TAU" = "y" ]; then
+      bool '    Interrupt driven TAU driver (DANGEROUS)' CONFIG_TAU_INT
+      bool '    Average high and low temp' CONFIG_TAU_AVERAGE
+   fi
 fi
 
 if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then
-  bool 'Math emulation' CONFIG_MATH_EMULATION
+   bool 'Math emulation' CONFIG_MATH_EMULATION
 fi
 
 if [ "$CONFIG_4xx" = "y" ]; then
 # It's often necessary to know the specific 4xx processor type.
 # Fortunately, it is impled (so far) from the board type, so we
 # don't need to ask more redundant questions.
- if [ "$CONFIG_ASH" = "y" ]; then
-    define_bool CONFIG_NP405H y
-    define_bool CONFIG_TREEBOOT y
-    define_bool CONFIG_IBM405_ERR77 y
-    define_bool CONFIG_IBM_OCP y
-  fi
-  if [ "$CONFIG_CEDER" = "y" ]; then
-    define_bool CONFIG_NP405L y
-    define_bool CONFIG_BIOS_FIXUP y
-    define_bool CONFIG_TREEBOOT y
-    define_bool CONFIG_IBM405_ERR77 y
-    define_bool CONFIG_IBM_OCP y
-  fi
-  if [ "$CONFIG_CPCI405" = "y" ]; then
-    define_bool CONFIG_405GP y
-    define_bool CONFIG_IBM405_ERR77 y
-    define_bool CONFIG_IBM_OCP y
-  fi
-  if [ "$CONFIG_EP405" = "y" ]; then
-    define_bool CONFIG_405GP y
-    define_bool CONFIG_BIOS_FIXUP y
-    define_bool CONFIG_EMBEDDEDBOOT y
-    define_bool CONFIG_IBM405_ERR77 y
-    define_bool CONFIG_IBM_OCP y
-  fi
-  if [ "$CONFIG_OAK" = "y" -o "$CONFIG_TIVO" = "y" ]; then
-    define_bool CONFIG_403GCX y
-    define_bool CONFIG_TREEBOOT y
-  fi
-  if [ "$CONFIG_REDWOOD_4" = "y" ]; then
-    define_bool CONFIG_STB03xxx y
-    define_bool CONFIG_TREEBOOT y
-    define_bool CONFIG_IBM405_ERR77 y
-    define_bool CONFIG_IBM_OCP y
-  fi
-  if [ "$CONFIG_REDWOOD_5" = "y" ]; then
-    define_bool CONFIG_STB03xxx y
-    define_bool CONFIG_TREEBOOT y
-    define_bool CONFIG_IBM405_ERR77 y
-    define_bool CONFIG_IBM_OCP y
-  fi
-  if [ "$CONFIG_WALNUT" = "y" ]; then
-    define_bool CONFIG_405GP y
-    define_bool CONFIG_BIOS_FIXUP y
-    define_bool CONFIG_TREEBOOT y
-    define_bool CONFIG_IBM405_ERR77 y
-    define_bool CONFIG_IBM_OCP y
-  fi
+   if [ "$CONFIG_ASH" = "y" ]; then
+      define_bool CONFIG_NP405H y
+      define_bool CONFIG_TREEBOOT y
+      define_bool CONFIG_IBM405_ERR77 y
+      define_bool CONFIG_IBM_OCP y
+   fi
+   if [ "$CONFIG_CEDER" = "y" ]; then
+      define_bool CONFIG_NP405L y
+      define_bool CONFIG_BIOS_FIXUP y
+      define_bool CONFIG_TREEBOOT y
+      define_bool CONFIG_IBM405_ERR77 y
+      define_bool CONFIG_IBM_OCP y
+   fi
+   if [ "$CONFIG_CPCI405" = "y" ]; then
+      define_bool CONFIG_405GP y
+      define_bool CONFIG_IBM405_ERR77 y
+      define_bool CONFIG_IBM_OCP y
+   fi
+   if [ "$CONFIG_EP405" = "y" ]; then
+      define_bool CONFIG_405GP y
+      define_bool CONFIG_BIOS_FIXUP y
+      define_bool CONFIG_EMBEDDEDBOOT y
+      define_bool CONFIG_IBM405_ERR77 y
+      define_bool CONFIG_IBM_OCP y
+   fi
+   if [ "$CONFIG_OAK" = "y" -o "$CONFIG_TIVO" = "y" ]; then
+      define_bool CONFIG_403GCX y
+      define_bool CONFIG_TREEBOOT y
+   fi
+   if [ "$CONFIG_REDWOOD_4" = "y" ]; then
+      define_bool CONFIG_STB03xxx y
+      define_bool CONFIG_TREEBOOT y
+      define_bool CONFIG_IBM405_ERR77 y
+      define_bool CONFIG_IBM_OCP y
+   fi
+   if [ "$CONFIG_REDWOOD_5" = "y" ]; then
+      define_bool CONFIG_STB03xxx y
+      define_bool CONFIG_TREEBOOT y
+      define_bool CONFIG_IBM405_ERR77 y
+      define_bool CONFIG_IBM_OCP y
+   fi
+   if [ "$CONFIG_WALNUT" = "y" ]; then
+      define_bool CONFIG_405GP y
+      define_bool CONFIG_BIOS_FIXUP y
+      define_bool CONFIG_TREEBOOT y
+      define_bool CONFIG_IBM405_ERR77 y
+      define_bool CONFIG_IBM_OCP y
+   fi
 
-  bool 'Blue Logic DMA' CONFIG_405_DMA
-  dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL
+   bool 'Blue Logic DMA' CONFIG_405_DMA
+   dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL
 
-  if [ "$CONFIG_4xx" = "y" ]; then
-    choice 'TTYS0 device and default console'	\
+   if [ "$CONFIG_4xx" = "y" ]; then
+      choice 'TTYS0 device and default console'	\
 	"UART0  CONFIG_UART0_TTYS0		\
 	 UART1	CONFIG_UART0_TTYS1"		UART0
-  fi
+   fi
 
-  define_bool CONFIG_IBM405_ERR51 y
-  define_bool CONFIG_NOT_COHERENT_CACHE y
+   define_bool CONFIG_IBM405_ERR51 y
+   define_bool CONFIG_NOT_COHERENT_CACHE y
 fi
 
 if [ "$CONFIG_8xx" = "y" -o "$CONFIG_8260" = "y" ]; then
-    define_bool CONFIG_EMBEDDEDBOOT y
+      define_bool CONFIG_EMBEDDEDBOOT y
 fi
 endmenu
 
@@ -262,43 +259,43 @@
 dep_bool '  Support for PTEs in high memory' CONFIG_HIGHPTE $CONFIG_HIGHMEM
 bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS
 if [ "$CONFIG_ADVANCED_OPTIONS" = "y" ]; then
-  if [ "$CONFIG_HIGHMEM" = "y" ]; then
-    bool "  Set high memory pool address" CONFIG_HIGHMEM_START_BOOL
-    if [ "$CONFIG_HIGHMEM_START_BOOL" = "y" ]; then
-      hex "    Virtual start address of high memory pool" CONFIG_HIGHMEM_START 0xfe000000
-    fi
-    bool "  Set maximum low memory" CONFIG_LOWMEM_SIZE_BOOL
-    if [ "$CONFIG_LOWMEM_SIZE_BOOL" = "y" ]; then
-      hex "    Maximum low memory size (in bytes)" CONFIG_LOWMEM_SIZE 0x20000000
-    fi
-  fi
-
-  bool "Set custom kernel base address" CONFIG_KERNEL_START_BOOL
-  if [ "$CONFIG_KERNEL_START_BOOL" = "y" ]; then
-    hex "  Virtual address of kernel base" CONFIG_KERNEL_START 0xc0000000
-  fi
-  bool "Set custom user task size" CONFIG_TASK_SIZE_BOOL
-  if [ "$CONFIG_TASK_SIZE_BOOL" = "y" ]; then
-    hex "  Size of user task space" CONFIG_TASK_SIZE 0x80000000
-  fi
-  if [ "$CONFIG_8xx" = "y" ]; then
-    bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB
-  fi
-  if [ "$CONFIG_4xx" = "y" ]; then
-    bool "Pinned Kernel TLBs" CONFIG_PIN_TLB
-  fi
-  if [ "$CONFIG_ALL_PPC" = "n" ]; then
-    bool "Set the boot link/load address" CONFIG_BOOT_LOAD_BOOL
-    if [ "$CONFIG_BOOT_LOAD_BOOL" = "y" ]; then
-      hex "  Link/load address for booting" CONFIG_BOOT_LOAD 0x00400000
-    fi
-  fi
+   if [ "$CONFIG_HIGHMEM" = "y" ]; then
+      bool "  Set high memory pool address" CONFIG_HIGHMEM_START_BOOL
+      if [ "$CONFIG_HIGHMEM_START_BOOL" = "y" ]; then
+         hex "    Virtual start address of high memory pool" CONFIG_HIGHMEM_START 0xfe000000
+      fi
+      bool "  Set maximum low memory" CONFIG_LOWMEM_SIZE_BOOL
+      if [ "$CONFIG_LOWMEM_SIZE_BOOL" = "y" ]; then
+         hex "    Maximum low memory size (in bytes)" CONFIG_LOWMEM_SIZE 0x20000000
+      fi
+   fi
+
+   bool "Set custom kernel base address" CONFIG_KERNEL_START_BOOL
+   if [ "$CONFIG_KERNEL_START_BOOL" = "y" ]; then
+      hex "  Virtual address of kernel base" CONFIG_KERNEL_START 0xc0000000
+   fi
+   bool "Set custom user task size" CONFIG_TASK_SIZE_BOOL
+   if [ "$CONFIG_TASK_SIZE_BOOL" = "y" ]; then
+      hex "  Size of user task space" CONFIG_TASK_SIZE 0x80000000
+   fi
+   if [ "$CONFIG_8xx" = "y" ]; then
+      bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB
+   fi
+   if [ "$CONFIG_4xx" = "y" ]; then
+      bool "Pinned Kernel TLBs" CONFIG_PIN_TLB
+   fi
+   if [ "$CONFIG_ALL_PPC" != "y" ]; then
+      bool "Set the boot link/load address" CONFIG_BOOT_LOAD_BOOL
+      if [ "$CONFIG_BOOT_LOAD_BOOL" = "y" ]; then
+         hex "  Link/load address for booting" CONFIG_BOOT_LOAD 0x00400000
+      fi
+   fi
 fi
 
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
-  bool 'Support for ISA-bus hardware' CONFIG_ISA
+   bool 'Support for ISA-bus hardware' CONFIG_ISA
 else
-  define_bool CONFIG_ISA n
+   define_bool CONFIG_ISA n
 fi
 define_bool CONFIG_EISA n
 define_bool CONFIG_SBUS n
@@ -307,30 +304,30 @@
 define_bool CONFIG_MCA n
 
 if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8260" = "y" ]; then
-  bool "Enable PCI" CONFIG_PCI
-  bool 'PC PS/2 style Keyboard' CONFIG_PC_KEYBOARD
+   bool "Enable PCI" CONFIG_PCI
+   bool 'PC PS/2 style Keyboard' CONFIG_PC_KEYBOARD
 else
-  if [ "$CONFIG_8xx" = "y" ]; then
-     bool 'QSpan PCI' CONFIG_PCI_QSPAN
-     define_bool CONFIG_PCI $CONFIG_PCI_QSPAN
-  else
-     if [ "$CONFIG_APUS" = "y" ]; then
-       bool 'PCI for Permedia2' CONFIG_PCI_PERMEDIA
-       define_bool CONFIG_PCI $CONFIG_PCI_PERMEDIA
-     else
-	if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
-	   bool "IBM iSeries Native I/O Support" CONFIG_PCI_ISERIES
-	   define_bool CONFIG_PCI $CONFIG_PCI_ISERIES
-	else
-	   define_bool CONFIG_PCI y
-	fi
-     fi
-  fi
+   if [ "$CONFIG_8xx" = "y" ]; then
+      bool 'QSpan PCI' CONFIG_PCI_QSPAN
+      define_bool CONFIG_PCI $CONFIG_PCI_QSPAN
+   else
+      if [ "$CONFIG_APUS" = "y" ]; then
+        bool 'PCI for Permedia2' CONFIG_PCI_PERMEDIA
+        define_bool CONFIG_PCI $CONFIG_PCI_PERMEDIA
+      else
+         if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+	    bool "IBM iSeries Native I/O Support" CONFIG_PCI_ISERIES
+	    define_bool CONFIG_PCI $CONFIG_PCI_ISERIES
+	 else
+	    define_bool CONFIG_PCI y
+	 fi
+      fi
+   fi
 fi
 
 # only elf supported, a.out is not -- Cort
 if [ "$CONFIG_PROC_FS" = "y" ]; then
-  define_bool CONFIG_KCORE_ELF y
+   define_bool CONFIG_KCORE_ELF y
 fi
 define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_KERNEL_ELF y
@@ -341,70 +338,70 @@
 bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
 
 if [ "$CONFIG_HOTPLUG" = "y" ]; then
-  source drivers/pcmcia/Config.in
+   source drivers/pcmcia/Config.in
 else
-  define_bool CONFIG_PCMCIA n
+   define_bool CONFIG_PCMCIA n
 fi
 
 source drivers/parport/Config.in
 
 if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
-  if [ "$CONFIG_APUS" != "y" ]; then
-    tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
-  else
-    bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
-  fi
+   if [ "$CONFIG_APUS" != "y" ]; then
+      tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
+   else
+      bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+   fi
 fi
 
 if [ "$CONFIG_ALL_PPC" = "y" -a "$CONFIG_POWER3" = "n" ] ; then
-  bool 'Workarounds for PPC601 bugs' CONFIG_PPC601_SYNC_FIX
+   bool 'Workarounds for PPC601 bugs' CONFIG_PPC601_SYNC_FIX
 fi
 
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
-  bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
-  bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS
-  bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL
+   bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+   bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS
+   bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL
 fi
 
 bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL
 if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
-  string 'Initial kernel command string' CONFIG_CMDLINE "console=ttyS0,9600 console=tty0 root=/dev/sda2"
+   string 'Initial kernel command string' CONFIG_CMDLINE "console=ttyS0,9600 console=tty0 root=/dev/sda2"
 fi
 
 if [ "$CONFIG_APUS" = "y" ]; then
-  define_bool CONFIG_FB_CONSOLE y
-  define_bool CONFIG_AMIGA y
-  define_bool CONFIG_ZORRO y
-  define_bool CONFIG_AMIGAMOUSE y
-  define_bool CONFIG_ABSTRACT_CONSOLE y
-  define_bool CONFIG_FB y
-  define_bool CONFIG_MOUSE y
-  define_bool CONFIG_BUSMOUSE y
-  define_bool CONFIG_APUS_FAST_EXCEPT y
-
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'Amiga 1200/600 PCMCIA support' CONFIG_AMIGA_PCMCIA
-  fi
-
-  tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
-  tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
-  dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
-  dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
-  tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   define_bool CONFIG_FB_CONSOLE y
+   define_bool CONFIG_AMIGA y
+   define_bool CONFIG_ZORRO y
+   define_bool CONFIG_AMIGAMOUSE y
+   define_bool CONFIG_ABSTRACT_CONSOLE y
+   define_bool CONFIG_FB y
+   define_bool CONFIG_MOUSE y
+   define_bool CONFIG_BUSMOUSE y
+   define_bool CONFIG_APUS_FAST_EXCEPT y
+
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'Amiga 1200/600 PCMCIA support' CONFIG_AMIGA_PCMCIA
+   fi
+
+   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
+   tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
+   dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
+   dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
+   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
-  fi
-  if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
-    tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
-    tristate 'PCMCIA NE2000 support' CONFIG_APNE
-  fi
-  if [ "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o "$CONFIG_GVPIOEXT" = "y" -o \
-       "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
-    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
-  fi
-  bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
-  bool '/proc/hardware support' CONFIG_PROC_HARDWARE
-  source drivers/zorro/Config.in
+   fi
+   if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+      tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
+      tristate 'PCMCIA NE2000 support' CONFIG_APNE
+   fi
+   if [ "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o "$CONFIG_GVPIOEXT" = "y" -o \
+        "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
+      bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
+   fi
+   bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
+   bool '/proc/hardware support' CONFIG_PROC_HARDWARE
+   source drivers/zorro/Config.in
 fi
 
 endmenu
@@ -414,18 +411,17 @@
 source drivers/md/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
-  source net/Config.in
+   source net/Config.in
 fi
 
 mainmenu_option next_comment
 comment 'ATA/IDE/MFM/RLL support'
 
 tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
-
 if [ "$CONFIG_IDE" != "n" ]; then
-  source drivers/ide/Config.in
+   source drivers/ide/Config.in
 else
-  define_bool CONFIG_BLK_DEV_HD n
+   define_bool CONFIG_BLK_DEV_HD n
 fi
 endmenu
 
@@ -433,7 +429,7 @@
 comment 'SCSI support'
 tristate 'SCSI support' CONFIG_SCSI
 if [ "$CONFIG_SCSI" != "n" ]; then
-  source drivers/scsi/Config.in
+   source drivers/scsi/Config.in
 fi
 endmenu
 
@@ -444,17 +440,17 @@
 source drivers/message/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'Network device support'
+   mainmenu_option next_comment
+   comment 'Network device support'
 
-  bool 'Network device support' CONFIG_NETDEVICES
-  if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    source drivers/net/Config.in
-    if [ "$CONFIG_ATM" = "y" ]; then
-      source drivers/atm/Config.in
-    fi
-  fi
-  endmenu
+   bool 'Network device support' CONFIG_NETDEVICES
+   if [ "$CONFIG_NETDEVICES" = "y" ]; then
+      source drivers/net/Config.in
+      if [ "$CONFIG_ATM" = "y" ]; then
+         source drivers/atm/Config.in
+      fi
+   fi
+   endmenu
 fi
 
 source net/ax25/Config.in
@@ -466,27 +462,26 @@
 
 tristate 'ISDN support' CONFIG_ISDN
 if [ "$CONFIG_ISDN" != "n" ]; then
-  source drivers/isdn/Config.in
+   source drivers/isdn/Config.in
 fi
 endmenu
 
 mainmenu_option next_comment
 comment 'Old CD-ROM drivers (not SCSI, not IDE)'
-
 bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-  source drivers/cdrom/Config.in
+   source drivers/cdrom/Config.in
 fi
 endmenu
 
 mainmenu_option next_comment
 comment 'Console drivers'
 if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then
-  bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
+   bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 fi
- source drivers/video/Config.in
+source drivers/video/Config.in
 if [ "$CONFIG_FB" = "y" -a "$CONFIG_ALL_PPC" = "y" ]; then
-  bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
+   bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
 fi
 endmenu
 
@@ -509,57 +504,56 @@
 	-o "$CONFIG_VIOTAPE" != "n" -o "$CONFIG_VIOCD" != "n" ]; then
       define_bool CONFIG_VIOPATH y
    fi
+   if [ "$CONFIG_VIOCD" = "y" ]; then
+      define_bool CONFIG_CD_NO_IDESCSI y
+      define_bool CONFIG_BLK_DEV_IDECD y
+   fi
    endmenu
 fi
 
-if [ "$CONFIG_VIOCD" = "y" ]; then
-   define_bool CONFIG_CD_NO_IDESCSI y
-   define_bool CONFIG_BLK_DEV_IDECD y
-fi
-
 source drivers/input/Config.in
 
 mainmenu_option next_comment
 comment 'Macintosh device drivers'
 
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
-  # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU
-  bool 'Support for CUDA based PowerMacs' CONFIG_ADB_CUDA
-  bool 'Support for PMU  based PowerMacs' CONFIG_ADB_PMU
-  if [ "$CONFIG_ADB_PMU" = "y" ]; then
-    bool '   Power management support for PowerBooks' CONFIG_PMAC_PBOOK
-    if [ "$CONFIG_PMAC_PBOOK" = "y" ]; then
-      define_bool CONFIG_PM y
-      tristate '     APM emulation' CONFIG_PMAC_APM_EMU
-    fi
-    # made a separate option since backlight may end up beeing used
-    # on non-powerbook machines (but only on PMU based ones AFAIK)
-    bool '   Backlight control for LCD screens' CONFIG_PMAC_BACKLIGHT
-  fi
-  bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
-  tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
-  if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
-    bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
-  fi
-  bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB
-  if [ "$CONFIG_ADB" = "y" ]; then
-    bool '   Include MacIO (CHRP) ADB driver' CONFIG_ADB_MACIO
-    dep_bool '   Use input layer for ADB devices' CONFIG_INPUT_ADBHID $CONFIG_INPUT
-    if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
-      bool '     Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
-      bool '     Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
-    else
-      bool '   Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD
-    fi
-  fi
-  # This is for drivers/macintosh/mac_hid.o, which is needed if the input
-  # layer is used.
-  if [ "$CONFIG_INPUT" != "n" ]; then
-    define_bool CONFIG_MAC_HID y
-  fi
-  if [ "$CONFIG_ADB_CUDA" != "n" ]; then
-    bool 'Support for ANS LCD display' CONFIG_ANSLCD
-  fi
+   # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU
+   bool 'Support for CUDA based PowerMacs' CONFIG_ADB_CUDA
+   bool 'Support for PMU  based PowerMacs' CONFIG_ADB_PMU
+   if [ "$CONFIG_ADB_PMU" = "y" ]; then
+      bool '   Power management support for PowerBooks' CONFIG_PMAC_PBOOK
+      if [ "$CONFIG_PMAC_PBOOK" = "y" ]; then
+         define_bool CONFIG_PM y
+         tristate '     APM emulation' CONFIG_PMAC_APM_EMU
+      fi
+      # made a separate option since backlight may end up beeing used
+      # on non-powerbook machines (but only on PMU based ones AFAIK)
+      bool '   Backlight control for LCD screens' CONFIG_PMAC_BACKLIGHT
+   fi
+   bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
+   tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
+   if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
+      bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   fi
+   bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB
+   if [ "$CONFIG_ADB" = "y" ]; then
+      bool '   Include MacIO (CHRP) ADB driver' CONFIG_ADB_MACIO
+      dep_bool '   Use input layer for ADB devices' CONFIG_INPUT_ADBHID $CONFIG_INPUT
+      if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
+         bool '     Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
+         bool '     Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
+      else
+         bool '   Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD
+      fi
+   fi
+   # This is for drivers/macintosh/mac_hid.o, which is needed if the input
+   # layer is used.
+   if [ "$CONFIG_INPUT" != "n" ]; then
+      define_bool CONFIG_MAC_HID y
+   fi
+   if [ "$CONFIG_ADB_CUDA" != "n" ]; then
+      bool 'Support for ANS LCD display' CONFIG_ANSLCD
+   fi
 fi
 endmenu
 
@@ -573,32 +567,31 @@
 comment 'Sound'
 tristate 'Sound card support' CONFIG_SOUND
 if [ "$CONFIG_SOUND" != "n" ]; then
-  source sound/oss/dmasound/Config.in
-  source sound/Config.in
+   source sound/oss/dmasound/Config.in
+   source sound/Config.in
 fi
-
 endmenu
 
 if [ "$CONFIG_8xx" = "y" ]; then
-source arch/ppc/8xx_io/Config.in
+   source arch/ppc/8xx_io/Config.in
 fi
 
 if [ "$CONFIG_8260" = "y" ]; then
-source arch/ppc/8260_io/Config.in
+   source arch/ppc/8260_io/Config.in
 fi
 
 if [ "$CONFIG_4xx" = "y"]; then
-  mainmenu_option next_comment
-  comment 'IBM 4xx options'
-  if [ "$CONFIG_STB03xxx" = "y" ]; then
-    bool 'STB IR Keyboard' CONFIG_STB_KB
-    bool 'SICC Serial port' CONFIG_SERIAL_SICC
-    if [ "$CONFIG_SERIAL_SICC" = "y" -a "$CONFIG_UART0_TTYS1" = "y" ]; then
-      define_bool CONFIG_UART1_DFLT_CONSOLE y	
-      define_bool CONFIG_SERIAL_SICC_CONSOLE y
+   mainmenu_option next_comment
+   comment 'IBM 4xx options'
+   if [ "$CONFIG_STB03xxx" = "y" ]; then
+      bool 'STB IR Keyboard' CONFIG_STB_KB
+      bool 'SICC Serial port' CONFIG_SERIAL_SICC
+      if [ "$CONFIG_SERIAL_SICC" = "y" -a "$CONFIG_UART0_TTYS1" = "y" ]; then
+         define_bool CONFIG_UART1_DFLT_CONSOLE y	
+         define_bool CONFIG_SERIAL_SICC_CONSOLE y
+      fi
    fi
-  fi
-  endmenu
+   endmenu
 fi
 
 source drivers/usb/Config.in
@@ -615,7 +608,7 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 bool 'Include kgdb kernel debugger' CONFIG_KGDB
 if [ "$CONFIG_KGDB" = "y" ]; then
-  choice 'Serial Port'			\
+   choice 'Serial Port'			\
 	"ttyS0	CONFIG_KGDB_TTYS0	\
 	 ttyS1	CONFIG_KGDB_TTYS1	\
 	 ttyS2	CONFIG_KGDB_TTYS2	\
@@ -624,19 +617,19 @@
 bool 'Include xmon kernel debugger' CONFIG_XMON
 bool 'Include BDI-2000 user context switcher' CONFIG_BDI_SWITCH
 if [ "$CONFIG_KGDB" = "y" -o "$CONFIG_XMON" = "y" \
-	-o "$CONFIG_BDI_SWITCH" = "y" ]; then
-  bool 'Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
-  if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then
-    string 'Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb"
-  fi
+     -o "$CONFIG_BDI_SWITCH" = "y" ]; then
+   bool 'Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
+   if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then
+      string 'Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb"
+   fi
 fi
 
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
-  bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
+   bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
 fi
 if [ "$CONFIG_MCPN765" = "y" -o "$CONFIG_SANDPOINT" = "y" \
-	-o "$CONFIG_ZX4500" = "y" -o "$CONFIG_PRPMC800" = "y" \
-	-o "$CONFIG_4xx" = "y" -o "$CONFIG_GT64260" = "y" ]; then
-  bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG
+     -o "$CONFIG_ZX4500" = "y" -o "$CONFIG_PRPMC800" = "y" \
+     -o "$CONFIG_4xx" = "y" -o "$CONFIG_GT64260" = "y" ]; then
+   bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG
 fi
 endmenu
diff -urN linux-2.5.8-pre2/arch/ppc/kernel/idle.c linux-2.5.8-pre3/arch/ppc/kernel/idle.c
--- linux-2.5.8-pre2/arch/ppc/kernel/idle.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/arch/ppc/kernel/idle.c	Tue Apr  9 18:35:18 2002
@@ -52,49 +52,45 @@
 unsigned long zero_paged_on;
 unsigned long powersave_nap;
 
-int idled(void)
+void default_idle(void)
 {
 	int do_power_save = 0;
 
 	if (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)
 		do_power_save = 1;
 
-	/* endless loop with no priority at all */
-	for (;;) {
 #ifdef CONFIG_PPC_ISERIES
-		if (!current->need_resched) {
-			/* Turn off the run light */
-			run_light_on(0);
-                	yield_shared_processor(); 
-		}
-		HMT_low();
+	if (!current->need_resched) {
+		/* Turn off the run light */
+		run_light_on(0);
+		yield_shared_processor(); 
+	}
+	HMT_low();
 #endif
 #ifdef CONFIG_SMP
-		if (!do_power_save) {
-			if (!need_resched()) {
-				set_thread_flag(TIF_POLLING_NRFLAG);
-				while (!test_thread_flag(TIF_NEED_RESCHED))
-					barrier();
-				clear_thread_flag(TIF_POLLING_NRFLAG);
-			}
+	if (!do_power_save) {
+		if (!need_resched()) {
+			set_thread_flag(TIF_POLLING_NRFLAG);
+			while (!test_thread_flag(TIF_NEED_RESCHED))
+				barrier();
+			clear_thread_flag(TIF_POLLING_NRFLAG);
 		}
+	}
 #endif
-		if (do_power_save && !need_resched())
-			power_save();
+	if (do_power_save && !need_resched())
+		power_save();
 
-		if (need_resched()) {
-			run_light_on(1);
-			schedule();
-		}
+	if (need_resched()) {
+		run_light_on(1);
+		schedule();
+	}
 #ifdef CONFIG_PPC_ISERIES
-		else {
-			run_light_on(0);
-			yield_shared_processor();
-			HMT_low();
-		}
-#endif /* CONFIG_PPC_ISERIES */
+	else {
+		run_light_on(0);
+		yield_shared_processor();
+		HMT_low();
 	}
-	return 0;
+#endif /* CONFIG_PPC_ISERIES */
 }
 
 /*
@@ -103,7 +99,8 @@
  */
 int cpu_idle(void)
 {
-	idled();
+	for (;;)
+		default_idle();
 	return 0; 
 }
 
diff -urN linux-2.5.8-pre2/arch/ppc/kernel/ppc_ksyms.c linux-2.5.8-pre3/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.5.8-pre2/arch/ppc/kernel/ppc_ksyms.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/arch/ppc/kernel/ppc_ksyms.c	Tue Apr  9 18:35:18 2002
@@ -79,6 +79,10 @@
 extern unsigned long ret_to_user_hook;
 extern unsigned long mm_ptov (unsigned long paddr);
 
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle);
+extern void consistent_free(void *vaddr);
+extern void consistent_sync(void *vaddr, size_t size, int direction);
+
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(do_signal);
 EXPORT_SYMBOL(do_syscall_trace);
diff -urN linux-2.5.8-pre2/arch/ppc/kernel/semaphore.c linux-2.5.8-pre3/arch/ppc/kernel/semaphore.c
--- linux-2.5.8-pre2/arch/ppc/kernel/semaphore.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/arch/ppc/kernel/semaphore.c	Tue Apr  9 18:35:18 2002
@@ -20,6 +20,7 @@
 #include <linux/sched.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
+#include <asm/errno.h>
 
 /*
  * Atomically update sem->count.
diff -urN linux-2.5.8-pre2/arch/ppc/kernel/signal.c linux-2.5.8-pre3/arch/ppc/kernel/signal.c
--- linux-2.5.8-pre2/arch/ppc/kernel/signal.c	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/arch/ppc/kernel/signal.c	Tue Apr  9 18:35:18 2002
@@ -594,8 +594,8 @@
 				info.si_signo = signr;
 				info.si_errno = 0;
 				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+				info.si_pid = current->parent->pid;
+				info.si_uid = current->parent->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
@@ -634,7 +634,7 @@
 			case SIGSTOP:
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+				if (!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
diff -urN linux-2.5.8-pre2/arch/ppc/mm/mmu_decl.h linux-2.5.8-pre3/arch/ppc/mm/mmu_decl.h
--- linux-2.5.8-pre2/arch/ppc/mm/mmu_decl.h	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/arch/ppc/mm/mmu_decl.h	Tue Apr  9 18:35:18 2002
@@ -22,6 +22,7 @@
  *  2 of the License, or (at your option) any later version.
  *
  */
+#include <asm/tlbflush.h>
 
 extern void mapin_ram(void);
 extern void bat_mapin_ram(void);
diff -urN linux-2.5.8-pre2/arch/ppc/mm/pgtable.c linux-2.5.8-pre3/arch/ppc/mm/pgtable.c
--- linux-2.5.8-pre2/arch/ppc/mm/pgtable.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/arch/ppc/mm/pgtable.c	Tue Apr  9 18:35:18 2002
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/highmem.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -56,6 +57,70 @@
 #define p_mapped_by_bats(x)	(0UL)
 #endif /* HAVE_BATS */
 
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+	pgd_t *ret;
+
+	if ((ret = (pgd_t *)__get_free_page(GFP_KERNEL)) != NULL)
+		clear_page(ret);
+	return ret;
+}
+
+void pgd_free(pgd_t *pgd)
+{
+	free_page((unsigned long)pgd);
+}
+
+pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte;
+	extern int mem_init_done;
+	extern void *early_get_page(void);
+	int timeout = 0;
+
+	if (mem_init_done) {
+		while ((pte = (pte_t *) __get_free_page(GFP_KERNEL)) == NULL
+		       && ++timeout < 10) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ);
+		}
+	} else
+		pte = (pte_t *) early_get_page();
+	if (pte != NULL)
+		clear_page(pte);
+	return pte;
+}
+
+struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	struct page *pte;
+	int timeout = 0;
+#ifdef CONFIG_HIGHPTE
+	int flags = GFP_KERNEL | __GFP_HIGHMEM;
+#else
+	int flags = GFP_KERNEL;
+#endif
+
+	while ((pte = alloc_pages(flags, 0)) == NULL) {
+		if (++timeout >= 10)
+			return NULL;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ);
+	}
+	clear_highpage(pte);
+	return pte;
+}
+
+void pte_free_kernel(pte_t *pte)
+{
+	free_page((unsigned long)pte);
+}
+
+void pte_free(struct page *pte)
+{
+	__free_page(pte);
+}
+
 #ifndef CONFIG_PPC_ISERIES
 void *
 ioremap(unsigned long addr, unsigned long size)
diff -urN linux-2.5.8-pre2/arch/ppc64/Makefile linux-2.5.8-pre3/arch/ppc64/Makefile
--- linux-2.5.8-pre2/arch/ppc64/Makefile	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/arch/ppc64/Makefile	Tue Apr  9 18:35:18 2002
@@ -15,9 +15,10 @@
 
 KERNELLOAD	=0xc000000000000000
 
-LINKFLAGS	= -T arch/ppc64/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
+LINKFLAGS	= -T arch/ppc64/vmlinux.lds -Bstatic \
+		-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
 CFLAGS		:= $(CFLAGS) -fsigned-char -msoft-float -pipe \
-		-Wno-uninitialized -mminimal-toc -fno-builtin
+		-Wno-uninitialized -mminimal-toc -mtraceback=full
 CPP		= $(CC) -E $(CFLAGS)
 
 
diff -urN linux-2.5.8-pre2/arch/ppc64/config.in linux-2.5.8-pre3/arch/ppc64/config.in
--- linux-2.5.8-pre2/arch/ppc64/config.in	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/arch/ppc64/config.in	Tue Apr  9 18:35:18 2002
@@ -147,6 +147,7 @@
 source drivers/video/Config.in
 endmenu
 
+source drivers/input/Config.in
 
 if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
 mainmenu_option next_comment
diff -urN linux-2.5.8-pre2/arch/ppc64/defconfig linux-2.5.8-pre3/arch/ppc64/defconfig
--- linux-2.5.8-pre2/arch/ppc64/defconfig	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/arch/ppc64/defconfig	Tue Apr  9 18:35:18 2002
@@ -449,7 +449,6 @@
 #
 # CONFIG_WATCHDOG is not set
 # CONFIG_INTEL_RNG is not set
-CONFIG_NVRAM=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/ItLpQueue.c linux-2.5.8-pre3/arch/ppc64/kernel/ItLpQueue.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/ItLpQueue.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/ItLpQueue.c	Tue Apr  9 18:35:18 2002
@@ -53,6 +53,8 @@
 	struct HvLpEvent * nextLpEvent = 
 		(struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
 	if ( nextLpEvent->xFlags.xValid ) {
+		/* rmb() needed only for weakly consistent machines (regatta) */
+		rmb();
 		/* Set pointer to next potential event */
 		lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
 				      LpEventAlign ) /
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/LparData.c linux-2.5.8-pre3/arch/ppc64/kernel/LparData.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/LparData.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/LparData.c	Tue Apr  9 18:35:18 2002
@@ -144,7 +144,9 @@
 
 struct ItIplParmsReal xItIplParmsReal = {};
 
-struct IoHriProcessorVpd xIoHriProcessorVpd[maxProcessors] = {
+#define maxPhysicalProcessors 32
+
+struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
 	{
 		xInstCacheOperandSize: 32,
 		xDataCacheOperandSize: 32,
@@ -172,7 +174,7 @@
 	0, 0,
 	26,		/* # VPD array entries */
 	10,		/* # DMA array entries */
-	maxProcessors*2, maxProcessors,	/* Max logical, physical procs */
+	maxProcessors*2, maxPhysicalProcessors,	/* Max logical, physical procs */
 	offsetof(struct ItVpdAreas,xPlicDmaToks),/* offset to DMA toks */
 	offsetof(struct ItVpdAreas,xSlicVpdAdrs),/* offset to VPD addrs */
 	offsetof(struct ItVpdAreas,xPlicDmaLens),/* offset to DMA lens */
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/Makefile linux-2.5.8-pre3/arch/ppc64/kernel/Makefile
--- linux-2.5.8-pre2/arch/ppc64/kernel/Makefile	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/Makefile	Tue Apr  9 18:35:18 2002
@@ -27,7 +27,7 @@
 			pmc.o mf_proc.o proc_pmc.o iSeries_setup.o \
 			ItLpQueue.o hvCall.o mf.o HvLpEvent.o ras.o \
 			iSeries_proc.o HvCall.o HvLpConfig.o \
-			rtc.o init_task.o
+			rtc.o init_task.o pSeries_htab.o
 
 obj-$(CONFIG_PCI) +=  pci.o pci_dn.o pci_dma.o
 obj-$(CONFIG_PPC_EEH) += eeh.o
@@ -38,18 +38,13 @@
 ifeq ($(CONFIG_PPC_PSERIES),y)
 obj-$(CONFIG_PCI) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o
 
-obj-y += rtasd.o 
+obj-y += rtasd.o nvram.o
 endif
 
 obj-$(CONFIG_KGDB) += ppc-stub.o
 
 obj-$(CONFIG_SMP) += smp.o
 
-# tibit: for matrox_init2()
-ifeq ($(CONFIG_NVRAM),y)
-   obj-$(CONFIG_NVRAM) += pmac_nvram.o
-endif
-
 obj-y += prom.o lmb.o rtas.o rtas-proc.o chrp_setup.o i8259.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/align.c linux-2.5.8-pre3/arch/ppc64/kernel/align.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/align.c	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/align.c	Tue Apr  9 18:35:18 2002
@@ -1,12 +1,12 @@
-/*
- * align.c - handle alignment exceptions for the Power PC.
+/* align.c - handle alignment exceptions for the Power PC.
  *
  * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  * Copyright (c) 1998-1999 TiVo, Inc.
  *   PowerPC 403GCX modifications.
  * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *   PowerPC 403GCX/405GP modifications.
- * Copyright (c) 2001 PPC64 team, IBM Corp
+ * Copyright (c) 2001-2002 PPC64 team, IBM Corp
+ *   64-bit and Power4 support
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -27,10 +27,8 @@
 	unsigned char flags;
 };
 
-#define	OPCD(inst)	(((inst) & 0xFC000000) >> 26)
-#define	RS(inst)	(((inst) & 0x03E00000) >> 21)
-#define	RA(inst)	(((inst) & 0x001F0000) >> 16)
-#define	IS_DFORM(code)	((code) >= 32 && (code) <= 47)
+#define IS_XFORM(inst)	(((inst) >> 26) == 31)
+#define IS_DSFORM(inst)	(((inst) >> 26) >= 56)
 
 #define INVALID	{ 0, 0 }
 
@@ -40,9 +38,7 @@
 #define F	8	/* to/from fp regs */
 #define U	0x10	/* update index register */
 #define M	0x20	/* multiple load/store */
-#define S	0x40	/* single-precision fp, or byte-swap value */
-#define HARD	0x80	/* string, stwcx. */
-#define D	0x100	/* double-word load/store */
+#define SW	0x40	/* byte swap */
 
 #define DCBZ	0x5f	/* 8xx/82xx dcbz faults when cache not enabled */
 
@@ -61,9 +57,9 @@
 	{ 2, LD+SE },		/* 00 0 0101: lha */
 	{ 2, ST },		/* 00 0 0110: sth */
 	{ 4, LD+M },		/* 00 0 0111: lmw */
-	{ 4, LD+F+S },		/* 00 0 1000: lfs */
+	{ 4, LD+F },		/* 00 0 1000: lfs */
 	{ 8, LD+F },		/* 00 0 1001: lfd */
-	{ 4, ST+F+S },		/* 00 0 1010: stfs */
+	{ 4, ST+F },		/* 00 0 1010: stfs */
 	{ 8, ST+F },		/* 00 0 1011: stfd */
 	INVALID,		/* 00 0 1100 */
 	{ 8, LD },		/* 00 0 1101: ld */
@@ -77,12 +73,12 @@
 	{ 2, LD+SE+U },		/* 00 1 0101: lhau */
 	{ 2, ST+U },		/* 00 1 0110: sthu */
 	{ 4, ST+M },		/* 00 1 0111: stmw */
-	{ 4, LD+F+S+U },	/* 00 1 1000: lfsu */
+	{ 4, LD+F+U },		/* 00 1 1000: lfsu */
 	{ 8, LD+F+U },		/* 00 1 1001: lfdu */
-	{ 4, ST+F+S+U },	/* 00 1 1010: stfsu */
+	{ 4, ST+F+U },		/* 00 1 1010: stfsu */
 	{ 8, ST+F+U },		/* 00 1 1011: stfdu */
 	INVALID,		/* 00 1 1100 */
-	{ 8, ST },		/* 00 1 1101: std */
+	INVALID,		/* 00 1 1101 */
 	INVALID,		/* 00 1 1110 */
 	INVALID,		/* 00 1 1111 */
 	{ 8, LD },		/* 01 0 0000: ldx */
@@ -90,13 +86,13 @@
 	{ 8, ST },		/* 01 0 0010: stdx */
 	INVALID,		/* 01 0 0011 */
 	INVALID,		/* 01 0 0100 */
-	INVALID,		/* 01 0 0101: lwax?? */
+	{ 4, LD+SE },		/* 01 0 0101: lwax */
 	INVALID,		/* 01 0 0110 */
 	INVALID,		/* 01 0 0111 */
-	{ 0, LD+HARD },		/* 01 0 1000: lswx */
-	{ 0, LD+HARD },		/* 01 0 1001: lswi */
-	{ 0, ST+HARD },		/* 01 0 1010: stswx */
-	{ 0, ST+HARD },		/* 01 0 1011: stswi */
+	{ 0, LD },		/* 01 0 1000: lswx */
+	{ 0, LD },		/* 01 0 1001: lswi */
+	{ 0, ST },		/* 01 0 1010: stswx */
+	{ 0, ST },		/* 01 0 1011: stswi */
 	INVALID,		/* 01 0 1100 */
 	{ 8, LD+U },		/* 01 0 1101: ldu */
 	INVALID,		/* 01 0 1110 */
@@ -106,7 +102,7 @@
 	{ 8, ST+U },		/* 01 1 0010: stdux */
 	INVALID,		/* 01 1 0011 */
 	INVALID,		/* 01 1 0100 */
-	INVALID,		/* 01 1 0101: lwaux?? */
+	{ 4, LD+SE+U },		/* 01 1 0101: lwaux */
 	INVALID,		/* 01 1 0110 */
 	INVALID,		/* 01 1 0111 */
 	INVALID,		/* 01 1 1000 */
@@ -119,19 +115,19 @@
 	INVALID,		/* 01 1 1111 */
 	INVALID,		/* 10 0 0000 */
 	INVALID,		/* 10 0 0001 */
-	{ 0, ST+HARD },		/* 10 0 0010: stwcx. */
+	{ 0, ST },		/* 10 0 0010: stwcx. */
 	INVALID,		/* 10 0 0011 */
 	INVALID,		/* 10 0 0100 */
 	INVALID,		/* 10 0 0101 */
 	INVALID,		/* 10 0 0110 */
 	INVALID,		/* 10 0 0111 */
-	{ 4, LD+S },		/* 10 0 1000: lwbrx */
+	{ 4, LD+SW },		/* 10 0 1000: lwbrx */
 	INVALID,		/* 10 0 1001 */
-	{ 4, ST+S },		/* 10 0 1010: stwbrx */
+	{ 4, ST+SW },		/* 10 0 1010: stwbrx */
 	INVALID,		/* 10 0 1011 */
-	{ 2, LD+S },		/* 10 0 1100: lhbrx */
-	INVALID,		/* 10 0 1101 */
-	{ 2, ST+S },		/* 10 0 1110: sthbrx */
+	{ 2, LD+SW },		/* 10 0 1100: lhbrx */
+	{ 4, LD+SE },		/* 10 0 1101  lwa */
+	{ 2, ST+SW },		/* 10 0 1110: sthbrx */
 	INVALID,		/* 10 0 1111 */
 	INVALID,		/* 10 1 0000 */
 	INVALID,		/* 10 1 0001 */
@@ -148,7 +144,7 @@
 	INVALID,		/* 10 1 1100 */
 	INVALID,		/* 10 1 1101 */
 	INVALID,		/* 10 1 1110 */
-	{ 0, ST+HARD },		/* 10 1 1111: dcbz */
+	{ L1_CACHE_BYTES, ST },	/* 10 1 1111: dcbz */
 	{ 4, LD },		/* 11 0 0000: lwzx */
 	INVALID,		/* 11 0 0001 */
 	{ 4, ST },		/* 11 0 0010: stwx */
@@ -157,14 +153,14 @@
 	{ 2, LD+SE },		/* 11 0 0101: lhax */
 	{ 2, ST },		/* 11 0 0110: sthx */
 	INVALID,		/* 11 0 0111 */
-	{ 4, LD+F+S },		/* 11 0 1000: lfsx */
+	{ 4, LD+F },		/* 11 0 1000: lfsx */
 	{ 8, LD+F },		/* 11 0 1001: lfdx */
-	{ 4, ST+F+S },		/* 11 0 1010: stfsx */
+	{ 4, ST+F },		/* 11 0 1010: stfsx */
 	{ 8, ST+F },		/* 11 0 1011: stfdx */
 	INVALID,		/* 11 0 1100 */
-	INVALID,		/* 11 0 1101 */
+	{ 8, LD+M },		/* 11 0 1101: lmd */
 	INVALID,		/* 11 0 1110 */
-	INVALID,		/* 11 0 1111 */
+	{ 8, ST+M },		/* 11 0 1111: stmd */
 	{ 4, LD+U },		/* 11 1 0000: lwzux */
 	INVALID,		/* 11 1 0001 */
 	{ 4, ST+U },		/* 11 1 0010: stwux */
@@ -173,9 +169,9 @@
 	{ 2, LD+SE+U },		/* 11 1 0101: lhaux */
 	{ 2, ST+U },		/* 11 1 0110: sthux */
 	INVALID,		/* 11 1 0111 */
-	{ 4, LD+F+S+U },	/* 11 1 1000: lfsux */
+	{ 4, LD+F+U },		/* 11 1 1000: lfsux */
 	{ 8, LD+F+U },		/* 11 1 1001: lfdux */
-	{ 4, ST+F+S+U },	/* 11 1 1010: stfsux */
+	{ 4, ST+F+U },		/* 11 1 1010: stfsux */
 	{ 8, ST+F+U },		/* 11 1 1011: stfdux */
 	INVALID,		/* 11 1 1100 */
 	INVALID,		/* 11 1 1101 */
@@ -185,178 +181,203 @@
 
 #define SWAP(a, b)	(t = (a), (a) = (b), (b) = t)
 
+unsigned static inline make_dsisr( unsigned instr )
+{
+	unsigned dsisr;
+	
+	/* create a DSISR value from the instruction */
+	dsisr = (instr & 0x03ff0000) >> 16;			/* bits  6:15 --> 22:31 */
+	
+	if ( IS_XFORM(instr) ) {
+		dsisr |= (instr & 0x00000006) << 14;		/* bits 29:30 --> 15:16 */
+		dsisr |= (instr & 0x00000040) << 8;		/* bit     25 -->    17 */
+		dsisr |= (instr & 0x00000780) << 3;		/* bits 21:24 --> 18:21 */
+	}
+	else {
+		dsisr |= (instr & 0x04000000) >> 12;		/* bit      5 -->    17 */
+		dsisr |= (instr & 0x78000000) >> 17;		/* bits  1: 4 --> 18:21 */
+		if ( IS_DSFORM(instr) ) {
+			dsisr |= (instr & 0x00000003) << 18;	/* bits 30:31 --> 12:13 */
+		}
+	}
+	
+	return dsisr;
+}
+
 int
 fix_alignment(struct pt_regs *regs)
 {
-	int instr, nb, flags;
-	int opcode, f1, f2, f3;
-	int i, t;
-	int reg, areg;
-	unsigned char *addr;
+	unsigned int instr, nb, flags;
+	int t;
+	unsigned long reg, areg;
+	unsigned long i;
+	int ret;
+	unsigned dsisr;
+	unsigned char *addr, *p;
+	unsigned long *lp;
 	union {
-		int l;
 		long ll;
-		float f;
-		double d;
+		double dd;
 		unsigned char v[8];
+		struct {
+			unsigned hi32;
+			int	 low32;
+		} x32;
+		struct {
+			unsigned char hi48[6];
+			short	      low16;
+		} x16;
 	} data;
 
-	if (__is_processor(PV_POWER4)) {
-		/* 
-		 * The POWER4 has a DSISR register but doesn't set it on
-		 * an alignment fault.  -- paulus
-		 */
-
-		instr = *((unsigned int *)regs->nip);
-		opcode = OPCD(instr);
-		reg = RS(instr);
-		areg = RA(instr);
-
-		if (IS_DFORM(opcode)) {
-			f1 = 0;
-			f2 = (instr & 0x04000000) >> 26;
-			f3 = (instr & 0x78000000) >> 27;
-		} else {
-			f1 = (instr & 0x00000006) >> 1;
-			f2 = (instr & 0x00000040) >> 6;
-			f3 = (instr & 0x00000780) >> 7;
-		}
-
-		instr = ((f1 << 5) | (f2 << 4) | f3);
-	} else {
-		reg = (regs->dsisr >> 5) & 0x1f;	/* source/dest register */
-		areg = regs->dsisr & 0x1f;		/* register to update */
-		instr = (regs->dsisr >> 10) & 0x7f;
-		instr |= (regs->dsisr >> 13) & 0x60;
-	}
+	/*
+	 * Return 1 on success
+	 * Return 0 if unable to handle the interrupt
+	 * Return -EFAULT if data address is bad
+	 */
+
+	dsisr = regs->dsisr;
+
+	/* Power4 doesn't set DSISR for an alignment interrupt */
+	if (__is_processor(PV_POWER4))
+		dsisr = make_dsisr( *((unsigned *)regs->nip) );
+
+	/* extract the operation and registers from the dsisr */
+	reg = (dsisr >> 5) & 0x1f;	/* source/dest register */
+	areg = dsisr & 0x1f;		/* register to update */
+	instr = (dsisr >> 10) & 0x7f;
+	instr |= (dsisr >> 13) & 0x60;
 
+	/* Lookup the operation in our table */
 	nb = aligninfo[instr].len;
-	if (nb == 0) {
-		long *p;
-		int i;
-
-		if (instr != DCBZ)
-			return 0;	/* too hard or invalid instruction */
-		/*
-		 * The dcbz (data cache block zero) instruction
-		 * gives an alignment fault if used on non-cacheable
-		 * memory.  We handle the fault mainly for the
-		 * case when we are running with the cache disabled
-		 * for debugging.
-		 */
-		p = (long *) (regs->dar & -L1_CACHE_BYTES);
-		for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i)
-			p[i] = 0;
-		return 1;
-	}
-
 	flags = aligninfo[instr].flags;
+
+	/* DAR has the operand effective address */
 	addr = (unsigned char *)regs->dar;
 
+	/* A size of 0 indicates an instruction we don't support */
+	/* we also don't support the multiples (lmw, stmw, lmd, stmd) */
+	if ((nb == 0) || (flags & M))
+		return 0;		/* too hard or invalid instruction */
+
+	/*
+	 * Special handling for dcbz
+	 * dcbz may give an alignment exception for accesses to caching inhibited
+	 * storage
+	 */
+	if (instr == DCBZ)
+		addr = (unsigned char *) ((unsigned long)addr & -L1_CACHE_BYTES);
+
 	/* Verify the address of the operand */
 	if (user_mode(regs)) {
 		if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
 			return -EFAULT;	/* bad address */
 	}
 
+	/* Force the fprs into the save area so we can reference them */
 	if ((flags & F) && (regs->msr & MSR_FP))
 		giveup_fpu(current);
-	if (flags & M)
-		return 0;		/* too hard for now */
-
-	/* If we read the operand, copy it in */
+	
+	/* If we are loading, get the data from user space */
 	if (flags & LD) {
-		if (nb == 2) {
-			data.v[0] = data.v[1] = 0;
-			if (__get_user(data.v[2], addr)
-			    || __get_user(data.v[3], addr+1))
+		data.ll = 0;
+		ret = 0;
+		p = addr;
+		switch (nb) {
+		case 8:
+			ret |= __get_user(data.v[0], p++);
+			ret |= __get_user(data.v[1], p++);
+			ret |= __get_user(data.v[2], p++);
+			ret |= __get_user(data.v[3], p++);
+		case 4:
+			ret |= __get_user(data.v[4], p++);
+			ret |= __get_user(data.v[5], p++);
+		case 2:
+			ret |= __get_user(data.v[6], p++);
+			ret |= __get_user(data.v[7], p++);
+			if (ret)
 				return -EFAULT;
-		} else {
-			for (i = 0; i < nb; ++i)
-				if (__get_user(data.v[i], addr+i))
-					return -EFAULT;
 		}
 	}
-	/* Unfortunately D (== 0x100) doesn't fit in the aligninfo[n].flags
-	   field.  So synthesize it here. */
-	if ((flags & F) == 0 && nb == 8)
-		flags |= D;
-
-	switch (flags & ~U) {
-	case LD+SE:
-		if (data.v[2] >= 0x80)
-			data.v[0] = data.v[1] = -1;
-		/* fall through */
-	case LD:
-		regs->gpr[reg] = data.l;
-		break;
-	case LD+D:
-		regs->gpr[reg] = data.ll;
-		break;
-	case LD+S:
-		if (nb == 2) {
-			SWAP(data.v[2], data.v[3]);
-		} else {
-			SWAP(data.v[0], data.v[3]);
-			SWAP(data.v[1], data.v[2]);
+	
+	/* If we are storing, get the data from the saved gpr or fpr */
+	if (flags & ST) {
+		if (flags & F) {
+			if (nb == 4) {
+				/* Doing stfs, have to convert to single */
+				enable_kernel_fp();
+				cvt_df(&current->thread.fpr[reg], (float *)&data.v[4], &current->thread.fpscr);
+			}
+			else
+				data.dd = current->thread.fpr[reg];
 		}
-		regs->gpr[reg] = data.l;
-		break;
-	case ST:
-		data.l = regs->gpr[reg];
-		break;
-	case ST+D:
-		data.ll = regs->gpr[reg];
-		break;
-	case ST+S:
-		data.l = regs->gpr[reg];
-		if (nb == 2) {
-			SWAP(data.v[2], data.v[3]);
-		} else {
-			SWAP(data.v[0], data.v[3]);
-			SWAP(data.v[1], data.v[2]);
+		else 
+			data.ll = regs->gpr[reg];
+	}
+	
+	/* Swap bytes as needed */
+	if (flags & SW) {
+		if (nb == 2)
+			SWAP(data.v[6], data.v[7]);
+		else {	/* nb must be 4 */
+			SWAP(data.v[4], data.v[7]);
+			SWAP(data.v[5], data.v[6]);
 		}
-		break;
-	case LD+F:
-		current->thread.fpr[reg] = data.d;
-		break;
-	case ST+F:
-		data.d = current->thread.fpr[reg];
-		break;
-	/* these require some floating point conversions... */
-	/* we'd like to use the assignment, but we have to compile
-	 * the kernel with -msoft-float so it doesn't use the
-	 * fp regs for copying 8-byte objects. */
-	case LD+F+S:
-		enable_kernel_fp();
-		cvt_fd(&data.f, &current->thread.fpr[reg], &current->thread.fpscr);
-		/* current->thread.fpr[reg] = data.f; */
-		break;
-	case ST+F+S:
-		enable_kernel_fp();
-		cvt_df(&current->thread.fpr[reg], &data.f, &current->thread.fpscr);
-		/* data.f = current->thread.fpr[reg]; */
-		break;
-	default:
-		printk("align: can't handle flags=%x\n", flags);
-		return 0;
 	}
-
+	
+	/* Sign extend as needed */
+	if (flags & SE) {
+		if ( nb == 2 )
+			data.ll = data.x16.low16;
+		else	/* nb must be 4 */
+			data.ll = data.x32.low32;
+	}
+	
+	/* If we are loading, move the data to the gpr or fpr */
+	if (flags & LD) {
+		if (flags & F) {
+			if (nb == 4) {
+				/* Doing lfs, have to convert to double */
+				enable_kernel_fp();
+				cvt_fd((float *)&data.v[4], &current->thread.fpr[reg], &current->thread.fpscr);
+			}
+			else
+				current->thread.fpr[reg] = data.dd;
+		}
+		else
+			regs->gpr[reg] = data.ll;
+	}
+	
+	/* If we are storing, copy the data to the user */
 	if (flags & ST) {
-		if (nb == 2) {
-			if (__put_user(data.v[2], addr)
-			    || __put_user(data.v[3], addr+1))
-				return -EFAULT;
-		} else {
-			for (i = 0; i < nb; ++i)
-				if (__put_user(data.v[i], addr+i))
-					return -EFAULT;
+		ret = 0;
+		p = addr;
+		switch (nb) {
+		case 128:	/* Special case - must be dcbz */
+			lp = (unsigned long *)p;
+			for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i)
+				ret |= __put_user(0, lp++);
+			break;
+		case 8:
+			ret |= __put_user(data.v[0], p++);
+			ret |= __put_user(data.v[1], p++);
+			ret |= __put_user(data.v[2], p++);
+			ret |= __put_user(data.v[3], p++);
+		case 4:
+			ret |= __put_user(data.v[4], p++);
+			ret |= __put_user(data.v[5], p++);
+		case 2:
+			ret |= __put_user(data.v[6], p++);
+			ret |= __put_user(data.v[7], p++);
 		}
+		if (ret)
+			return -EFAULT;
 	}
-
+	
+	/* Update RA as needed */
 	if (flags & U) {
 		regs->gpr[areg] = regs->dar;
 	}
 
 	return 1;
 }
+
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/chrp_setup.c linux-2.5.8-pre3/arch/ppc64/kernel/chrp_setup.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/chrp_setup.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/chrp_setup.c	Tue Apr  9 18:35:18 2002
@@ -342,12 +342,15 @@
 
 extern void setup_default_decr(void);
 
+extern unsigned long ppc_proc_freq;
+extern unsigned long ppc_tb_freq;
+
 void __init pSeries_calibrate_decr(void)
 {
 	struct device_node *cpu;
 	struct div_result divres;
 	int *fp;
-	unsigned long freq;
+	unsigned long freq, processor_freq;
 
 	/*
 	 * The cpu node should have a timebase-frequency property
@@ -360,8 +363,19 @@
 		if (fp != 0)
 			freq = *fp;
 	}
+	ppc_tb_freq = freq;
+	processor_freq = freq;
+	if (cpu != 0) {
+		fp = (int *) get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0)
+			processor_freq = *fp;
+	}
+	ppc_proc_freq = processor_freq;
+	
         printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", 
 	       freq/1000000, freq%1000000 );
+	printk("time_init: processor frequency   = %lu.%.6lu MHz\n",
+		processor_freq/1000000, processor_freq%1000000 );
 
 	tb_ticks_per_jiffy = freq / HZ;
 	tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/entry.S linux-2.5.8-pre3/arch/ppc64/kernel/entry.S
--- linux-2.5.8-pre2/arch/ppc64/kernel/entry.S	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/entry.S	Tue Apr  9 18:35:18 2002
@@ -42,10 +42,19 @@
 	.long	-1
 #endif
 
+	.section	".toc","aw"
+.SYS_CALL_TABLE:
+	.tc .sys_call_table[TC],.sys_call_table
+
+.SYS_CALL_TABLE32:
+	.tc .sys_call_table32[TC],.sys_call_table32
+
+	.section	".text"
+	.align 3
+
 /*
  * Handle a system call.
  */
-	.text
 _GLOBAL(DoSyscall)
 	std	r0,THREAD+LAST_SYSCALL(r13)
 	ld	r11,_CCR(r1)	/* Clear SO bit in CR */
@@ -94,7 +103,7 @@
 #ifdef CONFIG_BINFMT_ELF32
 	andi.	r11,r10,_TIF_32BIT
 	beq-	15f
-	LOADADDR(r10,.sys_call_table32)
+	ld	r10,.SYS_CALL_TABLE32@toc(2)
 /*
  * Now mung the first 4 parameters into shape, by making certain that
  * the high bits (most significant 32 bits in 64 bit reg) are 0
@@ -111,7 +120,7 @@
 	b	17f
 15:
 #endif
-	LOADADDR(r10,.sys_call_table)
+	ld	r10,.SYS_CALL_TABLE@toc(2)
 17:	slwi	r0,r0,3
 	ldx	r10,r10,r0	/* Fetch system call handler [ptr] */
 	mtlr	r10
@@ -167,7 +176,7 @@
 	ld	r10,TI_FLAGS(r10)
 	andi.	r11,r10,_TIF_32BIT
 	beq-	55f
-	LOADADDR(r10,.sys_call_table32)
+	ld	r10,.SYS_CALL_TABLE32@toc(2)
 /*
  * Now mung the first 4 parameters into shape, by making certain that
  * the high bits (most significant 32 bits in 64 bit reg) are 0
@@ -184,7 +193,7 @@
 	b	57f
 55:
 #endif
-	LOADADDR(r10,.sys_call_table)
+	ld	r10,.SYS_CALL_TABLE@toc(2)
 57:
 	slwi	r0,r0,3
 	ldx	r10,r10,r0	/* Fetch system call handler [ptr] */
@@ -255,38 +264,33 @@
  * Note: there are two ways to get to the "going out" portion
  * of this code; either by coming in via the entry (_switch)
  * or via "fork" which must set up an environment equivalent
- * to the "_switch" path.  If you change this (or in particular, the
- * SAVE_REGS macro), you'll have to change the fork code also.
+ * to the "_switch" path.  If you change this you'll have to change
+ * the fork code also.
  *
  * The code which creates the new task context is in 'copy_thread'
- * in arch/ppc/kernel/process.c
+ * in arch/ppc64/kernel/process.c
  */
 _GLOBAL(_switch)
-	stdu	r1,-INT_FRAME_SIZE(r1)
-	ld	r6,0(r1)
-	std	r6,GPR1(r1)
+	mflr	r0
+	std	r0,16(r1)
+	stdu	r1,-SWITCH_FRAME_SIZE(r1)
 	/* r3-r13 are caller saved -- Cort */
-	SAVE_GPR(2, r1)
 	SAVE_8GPRS(14, r1)
 	SAVE_10GPRS(22, r1)
 	mflr	r20		/* Return to switch caller */
 	mfmsr	r22
+	andi.	r21, r22, MSR_FP
+	beq+	1f
 	li	r6,MSR_FP	/* Disable floating-point */
 	andc	r22,r22,r6
 	mtmsrd	r22
 	isync
-	std	r20,_NIP(r1)
-	std	r22,_MSR(r1)
-	std	r20,_LINK(r1)
-	mfcr	r20
-	std	r20,_CCR(r1)
-	li	r6,0x0ff0
-	std	r6,TRAP(r1)
+1:	std	r20,_NIP(r1)
+	mfcr	r23
+	std	r23,_CCR(r1)
 	std	r1,KSP(r3)	/* Set old stack pointer */
 
 	mfspr	r5,SPRG3	/* Get Paca */
-	/* XXX remove - Anton */
-	addi	r3,r3,-THREAD	/* old 'current' for return value */
 	addi	r13,r4,-THREAD	/* Convert THREAD to 'current' */
 	std	r13,PACACURRENT(r5)	/* Set new 'current' */
 
@@ -298,6 +302,7 @@
 	insrdi	r9,r7,1,63	/* Insert run light into CTRL */
 	mtspr	CTRLT,r9
 #endif
+
 	ld	r1,KSP(r4)	/* Load new stack pointer */
 	ld	r6,_CCR(r1)
 	mtcrf	0xFF,r6
@@ -306,8 +311,8 @@
 	REST_10GPRS(22, r1)
 
 	ld	r7,_NIP(r1)	/* Return to _switch caller in new task */
-	ld	r1,GPR1(r1)
 	mtlr	r7
+	addi	r1,r1,SWITCH_FRAME_SIZE
 	blr
 
 _GLOBAL(ret_from_fork)
@@ -377,6 +382,7 @@
 	mtlr	r0
 	ld	r3,_XER(r1)
 	mtspr	XER,r3
+
 	REST_8GPRS(5, r1)
 	REST_10GPRS(14, r1)
 	REST_8GPRS(24, r1)
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/head.S linux-2.5.8-pre3/arch/ppc64/kernel/head.S
--- linux-2.5.8-pre2/arch/ppc64/kernel/head.S	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/head.S	Tue Apr  9 18:35:18 2002
@@ -993,6 +993,7 @@
 	li      r21,0
 	rldimi  r21,r20,12,0
 	ori     r20,r21,1024
+	ori	r20,r20,128    /* set class bit for kernel region */
 #ifndef CONFIG_PPC_ISERIES
 	ori	r20,r20,256    /* map kernel region with large ptes */
 #endif
@@ -1824,10 +1825,10 @@
 hardware_int_paca0:
 	.space	8*4096
 
-/* 1 page segment table per cpu (max 48) */
+/* 1 page segment table per cpu (max 48, cpu0 allocated at 0x5000) */
 	.globl	stab_array
 stab_array:
-	.space	4096 * 48
+	.space	4096 * 47
 	
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/htab.c linux-2.5.8-pre3/arch/ppc64/kernel/htab.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/htab.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/htab.c	Tue Apr  9 18:35:18 2002
@@ -1,10 +1,11 @@
 /*
- * 
- *
  * PowerPC64 port by Mike Corrigan and Dave Engebretsen
  *   {mikejc|engebret}@us.ibm.com
  *
  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
+ *
+ * SMP scalability work:
+ *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
  * 
  *    Module name: htab.c
  *
@@ -18,17 +19,7 @@
  */
 
 #include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-#include <asm/page.h>
-#include <asm/types.h>
-#include <asm/init.h>
-#include <asm/system.h>
-#include <asm/iSeries/LparData.h>
 #include <linux/spinlock.h>
-#include <asm/ppcdebug.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -36,56 +27,43 @@
 #include <linux/sysctl.h>
 #include <linux/ctype.h>
 #include <linux/cache.h>
+
+#include <asm/ppcdebug.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/init.h>
+#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/Naca.h>
 #include <asm/system.h>
 #include <asm/pmc.h>
 #include <asm/machdep.h>
 #include <asm/lmb.h>
+#include <asm/abs_addr.h>
+#include <asm/tlbflush.h>
 #ifdef CONFIG_PPC_EEH
 #include <asm/eeh.h>
 #endif
 
-/* For iSeries */
-#include <asm/iSeries/HvCallHpt.h>
-
-/* Note:  pte   --> Linux PTE
+/*
+ * Note:  pte   --> Linux PTE
  *        HPTE  --> PowerPC Hashed Page Table Entry
  */
 
 HTAB htab_data = {NULL, 0, 0, 0, 0};
 
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-		   void *buffer, size_t *lenp);
-
-void htab_initialize(void);
-void make_pte_LPAR(HPTE *htab,
-	      unsigned long va, unsigned long pa, int mode,
-	      unsigned long hash_mask, int large);
-
-extern unsigned long reloc_offset(void);
-extern unsigned long get_kernel_vsid( unsigned long ea );
-extern void cacheable_memzero( void *, unsigned int );
-
 extern unsigned long _SDR1;
 extern unsigned long klimit;
-extern struct Naca *naca;
-
-extern unsigned long _ASR;
-extern inline void make_ste(unsigned long stab,
-			    unsigned long esid, unsigned long vsid);
-
-extern char _stext[], _etext[], __start_naca[], __end_stab[];
-
-static spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
+extern unsigned long reloc_offset(void);
 #define PTRRELOC(x)	((typeof(x))((unsigned long)(x) - offset))
 #define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
 #define RELOC(x)	(*PTRRELOC(&(x)))
 
-extern unsigned long htab_size( unsigned long );
-unsigned long hpte_getword0_iSeries( unsigned long slot );
-
 #define KB (1024)
 #define MB (1024*KB)
 static inline void
@@ -94,7 +72,7 @@
 {
 	unsigned long addr, offset = reloc_offset();
 	HTAB *_htab_data = PTRRELOC(&htab_data);
-	HPTE  *htab  = (HPTE *)__v2a(_htab_data->htab);
+	HPTE *htab = (HPTE *)__v2a(_htab_data->htab);
 	unsigned int step;
 
 	if (large)
@@ -105,8 +83,12 @@
 	for (addr = start; addr < end; addr += step) {
 		unsigned long vsid = get_kernel_vsid(addr);
 		unsigned long va = (vsid << 28) | (addr & 0xfffffff);
-		make_pte(htab, va, (unsigned long)__v2a(addr), mode, mask,
-				large);
+		if (_machine == _MACH_pSeriesLP)
+			pSeries_lpar_make_pte(htab, va,
+				(unsigned long)__v2a(addr), mode, mask, large);
+		else
+			pSeries_make_pte(htab, va,
+				(unsigned long)__v2a(addr), mode, mask, large);
 	}
 }
 
@@ -115,7 +97,7 @@
 {
 	unsigned long table, htab_size_bytes;
 	unsigned long pteg_count;
-	unsigned long mode_ro, mode_rw, mask;
+	unsigned long mode_rw, mask;
 	unsigned long offset = reloc_offset();
 	struct Naca *_naca = RELOC(naca);
 	HTAB *_htab_data = PTRRELOC(&htab_data);
@@ -136,7 +118,7 @@
 	_htab_data->htab_num_ptegs = pteg_count;
 	_htab_data->htab_hash_mask = pteg_count - 1;
 
-	if(_machine == _MACH_pSeries) {
+	if (_machine == _MACH_pSeries) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
@@ -149,697 +131,235 @@
 		RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;
 
 		/* Initialize the HPT with no entries */
-		cacheable_memzero((void *)table, htab_size_bytes);
+		memset((void *)table, 0, htab_size_bytes);
 	} else {
 		_htab_data->htab = NULL;
 		RELOC(_SDR1) = 0; 
 	}
 
-	mode_ro = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RXRX;
 	mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
 	mask = pteg_count-1;
 
-	/* Create PTE's for the kernel text and data sections plus
-	 * the HPT and HPTX arrays.  Make the assumption that
-	 * (addr & KERNELBASE) == 0 (ie they are disjoint).
-	 * We also assume that the va is <= 64 bits.
-	 */
-#if 0
-	create_pte_mapping((unsigned long)_stext,       (unsigned long)__start_naca,                 mode_ro, mask);
-	create_pte_mapping((unsigned long)__start_naca, (unsigned long)__end_stab,                   mode_rw, mask);
-	create_pte_mapping((unsigned long)__end_stab,   (unsigned long)_etext,                       mode_ro, mask);
-	create_pte_mapping((unsigned long)_etext,       RELOC(klimit),                               mode_rw, mask);
-	create_pte_mapping((unsigned long)__a2v(table), (unsigned long)__a2v(table+htab_size_bytes), mode_rw, mask);
-#else
-#ifndef CONFIG_PPC_ISERIES
+	/* XXX we currently map kernel text rw, should fix this */
 	if (__is_processor(PV_POWER4) && _naca->physicalMemorySize > 256*MB) {
 		create_pte_mapping((unsigned long)KERNELBASE, 
 				   KERNELBASE + 256*MB, mode_rw, mask, 0);
 		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
 				   KERNELBASE + (_naca->physicalMemorySize), 
 				   mode_rw, mask, 1);
-		return;
+	} else {
+		create_pte_mapping((unsigned long)KERNELBASE, 
+				   KERNELBASE+(_naca->physicalMemorySize), 
+				   mode_rw, mask, 0);
 	}
-#endif
-	create_pte_mapping((unsigned long)KERNELBASE, 
-			   KERNELBASE+(_naca->physicalMemorySize), 
-			   mode_rw, mask, 0);
-#endif
 }
 #undef KB
 #undef MB
 
 /*
- * Create a pte.  Used during initialization only.
- * We assume the PTE will fit in the primary PTEG.
- */
-void make_pte(HPTE *htab,
-	      unsigned long va, unsigned long pa, int mode,
-	      unsigned long hash_mask, int large)
-{
-	HPTE  *hptep;
-	unsigned long hash, i;
-	volatile unsigned long x = 1;
-	unsigned long vpn;
-
-#ifdef CONFIG_PPC_PSERIES
-	if(_machine == _MACH_pSeriesLP) {
-		make_pte_LPAR(htab, va, pa, mode, hash_mask, large); 
-		return;
-	}
-#endif
-
-	if (large)
-		vpn = va >> 24;
-	else
-		vpn = va >> 12;
-
-	hash = hpt_hash(vpn, large);
-
-	hptep  = htab +  ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	for (i = 0; i < 8; ++i, ++hptep) {
-		if ( hptep->dw0.dw0.v == 0 ) {		/* !valid */
-			hptep->dw1.dword1 = pa | mode;
-			hptep->dw0.dword0 = 0;
-			hptep->dw0.dw0.avpn = va >> 23;
-			hptep->dw0.dw0.bolted = 1;	/* bolted */
-			hptep->dw0.dw0.v = 1;		/* make valid */
-			return;
-		}
-	}
-
-	/* We should _never_ get here and too early to call xmon. */
-	for(;x;x|=1);
-}
-
-/* Functions to invalidate a HPTE */
-static void hpte_invalidate_iSeries( unsigned long slot )
-{
-	HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 );
-}
-
-static void hpte_invalidate_pSeries( unsigned long slot )
-{
-	/* Local copy of the first doubleword of the HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-
-	/* Locate the HPTE */
-	HPTE  * hptep  = htab_data.htab  + slot;
-
-	/* Get the first doubleword of the HPTE */
-	hpte_dw0.d = hptep->dw0.dword0;
-
-	/* Invalidate the hpte */
-	hptep->dw0.dword0 = 0;
-
-	/* Invalidate the tlb   */
-	{
-		unsigned long vsid, group, pi, pi_high;
-
-		vsid = hpte_dw0.h.avpn >> 5;
-		group = slot >> 3;
-		if(hpte_dw0.h.h) {
-			group = ~group;
-		} 
-		pi = (vsid ^ group) & 0x7ff;
-		pi_high = (hpte_dw0.h.avpn & 0x1f) << 11;
-		pi |= pi_high;
-		_tlbie(pi << 12);
-	}
-}
-
-
-/* Select an available HPT slot for a new HPTE
- *   return slot index (if in primary group)
- *   return -slot index (if in secondary group) 
- */
-static long hpte_selectslot_iSeries( unsigned long vpn )
-{
-	HPTE hpte;
-	long ret_slot, orig_slot;
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned long slot;
-	unsigned i, k;
-	union {
-		unsigned long	d;
-		Hpte_dword0	h;
-	} hpte_dw0;
-
-	ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn );
-	if ( hpte.dw0.dw0.v ) {		/* If valid ...what do we do now? */
-		udbg_printf( "hpte_selectslot_iSeries: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot );
-		udbg_printf( "hpte_selectslot_iSeries: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 );
-
-		return (0x8000000000000000); 
-		/*			panic("select_hpte_slot found entry already valid\n"); */
-	}
-	if ( ret_slot == -1 ) {		/* -1 indicates no available slots */
-
-		/* No available entry found in secondary group */
-
-		PMC_SW_SYSTEM(htab_capacity_castouts);
-
-		primary_hash = hpt_hash(vpn, 0);
-		hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-		k = htab_data.next_round_robin++ & 0x7;
-
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			if ( k == HPTES_PER_GROUP )
-				k = 0;
-			slot = hpteg_slot + k;
-			hpte_dw0.d = hpte_getword0_iSeries( slot );
-			if ( !hpte_dw0.h.bolted ) {
-				hpte_invalidate_iSeries( slot );
-				ret_slot = slot;
-			}
-			++k;
-		}
-	} else {
-		if ( ret_slot < 0 ) {
-			PMC_SW_SYSTEM(htab_primary_overflows);
-			ret_slot &= 0x7fffffffffffffff;
-			ret_slot = -ret_slot;
-		}
-	}
-	if ( ret_slot == -1 ) {
-		/* No non-bolted entry found in primary group - time to panic */
-        	udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-        	panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
-	}
-	PPCDBG(PPCDBG_MM, "hpte_selectslot_iSeries: vpn=0x%016lx, orig_slot=0x%016lx, ret_slot=0x%016lx \n",
-	       vpn, orig_slot, ret_slot );	
-	return ret_slot;
-}
-
-static long hpte_selectslot_pSeries(unsigned long vpn)
-{
-	HPTE * hptep;
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned i, k;
-
-	/* Search the primary group for an available slot */
-
-	primary_hash = hpt_hash(vpn, 0);
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
-	
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if ( hptep->dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-		hptep++;
-	}
-
-	/* No available entry found in primary group */
-
-	PMC_SW_SYSTEM(htab_primary_overflows);
-
-	/* Search the secondary group */
-
-	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if ( hptep->dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return -(hpteg_slot + i);
-		}
-		hptep++;
-	}
-
-	/* No available entry found in secondary group */
-
-	PMC_SW_SYSTEM(htab_capacity_castouts);
-
-	/* Select an entry in the primary group to replace */
-
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-	hptep = htab_data.htab + hpteg_slot;
-	k = htab_data.next_round_robin++ & 0x7;
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if (k == HPTES_PER_GROUP)
-			k = 0;
-
-		if (!hptep[k].dw0.dw0.bolted) {
-			hpteg_slot += k;
-			/* Invalidate the current entry */
-			ppc_md.hpte_invalidate(hpteg_slot); 
-			return hpteg_slot;
-		}
-		++k;
-	}
-
-	/* No non-bolted entry found in primary group - time to panic */
-        udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-	/*      xmon(0); */
-        panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
-
-	/* keep the compiler happy */
-	return 0;
-}
-
-unsigned long hpte_getword0_iSeries( unsigned long slot )
-{
-	unsigned long dword0;
-
-	HPTE hpte;
-	HvCallHpt_get( &hpte, slot );
-	dword0 = hpte.dw0.dword0;
-
-	return dword0;
-}
-
-unsigned long hpte_getword0_pSeries( unsigned long slot )
-{
-	unsigned long dword0;
-	HPTE * hptep = htab_data.htab + slot;
-
-	dword0 = hptep->dw0.dword0;
-	return dword0;
-}
-
-static long hpte_find_iSeries(unsigned long vpn)
-{
-	HPTE hpte;
-	long slot;
-
-	slot = HvCallHpt_findValid( &hpte, vpn );
-	if ( hpte.dw0.dw0.v ) {
-		if ( slot < 0 ) {
-			slot &= 0x7fffffffffffffff;
-			slot = -slot;
-		}
-	} else
-		slot = -1;
-	return slot;
-}
-
-static long hpte_find_pSeries(unsigned long vpn)
-{
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	long slot;
-	unsigned long hash;
-	unsigned long i,j;
-
-	hash = hpt_hash(vpn, 0);
-	for ( j=0; j<2; ++j ) {
-		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			hpte_dw0.d = hpte_getword0_pSeries( slot );
-			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
-			     ( hpte_dw0.h.v ) &&
-			     ( hpte_dw0.h.h == j ) ) {
-				/* HPTE matches */
-				if ( j )
-					slot = -slot;
-				return slot;
-			}
-			++slot;
-		}
-		hash = ~hash;
-	}
-	return -1;
-} 
-
-/* This function is called by iSeries setup when initializing the hpt */
-void build_valid_hpte( unsigned long vsid, unsigned long ea, unsigned long pa,
-		       pte_t * ptep, unsigned hpteflags, unsigned bolted )
-{
-	unsigned long vpn, flags;
-	long hpte_slot;
-	unsigned hash;
-	pte_t pte;
-
-	vpn = ((vsid << 28) | ( ea & 0xffff000 )) >> 12;
-
-	spin_lock_irqsave( &hash_table_lock, flags );
-
-	hpte_slot = ppc_md.hpte_selectslot( vpn );
-	hash = 0;
-	if ( hpte_slot < 0 ) {
-		if ( hpte_slot == 0x8000000000000000 ) {
-			udbg_printf("hash_page: ptep    = 0x%016lx\n", 
-				    (unsigned long)ptep );
-			udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
-			udbg_printf("hash_page: vpn     = 0x%016lx\n", vpn );
-               
-			panic("hash_page: hpte already exists\n");
-		}
-		hash = 1;
-		hpte_slot = -hpte_slot;
-	}
-	ppc_md.hpte_create_valid( hpte_slot, vpn, pa >> 12, hash, ptep,
-				  hpteflags, bolted );
-
-	if ( ptep ) {
-		/* Get existing pte flags */
-		pte = *ptep;
-		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
-
-		/* Add in the has hpte flag */
-		pte_val(pte) |= _PAGE_HASHPTE;
-
-		/* Add in the _PAGE_SECONDARY flag */
-		pte_val(pte) |= hash << 15;
-
-		/* Add in the hpte slot */
-		pte_val(pte) |= (hpte_slot << 12) & _PAGE_GROUP_IX;
-               
-		/* Save the new pte.  */
-		*ptep = pte;
-               
-	}
-	spin_unlock_irqrestore( &hash_table_lock, flags );
-}
-
-
-/* Create an HPTE and validate it
- *   It is assumed that the HPT slot currently is invalid.
- *   The HPTE is set with the vpn, rpn (converted to absolute)
- *   and flags
- */
-static void hpte_create_valid_iSeries(unsigned long slot, unsigned long vpn,
-				      unsigned long prpn, unsigned hash, 
-				      void * ptep, unsigned hpteflags, 
-				      unsigned bolted )
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
-
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
-
-	/* Now fill in the actual HPTE */
-	HvCallHpt_addValidate( slot, hash, (HPTE *)&lhpte );
-}
-
-static void hpte_create_valid_pSeries(unsigned long slot, unsigned long vpn,
-				      unsigned long prpn, unsigned hash, 
-				      void * ptep, unsigned hpteflags, 
-				      unsigned bolted)
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
-
-	HPTE *hptep;
-
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
-
-	/* Now fill in the actual HPTE */
-	hptep  = htab_data.htab  + slot;
-
-	/* Set the second dword first so that the valid bit
-	 * is the last thing set
-	 */
-	
-	hptep->dw1.dword1 = lhpte.dw1.d;
-
-	/* Guarantee the second dword is visible before
-	 * the valid bit
-	 */
-	
-	__asm__ __volatile__ ("eieio" : : : "memory");
-
-	/* Now set the first dword including the valid bit */
-	hptep->dw0.dword0 = lhpte.dw0.d;
-
-	__asm__ __volatile__ ("ptesync" : : : "memory");
-}
-
-/* find_linux_pte returns the address of a linux pte for a given 
+ * find_linux_pte returns the address of a linux pte for a given 
  * effective address and directory.  If not found, it returns zero.
  */
-
-pte_t  * find_linux_pte( pgd_t * pgdir, unsigned long ea )
+pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
 {
 	pgd_t *pg;
 	pmd_t *pm;
 	pte_t *pt = NULL;
 	pte_t pte;
-	pg = pgdir + pgd_index( ea );
-	if ( ! pgd_none( *pg ) ) {
 
-		pm = pmd_offset( pg, ea );
-		if ( ! pmd_none( *pm ) ) { 
-			pt = pte_offset( pm, ea );
+	pg = pgdir + pgd_index(ea);
+	if (!pgd_none(*pg)) {
+
+		pm = pmd_offset(pg, ea);
+		if (!pmd_none(*pm)) { 
+			pt = pte_offset_kernel(pm, ea);
 			pte = *pt;
-			if ( ! pte_present( pte ) )
+			if (!pte_present(pte))
 				pt = NULL;
 		}
 	}
 
 	return pt;
-
-}
-
-static inline unsigned long computeHptePP( unsigned long pte )
-{
-	return (     pte & _PAGE_USER )           |
-		( ( ( pte & _PAGE_USER )    >> 1 ) &
-		  ( ( ~( ( pte >> 2 ) &		/* _PAGE_RW */
-		         ( pte >> 7 ) ) ) &     /* _PAGE_DIRTY */
-			 1 ) );
 }
 
-static void hpte_updatepp_iSeries(long slot, unsigned long newpp, unsigned long va)
+static inline unsigned long computeHptePP(unsigned long pte)
 {
-	HvCallHpt_setPp( slot, newpp );
-}
-
-static void hpte_updatepp_pSeries(long slot, unsigned long newpp, unsigned long va)
-{
-	/* Local copy of first doubleword of HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	
-	/* Local copy of second doubleword of HPTE */
-	union {
-		unsigned long     d;
-		Hpte_dword1       h;
-		Hpte_dword1_flags f;
-	} hpte_dw1;	
-
-	HPTE *  hptep  = htab_data.htab  + slot;
-
-	/* Turn off valid bit in HPTE */
-	hpte_dw0.d = hptep->dw0.dword0;
-	hpte_dw0.h.v = 0;
-	hptep->dw0.dword0 = hpte_dw0.d;
-
-	/* Ensure it is out of the tlb too */
-	_tlbie( va );
-
-	/* Insert the new pp bits into the HPTE */
-	hpte_dw1.d = hptep->dw1.dword1;
-	hpte_dw1.h.pp = newpp;
-	hptep->dw1.dword1 = hpte_dw1.d;
-
-	/* Ensure it is visible before validating */
-	__asm__ __volatile__ ("eieio" : : : "memory");
-
-	/* Turn the valid bit back on in HPTE */
-	hpte_dw0.h.v = 1;
-	hptep->dw0.dword0 = hpte_dw0.d;
-
-	__asm__ __volatile__ ("ptesync" : : : "memory");
+	return (pte & _PAGE_USER) |
+		(((pte & _PAGE_USER) >> 1) &
+		 ((~((pte >> 2) &	/* _PAGE_RW */
+		     (pte >> 7))) &	/* _PAGE_DIRTY */
+		  1));
 }
 
 /*
- * Update the page protection bits.  Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT.  Assumes pages being operated on will not be stolen. 
+ * Handle a fault by adding an HPTE. If the address can't be determined
+ * to be valid via Linux page tables, return 1. If handled return 0
  */
-void hpte_updateboltedpp_iSeries(unsigned long newpp, unsigned long ea )
+int __hash_page(unsigned long ea, unsigned long access, unsigned long vsid,
+		pte_t *ptep)
 {
-	unsigned long vsid,va,vpn;
+	unsigned long va, vpn;
+	unsigned long newpp, prpn;
+	unsigned long hpteflags;
 	long slot;
+	pte_t old_pte, new_pte;
 
-	vsid = get_kernel_vsid( ea );
-	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
+	/* Search the Linux page table for a match with va */
+	va = (vsid << 28) | (ea & 0x0fffffff);
 	vpn = va >> PAGE_SHIFT;
 
-	slot = ppc_md.hpte_find( vpn );
-	HvCallHpt_setPp( slot, newpp );
-}
-
-
-static __inline__ void set_pp_bit(unsigned long  pp, HPTE *addr)
-{
-	unsigned long old;
-	unsigned long *p = (unsigned long *)(&(addr->dw1));
-
-	__asm__ __volatile__(
-        "1:	ldarx	%0,0,%3\n\
-                rldimi  %0,%2,0,62\n\
-                stdcx.	%0,0,%3\n\
-            	bne	1b"
-        : "=&r" (old), "=m" (*p)
-        : "r" (pp), "r" (p), "m" (*p)
-        : "cc");
-}
+	/*
+	 * If no pte found or not present, send the problem up to
+	 * do_page_fault
+	 */
+	if (!ptep || !pte_present(*ptep))
+		return 1;
 
-/*
- * Update the page protection bits.  Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT.  Assumes pages being operated on will not be stolen. 
- */
-void hpte_updateboltedpp_pSeries(unsigned long newpp, unsigned long ea)
-{
-	unsigned long vsid,va,vpn,flags;
-	long slot;
-	HPTE *hptep;
+	/* 
+	 * Check the user's access rights to the page.  If access should be
+	 * prevented then send the problem up to do_page_fault.
+	 */
+	access |= _PAGE_PRESENT;
+	if (access & ~(pte_val(*ptep)))
+		return 1;
 
-	vsid = get_kernel_vsid( ea );
-	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
+	/*
+	 * At this point, we have a pte (old_pte) which can be used to build
+	 * or update an HPTE. There are 2 cases:
+	 *
+	 * 1. There is a valid (present) pte with no associated HPTE (this is 
+	 *	the most common case)
+	 * 2. There is a valid (present) pte with an associated HPTE. The
+	 *	current values of the pp bits in the HPTE prevent access
+	 *	because we are doing software DIRTY bit management and the
+	 *	page is currently not DIRTY. 
+	 */
 
-	slot = ppc_md.hpte_find( vpn );
-	hptep = htab_data.htab  + slot;
+	old_pte = *ptep;
+	new_pte = old_pte;
+	/* If the attempted access was a store */
+	if (access & _PAGE_RW)
+		pte_val(new_pte) |= _PAGE_ACCESSED | _PAGE_DIRTY;
+	else
+		pte_val(new_pte) |= _PAGE_ACCESSED;
 
-	set_pp_bit(newpp , hptep);
+	newpp = computeHptePP(pte_val(new_pte));
 
-	/* Ensure it is out of the tlb too */
-	spin_lock_irqsave( &hash_table_lock, flags );
-	_tlbie( va );
-	spin_unlock_irqrestore( &hash_table_lock, flags );
-}
+	/* Check if pte already has an hpte (case 2) */
+	if (pte_val(old_pte) & _PAGE_HASHPTE) {
+		/* There MIGHT be an HPTE for this pte */
+		unsigned long hash, slot, secondary;
+
+		/* XXX fix large pte flag */
+		hash = hpt_hash(vpn, 0);
+		secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
+		if (secondary)
+			hash = ~hash;
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
 
+		/* XXX fix large pte flag */
+		if (ppc_md.hpte_updatepp(slot, newpp, va, 0) == -1)
+			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
+		else
+			if (!pte_same(old_pte, new_pte))
+				*ptep = new_pte;
+	}
 
+	if (!(pte_val(old_pte) & _PAGE_HASHPTE)) {
+		/* XXX fix large pte flag */
+		unsigned long hash = hpt_hash(vpn, 0);
+		unsigned long hpte_group;
+		prpn = pte_val(old_pte) >> PTE_SHIFT;
+
+repeat:
+		hpte_group = ((hash & htab_data.htab_hash_mask) *
+			      HPTES_PER_GROUP) & ~0x7UL;
+
+		/* Update the linux pte with the HPTE slot */
+		pte_val(new_pte) &= ~_PAGE_HPTEFLAGS;
+		pte_val(new_pte) |= _PAGE_HASHPTE;
+
+		/* copy appropriate flags from linux pte */
+		hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
+
+		/* XXX fix large pte flag */
+		slot = ppc_md.insert_hpte(hpte_group, vpn, prpn, 0,
+					  hpteflags, 0, 0);
+
+		/* Primary is full, try the secondary */
+		if (slot == -1) {
+			pte_val(new_pte) |= 1 << 15;
+			hpte_group = ((~hash & htab_data.htab_hash_mask) *
+				      HPTES_PER_GROUP) & ~0x7UL; 
+			/* XXX fix large pte flag */
+			slot = ppc_md.insert_hpte(hpte_group, vpn, prpn,
+						  1, hpteflags, 0, 0);
+			if (slot == -1) {
+				if (mftb() & 0x1)
+					hpte_group = ((hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+
+				ppc_md.remove_hpte(hpte_group);
+				goto repeat;
+                        }
+		}
+
+		pte_val(new_pte) |= (slot<<12) & _PAGE_GROUP_IX;
+
+		/* 
+		 * No need to use ldarx/stdcx here because all who
+		 * might be updating the pte will hold the
+		 * page_table_lock or the hash_table_lock
+		 * (we hold both)
+		 */
+		*ptep = new_pte;
+	}
 
-/* This is called very early. */
-void hpte_init_iSeries(void)
-{
-	ppc_md.hpte_invalidate   = hpte_invalidate_iSeries;
-	ppc_md.hpte_updatepp     = hpte_updatepp_iSeries;
-	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_iSeries;
-	ppc_md.hpte_getword0     = hpte_getword0_iSeries;
-	ppc_md.hpte_selectslot   = hpte_selectslot_iSeries;
-	ppc_md.hpte_create_valid = hpte_create_valid_iSeries;
-	ppc_md.hpte_find	 = hpte_find_iSeries;
-}
-void hpte_init_pSeries(void)
-{
-	ppc_md.hpte_invalidate   = hpte_invalidate_pSeries;
-	ppc_md.hpte_updatepp     = hpte_updatepp_pSeries;
-	ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_pSeries;
-	ppc_md.hpte_getword0     = hpte_getword0_pSeries;
-	ppc_md.hpte_selectslot   = hpte_selectslot_pSeries;
-	ppc_md.hpte_create_valid = hpte_create_valid_pSeries;
-	ppc_md.hpte_find	 = hpte_find_pSeries;
+	return 0;
 }
 
-/* Handle a fault by adding an HPTE 
- * If the address can't be determined to be valid
- * via Linux page tables, return 1.  If handled
- * return 0
- */
-int hash_page( unsigned long ea, unsigned long access )
+int hash_page(unsigned long ea, unsigned long access)
 {
-	int rc = 1;
-	void * pgdir = NULL;
-	unsigned long va, vsid, vpn;
-	unsigned long newpp, hash_ind, prpn;
-	unsigned long hpteflags, regionid;
-	long slot;
-	struct mm_struct * mm;
-	pte_t old_pte, new_pte, *ptep;
+	void *pgdir;
+	unsigned long vsid;
+	struct mm_struct *mm;
+	pte_t *ptep;
+	int ret;
 
 	/* Check for invalid addresses. */
-	if (!IS_VALID_EA(ea)) {
+	if (!IS_VALID_EA(ea))
 		return 1;
-	}
 
-	regionid =  REGION_ID(ea);
-	switch ( regionid ) {
+ 	switch (REGION_ID(ea)) {
 	case USER_REGION_ID:
 		mm = current->mm;
-		if ( mm == NULL ) {
-			PPCDBG(PPCDBG_MM, "hash_page returning; mm = 0\n"); 
+		if (mm == NULL)
 			return 1;
-		}
-		vsid = get_vsid(mm->context, ea );
+
+		vsid = get_vsid(mm->context, ea);
 		break;
 	case IO_REGION_ID:
 		mm = &ioremap_mm;
-		vsid = get_kernel_vsid( ea );
+		vsid = get_kernel_vsid(ea);
 		break;
 	case VMALLOC_REGION_ID:
 		mm = &init_mm;
-		vsid = get_kernel_vsid( ea );
+		vsid = get_kernel_vsid(ea);
 		break;
 #ifdef CONFIG_PPC_EEH
 	case IO_UNMAPPED_REGION_ID:
 		udbg_printf("EEH Error ea = 0x%lx\n", ea);
- 		PPCDBG_ENTER_DEBUGGER();
+		PPCDBG_ENTER_DEBUGGER();
 		panic("EEH Error ea = 0x%lx\n", ea);
 		break;
 #endif
 	case KERNEL_REGION_ID:
-		/* As htab_initialize is now, we shouldn't ever get here since
+		/*
+		 * As htab_initialize is now, we shouldn't ever get here since
 		 * we're bolting the entire 0xC0... region.
 		 */
 		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
- 		PPCDBG_ENTER_DEBUGGER();
+		PPCDBG_ENTER_DEBUGGER();
 		panic("Little faulted on kernel address 0x%lx\n", ea);
 		break;
 	default:
@@ -848,383 +368,63 @@
 		break;
 	}
 
-	/* Search the Linux page table for a match with va */
-        va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
 	pgdir = mm->pgd;
-	PPCDBG(PPCDBG_MM, "hash_page ea = 0x%16.16lx, va = 0x%16.16lx\n          current = 0x%16.16lx, access = %lx\n", ea, va, current, access); 
-                if ( pgdir == NULL ) {
-                return 1;
-	}
-	
-	/* Lock the Linux page table to prevent mmap and kswapd
-	 * from modifying entries while we search and update
-	 */
-	
-	spin_lock( &mm->page_table_lock );
-	
-	ptep = find_linux_pte( pgdir, ea );
-	/* If no pte found, send the problem up to do_page_fault */
-	if ( ! ptep ) {
-	  spin_unlock( &mm->page_table_lock );
-	  return 1;
-	}
-	
-	/* Acquire the hash table lock to guarantee that the linux
-	 * pte we fetch will not change
-	 */
-	spin_lock( &hash_table_lock );
-	
-	old_pte = *ptep;
-	
-	/* If the pte is not "present" (valid), send the problem
-	 * up to do_page_fault.
-	 */
-	if ( ! pte_present( old_pte ) ) {
-	  spin_unlock( &hash_table_lock );
-	  spin_unlock( &mm->page_table_lock );
-	  return 1;
-	}
-	
-	/* At this point we have found a pte (which was present).
-	 * The spinlocks prevent this status from changing
-	 * The hash_table_lock prevents the _PAGE_HASHPTE status
-	 * from changing (RPN, DIRTY and ACCESSED too)
-	 * The page_table_lock prevents the pte from being 
-	 * invalidated or modified
-	 */
-
-/* At this point, we have a pte (old_pte) which can be used to build or update
- * an HPTE.   There are 5 cases:
- *
- * 1. There is a valid (present) pte with no associated HPTE (this is 
- *	the most common case)
- * 2. There is a valid (present) pte with an associated HPTE.  The
- *	current values of the pp bits in the HPTE prevent access because the
- *	user doesn't have appropriate access rights.
- * 3. There is a valid (present) pte with an associated HPTE.  The
- *	current values of the pp bits in the HPTE prevent access because we are
- *	doing software DIRTY bit management and the page is currently not DIRTY. 
- * 4. This is a Kernel address (0xC---) for which there is no page directory.
- *	There is an HPTE for this page, but the pp bits prevent access.
- *      Since we always set up kernel pages with R/W access for the kernel
- *	this case only comes about for users trying to access the kernel.
- *	This case is always an error and is not dealt with further here.
- * 5. This is a Kernel address (0xC---) for which there is no page directory.
- *	There is no HPTE for this page.
-
- * Check the user's access rights to the page.  If access should be prevented
- * then send the problem up to do_page_fault.
- */
-
-	access |= _PAGE_PRESENT;
-	if ( 0 == ( access & ~(pte_val(old_pte)) ) ) {
-		/*
-		 * Check if pte might have an hpte, but we have
-		 * no slot information
-		 */
-		if ( pte_val(old_pte) & _PAGE_HPTENOIX ) {
-			unsigned long slot;	
-			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
-			slot = ppc_md.hpte_find( vpn );
-			if ( slot != -1 ) {
-				if ( slot < 0 ) {
-					pte_val(old_pte) |= _PAGE_SECONDARY;
-					slot = -slot;
-				}
-				pte_val(old_pte) |= ((slot << 12) & _PAGE_GROUP_IX) | _PAGE_HASHPTE;
-				
-			}
-		}
-
-		/* User has appropriate access rights. */
-		new_pte = old_pte;
-		/* If the attempted access was a store */
-		if ( access & _PAGE_RW )
-			pte_val(new_pte) |= _PAGE_ACCESSED |
-				_PAGE_DIRTY;
-		else
-			pte_val(new_pte) |= _PAGE_ACCESSED;
 
-		/* Only cases 1, 3 and 5 still in play */
-
-		newpp = computeHptePP( pte_val(new_pte) );
-
-		/* Check if pte already has an hpte (case 3) */
-		if ( pte_val(old_pte) & _PAGE_HASHPTE ) {
-			/* There MIGHT be an HPTE for this pte */
-			unsigned long hash, slot, secondary;
-			/* Local copy of first doubleword of HPTE */
-			union {
-				unsigned long d;
-				Hpte_dword0   h;
-			} hpte_dw0;
-			hash = hpt_hash(vpn, 0);
-			secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
-			if ( secondary )
-				hash = ~hash;
-			slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-			slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
-			/* If there is an HPTE for this page it is indexed by slot */
-			hpte_dw0.d = ppc_md.hpte_getword0( slot );
-			if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
-			     (hpte_dw0.h.v) && 
-			     (hpte_dw0.h.h == secondary ) ){
-				/* HPTE matches */
-				ppc_md.hpte_updatepp( slot, newpp, va );
-				if ( !pte_same( old_pte, new_pte ) )
-					*ptep = new_pte;
-			}
-			else {
-				/* HPTE is not for this pte */
-				pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
-			}
-		}
-		if ( !( pte_val(old_pte) & _PAGE_HASHPTE ) ) {
-			/* Cases 1 and 5 */
-			/* For these cases we need to create a new
-			 * HPTE and update the linux pte (for
-			 * case 1).  For case 5 there is no linux pte.
-			 *
-			 * Find an available HPTE slot
- 			 */
-			slot = ppc_md.hpte_selectslot( vpn );
-
-			/* Debug code */
-			if ( slot == 0x8000000000000000 ) {
-				unsigned long xold_pte = pte_val(old_pte);
-				unsigned long xnew_pte = pte_val(new_pte);
-				
-				udbg_printf("hash_page: ptep    = 0x%016lx\n", (unsigned long)ptep );
-				udbg_printf("hash_page: old_pte = 0x%016lx\n", xold_pte );
-				udbg_printf("hash_page: new_pte = 0x%016lx\n", xnew_pte );
-				udbg_printf("hash_page: ea      = 0x%016lx\n", ea );
-				udbg_printf("hash_page: va      = 0x%016lx\n", va );
-				udbg_printf("hash_page: access  = 0x%016lx\n", access );
-			
-				panic("hash_page: hpte already exists\n");
-			}
-
-			hash_ind = 0;
-			if ( slot < 0 ) {
-				slot = -slot;
-				hash_ind = 1;
-			}
-
-			/* Set the physical address */
-			prpn = pte_val(old_pte) >> PTE_SHIFT;
-			
-			if ( ptep ) {
-				/* Update the linux pte with the HPTE slot */
-				pte_val(new_pte) &= ~_PAGE_HPTEFLAGS;
-				pte_val(new_pte) |= hash_ind << 15;
-				pte_val(new_pte) |= (slot<<12) & _PAGE_GROUP_IX;
-				pte_val(new_pte) |= _PAGE_HASHPTE;
-				/* No need to use ldarx/stdcx here because all
-				 * who might be updating the pte will hold the page_table_lock
-				 * or the hash_table_lock (we hold both)
-				 */
-				*ptep = new_pte;
-			}
-
-			/* copy appropriate flags from linux pte */
-			hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
-
-			/* Create the HPTE */
-			ppc_md.hpte_create_valid( slot, vpn, prpn, hash_ind, ptep, hpteflags, 0 ); 
-
-		}
+	if (pgdir == NULL)
+		return 1;
 
-		/* Indicate success */
-		rc = 0;
-	}		
-	
-	spin_unlock( &hash_table_lock );
-	if (ptep)
-		spin_unlock( &mm->page_table_lock );
+	/*
+	 * Lock the Linux page table to prevent mmap and kswapd
+	 * from modifying entries while we search and update
+	 */
+	spin_lock(&mm->page_table_lock);
+	ptep = find_linux_pte(pgdir, ea);
+	ret = __hash_page(ea, access, vsid, ptep);
+	spin_unlock(&mm->page_table_lock);
 
-	return rc;
+	return ret;
 }
 
-void flush_hash_page( unsigned long context, unsigned long ea, pte_t pte )
+void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte,
+		     int local)
 {
-	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
-	/* Local copy of first doubleword of HPTE */
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
+	unsigned long vsid, vpn, va, hash, secondary, slot;
 
-	if ( (ea >= USER_START ) && ( ea <= USER_END ) )
-		vsid = get_vsid( context, ea );
+	/* XXX fix for large ptes */
+	unsigned long large = 0;
+
+	if ((ea >= USER_START) && (ea <= USER_END))
+		vsid = get_vsid(context, ea);
 	else
-		vsid = get_kernel_vsid( ea );
+		vsid = get_kernel_vsid(ea);
+
 	va = (vsid << 28) | (ea & 0x0fffffff);
-	vpn = va >> PAGE_SHIFT;
-	hash = hpt_hash(vpn, 0);
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+	hash = hpt_hash(vpn, large);
 	secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
-	if ( secondary )
+	if (secondary)
 		hash = ~hash;
 	slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
 	slot += (pte_val(pte) & _PAGE_GROUP_IX) >> 12;
-	/* If there is an HPTE for this page it is indexed by slot */
 
-	spin_lock_irqsave( &hash_table_lock, flags);
-	hpte_dw0.d = ppc_md.hpte_getword0( slot );
-	if ( (hpte_dw0.h.avpn == (vpn >> 11) ) &&
-	     (hpte_dw0.h.v) && 
-	     (hpte_dw0.h.h == secondary ) ){
-		/* HPTE matches */
-		ppc_md.hpte_invalidate( slot );	
-	}
-	else {
-		unsigned k;
-		/* Temporarily lets check for the hpte in all possible slots */
-		for ( secondary = 0; secondary < 2; ++secondary ) {
-			hash = hpt_hash(vpn, 0);
-			if ( secondary )
-				hash = ~hash;
-			slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-			for ( k=0; k<8; ++k ) {
-				hpte_dw0.d = ppc_md.hpte_getword0( slot+k );
-				if ( ( hpte_dw0.h.avpn == (vpn >> 11) ) &&
-				     ( hpte_dw0.h.v ) &&
-				     ( hpte_dw0.h.h == secondary ) ) {
-					while (1) ;
-				}
-			}
-		}
-		
-	}
-	spin_unlock_irqrestore( &hash_table_lock, flags );
+	ppc_md.hpte_invalidate(slot, va, large, local);
 }
 
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-		   void *buffer, size_t *lenp)
+void flush_hash_range(unsigned long context, unsigned long number, int local)
 {
-	int vleft, first=1, len, left, val;
-#define TMPBUFLEN 256
-	char buf[TMPBUFLEN], *p;
-	static const char *sizestrings[4] = {
-		"2MB", "256KB", "512KB", "1MB"
-	};
-	static const char *clockstrings[8] = {
-		"clock disabled", "+1 clock", "+1.5 clock", "reserved(3)",
-		"+2 clock", "+2.5 clock", "+3 clock", "reserved(7)"
-	};
-	static const char *typestrings[4] = {
-		"flow-through burst SRAM", "reserved SRAM",
-		"pipelined burst SRAM", "pipelined late-write SRAM"
-	};
-	static const char *holdstrings[4] = {
-		"0.5", "1.0", "(reserved2)", "(reserved3)"
-	};
-
-	if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
-		return -EFAULT;
-	
-	if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
-		*lenp = 0;
-		return 0;
-	}
-	
-	vleft = table->maxlen / sizeof(int);
-	left = *lenp;
-	
-	for (; left /*&& vleft--*/; first=0) {
-		if (write) {
-			while (left) {
-				char c;
-				if(get_user(c,(char *) buffer))
-					return -EFAULT;
-				if (!isspace(c))
-					break;
-				left--;
-				((char *) buffer)++;
-			}
-			if (!left)
-				break;
-			len = left;
-			if (len > TMPBUFLEN-1)
-				len = TMPBUFLEN-1;
-			if(copy_from_user(buf, buffer, len))
-				return -EFAULT;
-			buf[len] = 0;
-			p = buf;
-			if (*p < '0' || *p > '9')
-				break;
-			val = simple_strtoul(p, &p, 0);
-			len = p-buf;
-			if ((len < left) && *p && !isspace(*p))
-				break;
-			buffer += len;
-			left -= len;
-#if 0
-			/* DRENG need a def */
-			_set_L2CR(0);
-			_set_L2CR(val);
-			while ( _get_L2CR() & 0x1 )
-				/* wait for invalidate to finish */;
-#endif
-			  
-		} else {
-			p = buf;
-			if (!first)
-				*p++ = '\t';
-#if 0
-			/* DRENG need a def */
-			val = _get_L2CR();
-#endif
-			p += sprintf(p, "0x%08x: ", val);
-			p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" :
-				     "disabled");
-			p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no ");
-			p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]);
-			p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]);
-			p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]);
-			p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : "");
-			p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": "");
-			p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" :
-				     "copy-back");
-			p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : "");
-			p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]);
-			p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : "");
-			p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :"");
-			p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :"");
-			
-			p += sprintf(p,"\n");
-			
-			len = strlen(buf);
-			if (len > left)
-				len = left;
-			if(copy_to_user(buffer, buf, len))
-				return -EFAULT;
-			left -= len;
-			buffer += len;
-			break;
-		}
-	}
-
-	if (!write && !first && left) {
-		if(put_user('\n', (char *) buffer))
-			return -EFAULT;
-		left--, buffer++;
-	}
-	if (write) {
-		p = (char *) buffer;
-		while (left) {
-			char c;
-			if(get_user(c, p++))
-				return -EFAULT;
-			if (!isspace(c))
-				break;
-			left--;
+	if (ppc_md.flush_hash_range) {
+		ppc_md.flush_hash_range(context, number, local);
+	} else {
+		int i;
+		struct tlb_batch_data *ptes =
+			&tlb_batch_array[smp_processor_id()][0];
+
+		for (i = 0; i < number; i++) {
+			flush_hash_page(context, ptes->addr, ptes->pte, local);
+			ptes++;
 		}
 	}
-	if (write && first)
-		return -EINVAL;
-	*lenp -= left;
-	filp->f_pos += *lenp;
-	return 0;
 }
-
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_irq.c linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_irq.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_irq.c	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_irq.c	Tue Apr  9 18:35:18 2002
@@ -106,7 +106,7 @@
 {
 	u8 idsel = (deviceId >> 4);
 	u8 function = deviceId & 0x0F;
-	int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 254) + 1;
+	int irq = ((((busNumber-1)*16 + (idsel-1)*8 + function)*9/8) % 253) + 2;
 	return irq;
 }
 
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_pci.c linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_pci.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_pci.c	Mon Mar 18 12:37:19 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_pci.c	Tue Apr  9 18:35:19 2002
@@ -21,6 +21,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h> 
 #include <linux/string.h>
@@ -36,12 +37,12 @@
 #include <asm/ppcdebug.h>
 #include <asm/Naca.h>
 #include <asm/flight_recorder.h>
+#include <asm/pci_dma.h>
 
 #include <asm/iSeries/HvCallPci.h>
 #include <asm/iSeries/HvCallSm.h>
 #include <asm/iSeries/HvCallXm.h>
 #include <asm/iSeries/LparData.h>
-#include <asm/iSeries/iSeries_dma.h>
 #include <asm/iSeries/iSeries_irq.h>
 #include <asm/iSeries/iSeries_pci.h>
 #include <asm/iSeries/mf.h>
@@ -92,12 +93,12 @@
 
 void  iSeries_Scan_PHBs_Slots(struct pci_controller* Phb);
 void  iSeries_Scan_EADs_Bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
-int   iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgents);
+int   iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* Info);
 void  list_device_nodes(void);
 
 struct pci_dev;
 
-LIST_HEAD(Global_Device_List);
+extern struct list_head iSeries_Global_Device_List;
 
 int DeviceCount = 0;
 
@@ -138,6 +139,9 @@
 		    ISERIES_SUBBUS(DevNode),
 		    DevNode->AgentId,
 		    DevNode->DevFn);
+	udbg_printf("     - LSlot     = 0x%02X\n",DevNode->LogicalSlot);
+	udbg_printf("     - TceTable  = 0x%p\n  ",DevNode->DevTceTable);
+
 	udbg_printf("     - DSA       = 0x%04X\n",ISERIES_DSA(DevNode)>>32 );
 
 	udbg_printf("                 = Irq:0x%02X Vendor:0x%04X  Flags:0x%02X\n",
@@ -145,14 +149,16 @@
 		    DevNode->Vendor,
 		    DevNode->Flags );
 	udbg_printf("     - Location  = %s\n",DevNode->CardLocation);
+
+
 }
 /**********************************************************************************
  * Walk down the device node chain 
  **********************************************************************************/
 void  list_device_nodes(void)
 {
-	struct list_head* Device_Node_Ptr = Global_Device_List.next;
-	while(Device_Node_Ptr != &Global_Device_List) {
+	struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next;
+	while(Device_Node_Ptr != &iSeries_Global_Device_List) {
 		dumpDevice_Node( (struct iSeries_Device_Node*)Device_Node_Ptr );
 		Device_Node_Ptr = Device_Node_Ptr->next;
 	}
@@ -167,13 +173,13 @@
 {
 	struct iSeries_Device_Node*  DeviceNode;
 
-	PPCDBG(PPCDBG_BUSWALK,"- "__FUNCTION__" 0x%02X.%02X.%02X Function: %02X\n",Bus,SubBus,AgentId, Function);
+	PPCDBG(PPCDBG_BUSWALK,"-build_device_node 0x%02X.%02X.%02X Function: %02X\n",Bus,SubBus,AgentId, Function);
 
 	DeviceNode = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL);
 	if(DeviceNode == NULL) return NULL;
 
 	memset(DeviceNode,0,sizeof(struct iSeries_Device_Node) );
-	list_add_tail(&DeviceNode->Device_List,&Global_Device_List);
+	list_add_tail(&DeviceNode->Device_List,&iSeries_Global_Device_List);
 	/*DeviceNode->DsaAddr      = ((u64)Bus<<48)+((u64)SubBus<<40)+((u64)0x10<<32); */
 	ISERIES_BUS(DeviceNode)       = Bus;
 	ISERIES_SUBBUS(DeviceNode)    = SubBus;
@@ -224,7 +230,7 @@
 	struct      pci_controller* phb;
 	HvBusNumber BusNumber;
 
-	PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry\n");
+	PPCDBG(PPCDBG_BUSWALK,"find_and_init_phbs Entry\n");
 
 	/* Check all possible buses. */
 	for (BusNumber = 0; BusNumber < 256; BusNumber++) {
@@ -239,7 +245,7 @@
 			phb->pci_mem_offset = phb->local_number = BusNumber;
 			phb->first_busno  = BusNumber;
 			phb->last_busno   = BusNumber;
-			phb->ops = &iSeries_pci_ops;
+			phb->ops          = &iSeries_pci_ops;
 
 			PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",phb,BusNumber);
 			PCIFR("Create iSeries PHB controller: %04X",BusNumber);
@@ -276,26 +282,15 @@
  ***********************************************************************/
 void iSeries_pcibios_init(void)
 {
-	struct pci_controller *phb;
-	PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry.\n"); 
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Entry.\n"); 
 
 	iSeries_IoMmTable_Initialize();
 
 	find_and_init_phbs();
 
-	/* Create the TCE Tables */
-	phb = hose_head;
-	while(phb != NULL) {
-		create_pci_bus_tce_table(phb->local_number);
-		PCIFR("Bus 0x%04X TCE Table %p",phb->local_number,tceTables[phb->local_number] );
-		phb = phb->next;
-	}
-
-
 	pci_assign_all_busses = 0;
-	PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Exit.\n"); 
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Exit.\n"); 
 }
-
 /***********************************************************************
  * iSeries_pcibios_fixup(void)  
  ***********************************************************************/
@@ -306,11 +301,12 @@
 	char   Buffer[256];
     	int    DeviceCount = 0;
 
-	PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" Entry.\n"); 
-
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup Entry.\n"); 
 	/******************************************************/
 	/* Fix up at the device node and pci_dev relationship */
 	/******************************************************/
+	mf_displaySrc(0xC9000100);
+
 	pci_for_each_dev(PciDev) {
 		DeviceNode = find_Device_Node(PciDev);
 		if(DeviceNode != NULL) {
@@ -327,6 +323,7 @@
 			iSeries_Device_Information(PciDev,Buffer, sizeof(Buffer) );
 			printk("%d. %s\n",DeviceCount,Buffer);
 
+			create_pci_bus_tce_table((unsigned long)DeviceNode);
 		} else {
 			printk("PCI: Device Tree not found for 0x%016lX\n",(unsigned long)PciDev);
 		}
@@ -335,37 +332,18 @@
 
 	iSeries_activate_IRQs();
 
-	// This is test code. 
-	//mf_displaySrc(0xC9000100);
-	//Pci_IoTest();
-	// Pci_CfgIoTest(); 
-	// mf_displaySrc(0xC9000500);
-	// Pci_MMIoTest(); 
-	//mf_displaySrc(0xC9000999);
-}	
+	mf_displaySrc(0xC9000200);
+}
+
 /***********************************************************************
  * iSeries_pcibios_fixup_bus(int Bus)
  *
  ***********************************************************************/
 void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus)
 {
-	PPCDBG(PPCDBG_BUSWALK,__FUNCTION__"(0x%04X) Entry.\n",PciBus->number); 
+	PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",PciBus->number); 
 
 }
-/***********************************************************************
- * find_floppy(void) 
- *	
- * Finds the default floppy device, if the system has one, and returns 
- * the pci_dev for the isa bridge for the floppy device.  
- *
- * Note: On iSeries there will only be a virtual diskette. 
- ***********************************************************************/
-struct pci_dev*
-find_floppy(void)
-{
-	PPCDBG(PPCDBG_BUSWALK,"- Find Floppy pci_dev.. None on iSeries.\n");
-	return NULL;
-}
 
 
 /***********************************************************************
@@ -374,7 +352,7 @@
  ***********************************************************************/
 void fixup_resources(struct pci_dev *PciDev)
 {
-	PPCDBG(PPCDBG_BUSWALK,__FUNCTION__" PciDev %p\n",PciDev);
+	PPCDBG(PPCDBG_BUSWALK,"fixup_resources PciDev %p\n",PciDev);
 }   
 
 
@@ -409,7 +387,6 @@
 	kfree(DevInfo);
 }
 
-
 /********************************************************************************
 * 
 *********************************************************************************/
@@ -432,18 +409,26 @@
  		if (HvRc == 0) {
   			/*  Connect EADs: 0x18.00.12 = 0x00 */
 			PPCDBG(PPCDBG_BUSWALK,"PCI:Connect EADs: 0x%02X.%02X.%02X\n",Bus, SubBus, AgentId);
-			PCIFR(                "Connect EADs: 0x%02X.%02X.%02X",  Bus, SubBus, AgentId);
+			PCIFR(                    "Connect EADs: 0x%02X.%02X.%02X",  Bus, SubBus, AgentId);
 	    		HvRc = HvCallPci_getBusUnitInfo(Bus, SubBus, AgentId, 
 			                                REALADDR(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo));
 	 		if (HvRc == 0) {
-				PPCDBG(PPCDBG_BUSWALK,"PCI: BridgeInfo, Type: 0x%02X, SubBus 0x%02X, MaxAgents 0x%02X\n",
-				                        BridgeInfo->busUnitInfo.deviceType,
-				                         BridgeInfo->subBusNumber,
-				                          BridgeInfo->maxAgents);
+				PPCDBG(PPCDBG_BUSWALK,"PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n",
+				       BridgeInfo->busUnitInfo.deviceType,
+				       BridgeInfo->subBusNumber,
+				       BridgeInfo->maxAgents,
+				       BridgeInfo->maxSubBusNumber,
+				       BridgeInfo->logicalSlotNumber);
+				PCIFR(                     "BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X",
+				       BridgeInfo->busUnitInfo.deviceType,
+				       BridgeInfo->subBusNumber,
+				       BridgeInfo->maxAgents,
+				       BridgeInfo->maxSubBusNumber,
+				       BridgeInfo->logicalSlotNumber);
 
 				if (BridgeInfo->busUnitInfo.deviceType == HvCallPci_BridgeDevice)  {
 					/* Scan_Bridge_Slot...: 0x18.00.12 */
-					iSeries_Scan_Bridge_Slot(Bus,BridgeInfo->subBusNumber,BridgeInfo->maxAgents);
+					iSeries_Scan_Bridge_Slot(Bus,BridgeInfo);
 				}
 				else printk("PCI: Invalid Bridge Configuration(0x%02X)",BridgeInfo->busUnitInfo.deviceType);
 			}
@@ -458,17 +443,18 @@
 * This assumes that the node slot is always on the primary bus!
 *
 *********************************************************************************/
-int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, HvSubBusNumber SubBus, int MaxAgents)
+int iSeries_Scan_Bridge_Slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo* BridgeInfo)
 {
-     struct iSeries_Device_Node* DeviceNode;
-	u16       VendorId   = 0;
-	int       HvRc       = 0;
-	int       Irq        = 0;
-	int       IdSel      = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
-	int       Function   = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
-	HvAgentId AgentId    = ISERIES_PCI_AGENTID(IdSel, Function);
-	HvAgentId EADsIdSel  = ISERIES_PCI_AGENTID(IdSel, Function);
-	int       FirstSlotId= 0; 	
+	struct iSeries_Device_Node* DeviceNode;
+	HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
+	u16       VendorId    = 0;
+	int       HvRc        = 0;
+	int       Irq         = 0;
+	int       IdSel       = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
+	int       Function    = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
+	HvAgentId AgentId     = ISERIES_PCI_AGENTID(IdSel, Function);
+	HvAgentId EADsIdSel   = ISERIES_PCI_AGENTID(IdSel, Function);
+	int       FirstSlotId = 0; 	
 
 	/**********************************************************/
 	/* iSeries_allocate_IRQ.: 0x18.00.12(0xA3)                */
@@ -480,7 +466,7 @@
 	/****************************************************************************
 	 * Connect all functions of any device found.  
 	 ****************************************************************************/
-  	for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) {
+  	for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
     		for (Function = 0; Function < 8; ++Function) {
 			AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
 			HvRc = HvCallXm_connectBusUnit(Bus, SubBus, AgentId, Irq);
@@ -494,10 +480,13 @@
 					PPCDBG(PPCDBG_BUSWALK,"PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X\n",
 					                                       Bus, SubBus, AgentId, VendorId);
 					++DeviceCount;
-					PCIFR("Device(%4d): 0x%02X.%02X.%02X",DeviceCount,Bus, SubBus, AgentId);
 					DeviceNode = build_device_node(Bus, SubBus, EADsIdSel, Function);
-					DeviceNode->Vendor = VendorId;
-					DeviceNode->Irq    = Irq;
+					DeviceNode->Vendor      = VendorId;
+					DeviceNode->Irq         = Irq;
+					DeviceNode->LogicalSlot = BridgeInfo->logicalSlotNumber;
+					PCIFR("Device(%4d): 0x%02X.%02X.%02X 0x%02X 0x%04X",
+					      DeviceCount,Bus, SubBus, AgentId,
+					      DeviceNode->LogicalSlot,DeviceNode->Vendor);
 
 					/***********************************************************
 					 * On the first device/function, assign irq to slot
@@ -557,11 +546,11 @@
  **********************************************************************************/
 struct iSeries_Device_Node* find_Device_Node(struct pci_dev* PciDev)
 {
-	struct list_head* Device_Node_Ptr = Global_Device_List.next;
+	struct list_head* Device_Node_Ptr = iSeries_Global_Device_List.next;
 	int Bus   = PciDev->bus->number;
 	int DevFn = PciDev->devfn;
 	
-	while(Device_Node_Ptr != &Global_Device_List) { 
+	while(Device_Node_Ptr != &iSeries_Global_Device_List) { 
 		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)Device_Node_Ptr;
 		if(Bus == ISERIES_BUS(DevNode) && DevFn == DevNode->DevFn) {
 			return DevNode;
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_setup.c linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_setup.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_setup.c	Tue Apr  9 18:35:19 2002
@@ -26,6 +26,7 @@
 #include <linux/string.h>
 #include <linux/bootmem.h>
 #include <linux/blk.h>
+#include <linux/seq_file.h>
 
 #include <asm/processor.h>
 #include <asm/machdep.h>
@@ -587,6 +588,7 @@
 
 	lmb_init();
 	lmb_add( 0, naca->physicalMemorySize );
+	lmb_analyze();	/* ?? */
 	lmb_reserve( 0, __pa(klimit));
 
 	/* 
@@ -603,8 +605,10 @@
 static void __init setup_iSeries_cache_sizes(void)
 {
 	unsigned i,n;
-	naca->iCacheL1LineSize = xIoHriProcessorVpd[0].xInstCacheOperandSize;
-	naca->dCacheL1LineSize = xIoHriProcessorVpd[0].xDataCacheOperandSize;
+	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
+
+	naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
+	naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
 	naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
 	naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
 	i = naca->iCacheL1LineSize;
@@ -652,6 +656,9 @@
 }
 #endif /* CONFIG_PPC_ISERIES */
 
+extern unsigned long ppc_proc_freq;
+extern unsigned long ppc_tb_freq;
+
 /*
  * Document me.
  */
@@ -659,7 +666,8 @@
 iSeries_setup_arch(void)
 {
 	void *	eventStack;
-	
+	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
+
 	/* Setup the Lp Event Queue */
 
 	/* Allocate a page for the Event Stack
@@ -685,15 +693,19 @@
 	xItLpQueue.xIndex = 0;
 	
 	/* Compute processor frequency */
-	procFreqHz = (((1UL<<34) * 1000000) / xIoHriProcessorVpd[0].xProcFreq );
+	procFreqHz = (((1UL<<34) * 1000000) / xIoHriProcessorVpd[procIx].xProcFreq );
 	procFreqMhz = procFreqHz / 1000000;
 	procFreqMhzHundreths = (procFreqHz/10000) - (procFreqMhz*100);
 
+	ppc_proc_freq = procFreqHz;
+
 	/* Compute time base frequency */
-	tbFreqHz = (((1UL<<32) * 1000000) / xIoHriProcessorVpd[0].xTimeBaseFreq );
+	tbFreqHz = (((1UL<<32) * 1000000) / xIoHriProcessorVpd[procIx].xTimeBaseFreq );
 	tbFreqMhz = tbFreqHz / 1000000;
 	tbFreqMhzHundreths = (tbFreqHz/10000) - (tbFreqMhz*100);
 
+	ppc_tb_freq = tbFreqHz;
+
 	printk("Max  logical processors = %d\n", 
 			itVpdAreas.xSlicMaxLogicalProcs );
 	printk("Max physical processors = %d\n",
@@ -705,12 +717,12 @@
 			tbFreqMhz,
 			tbFreqMhzHundreths );
 	printk("Processor version = %x\n",
-			xIoHriProcessorVpd[0].xPVR );
+			xIoHriProcessorVpd[procIx].xPVR );
 
 }
 
 /*
- * int iSeries_setup_residual()
+ * int as400_setup_residual()
  *
  * Description:
  *   This routine pretty-prints CPU information gathered from the VPD    
@@ -726,20 +738,25 @@
  *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
  *   on error.
  */
-void
-iSeries_setup_residual(struct seq_file *m, unsigned long cpu_id)
+void iSeries_setup_residual(struct seq_file *m)
 {
-	seq_printf(m, "clock\t\t: %lu.%02luMhz\n", procFreqMhz,
-			procFreqMhzHundreths);
-	seq_printf(m, "time base\t: %lu.%02luMHz\n", tbFreqMhz,
-			tbFreqMhzHundreths);
-	seq_printf(m, "i-cache\t\t: %d\n", naca->iCacheL1LineSize);
-	seq_printf(m, "d-cache\t\t: %d\n", naca->dCacheL1LineSize);
+	
+	seq_printf(m,"clock\t\t: %lu.%02luMhz\n",
+		procFreqMhz, procFreqMhzHundreths );
+	seq_printf(m,"time base\t: %lu.%02luMHz\n",
+		tbFreqMhz, tbFreqMhzHundreths );
+	seq_printf(m,"i-cache\t\t: %d\n",
+		naca->iCacheL1LineSize);
+	seq_printf(m,"d-cache\t\t: %d\n",
+		naca->dCacheL1LineSize);
+
 }
 
 void iSeries_get_cpuinfo(struct seq_file *m)
 {
-	seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
+
+	seq_printf(m,"machine\t\t: 64-bit iSeries Logical Partition\n");
+
 }
 
 /*
@@ -805,29 +822,29 @@
 void __init
 iSeries_calibrate_decr(void)
 {
-	unsigned long	freq;
 	unsigned long	cyclesPerUsec;
-	unsigned long	tbf;
 
 	struct div_result divres;
 	
 	/* Compute decrementer (and TB) frequency 
 	 * in cycles/sec 
 	 */
-	
-	tbf = xIoHriProcessorVpd[0].xTimeBaseFreq;
-	
-	freq = 0x0100000000;
-	freq *= 1000000;		/* 2^32 * 10^6 */
-	freq = freq / tbf;		/* cycles / sec */
-	cyclesPerUsec = freq / 1000000;	/* cycles / usec */
+
+	cyclesPerUsec = ppc_tb_freq / 1000000;	/* cycles / usec */
 
 	/* Set the amount to refresh the decrementer by.  This
 	 * is the number of decrementer ticks it takes for 
 	 * 1/HZ seconds.
 	 */
 
-	tb_ticks_per_jiffy = freq / HZ;
+	tb_ticks_per_jiffy = ppc_tb_freq / HZ;
+
+#if 0
+	/* TEST CODE FOR ADJTIME */
+	tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000;
+	/* END OF TEST CODE */
+#endif
+
 	/*
 	 * tb_ticks_per_sec = freq; would give better accuracy
 	 * but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures
@@ -836,7 +853,7 @@
 	 */
 	tb_ticks_per_sec   = tb_ticks_per_jiffy * HZ;
 	tb_ticks_per_usec = cyclesPerUsec;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+	tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
 	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
 	tb_to_xs = divres.result_low;
 	setup_default_decr();
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_setup.h linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_setup.h
--- linux-2.5.8-pre2/arch/ppc64/kernel/iSeries_setup.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/iSeries_setup.h	Tue Apr  9 18:35:19 2002
@@ -19,8 +19,6 @@
 #ifndef	__ISERIES_SETUP_H__
 #define	__ISERIES_SETUP_H__
 
-#include <linux/seq_file.h>
-
 extern void		 iSeries_init_early(void);
 extern void		 iSeries_init(unsigned long r3,
 			            unsigned long ird_start,
@@ -28,8 +26,7 @@
 				    unsigned long cline_start,
 				    unsigned long cline_end);
 extern void		 iSeries_setup_arch(void);
-extern void		 iSeries_setup_residual(struct seq_file *m,
-						unsigned long cpu_id);
+extern void		 iSeries_setup_residual(struct seq_file *m);
 extern void		 iSeries_get_cpuinfo(struct seq_file *m);
 extern void		 iSeries_init_IRQ(void);
 extern int		 iSeries_get_irq(struct pt_regs *regs);
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/idle.c linux-2.5.8-pre3/arch/ppc64/kernel/idle.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/idle.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/idle.c	Tue Apr  9 18:35:19 2002
@@ -1,14 +1,12 @@
 /*
- * Idle daemon for PowerPC.  Idle daemon will handle any action
- * that needs to be taken when the system becomes idle.
- *
- * Written by Cort Dougan (cort@cs.nmt.edu)
+ * idle.c
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -28,8 +26,10 @@
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/cache.h>
-
 #include <asm/time.h>
+
+#ifdef CONFIG_PPC_ISERIES
+
 #include <asm/iSeries/LparData.h>
 #include <asm/iSeries/HvCall.h>
 #include <asm/iSeries/ItLpQueue.h>
@@ -37,105 +37,109 @@
 unsigned long maxYieldTime = 0;
 unsigned long minYieldTime = 0xffffffffffffffffUL;
 
-#ifdef CONFIG_PPC_ISERIES
 static void yield_shared_processor(void)
 {
-	struct Paca *paca;
 	unsigned long tb;
 	unsigned long yieldTime;
 
-	paca = (struct Paca *)mfspr(SPRG3);
-	HvCall_setEnabledInterrupts( HvCall_MaskIPI |
-				     HvCall_MaskLpEvent |
-				     HvCall_MaskLpProd |
-				     HvCall_MaskTimeout );
+	HvCall_setEnabledInterrupts(HvCall_MaskIPI |
+				    HvCall_MaskLpEvent |
+				    HvCall_MaskLpProd |
+				    HvCall_MaskTimeout);
 
 	tb = get_tb();
 	/* Compute future tb value when yield should expire */
-	HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
+	HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
 
 	yieldTime = get_tb() - tb;
-	if ( yieldTime > maxYieldTime )
+	if (yieldTime > maxYieldTime)
 		maxYieldTime = yieldTime;
 
-	if ( yieldTime < minYieldTime )
+	if (yieldTime < minYieldTime)
 		minYieldTime = yieldTime;
 	
-	/* The decrementer stops during the yield.  Force a fake decrementer
+	/*
+	 * The decrementer stops during the yield.  Force a fake decrementer
 	 * here and let the timer_interrupt code sort out the actual time.
 	 */
-	paca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	get_paca()->xLpPaca.xIntDword.xFields.xDecrInt = 1;
 	process_iSeries_events();
 }
-#endif /* CONFIG_PPC_ISERIES */
 
-int idled(void)
+int cpu_idle(void)
 {
 	struct Paca *paca;
 	long oldval;
-#ifdef CONFIG_PPC_ISERIES
 	unsigned long CTRL;
-#endif
 
-	/* endless loop with no priority at all */
-#ifdef CONFIG_PPC_ISERIES
 	/* ensure iSeries run light will be out when idle */
 	current->thread.flags &= ~PPC_FLAG_RUN_LIGHT;
 	CTRL = mfspr(CTRLF);
 	CTRL &= ~RUNLATCH;
 	mtspr(CTRLT, CTRL);
-#endif
-
-	printk("cpu %d hits idle loop\n", smp_processor_id());
-
-	paca = (struct Paca *)mfspr(SPRG3);
 
-	while(1) {
-		if (need_resched()) {
-			schedule();
-			check_pgt_cache();
-		}
-	}
+	paca = get_paca();
 
-	for (;;) {
-#ifdef CONFIG_PPC_ISERIES
-		if ( paca->xLpPaca.xSharedProc ) {
-			if ( ItLpQueue_isLpIntPending( paca->lpQueuePtr ) )
+	while (1) {
+		if (paca->xLpPaca.xSharedProc) {
+			if (ItLpQueue_isLpIntPending(paca->lpQueuePtr))
 				process_iSeries_events();
 			if (!need_resched())
 				yield_shared_processor();
-		}
-		else 
-#endif
-		{
-			if (!need_resched()) {
+		} else {
+			oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+
+			if (!oldval) {
 				set_thread_flag(TIF_POLLING_NRFLAG);
-				while (!test_thread_flag(TIF_NEED_RESCHED)) {
-#ifdef CONFIG_PPC_ISERIES
+
+				while (!need_resched()) {
 					HMT_medium();
 					if (ItLpQueue_isLpIntPending(paca->lpQueuePtr))
 						process_iSeries_events();
-#endif
 					HMT_low();
 				}
+
+				HMT_medium();
 				clear_thread_flag(TIF_POLLING_NRFLAG);
+			} else {
+				set_need_resched();
 			}
 		}
-		HMT_medium();
-		if (need_resched()) {
+
+		if (need_resched())
 			schedule();
-			check_pgt_cache();
-		}
 	}
+
 	return 0;
 }
 
-/*
- * SMP entry into the idle task - calls the same thing as the
- * non-smp versions. -- Cort
- */
+#else /* CONFIG_PPC_ISERIES */
+
 int cpu_idle(void)
 {
-	idled();
-	return 0; 
+	long oldval;
+
+	while (1) {
+		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+
+		if (!oldval) {
+			set_thread_flag(TIF_POLLING_NRFLAG);
+
+			while (!need_resched()) {
+				barrier();
+				HMT_low();
+			}
+
+			HMT_medium();
+			clear_thread_flag(TIF_POLLING_NRFLAG);
+		} else {
+			set_need_resched();
+		}
+
+		schedule();
+	}
+
+	return 0;
 }
+
+#endif /* CONFIG_PPC_ISERIES */
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/ioctl32.c linux-2.5.8-pre3/arch/ppc64/kernel/ioctl32.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/ioctl32.c	Mon Mar 18 12:37:19 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/ioctl32.c	Tue Apr  9 18:35:19 2002
@@ -3736,8 +3736,6 @@
 COMPATIBLE_IOCTL(BLKROGET),
 COMPATIBLE_IOCTL(BLKRRPART),
 COMPATIBLE_IOCTL(BLKFLSBUF),
-COMPATIBLE_IOCTL(BLKRASET),
-COMPATIBLE_IOCTL(BLKFRASET),
 COMPATIBLE_IOCTL(BLKSECTSET),
 COMPATIBLE_IOCTL(BLKSSZGET),
 COMPATIBLE_IOCTL(BLKBSZGET),
@@ -4310,10 +4308,8 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval),
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp),
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo),
-HANDLE_IOCTL(BLKRAGET, w_long),
 HANDLE_IOCTL(BLKGETSIZE, w_long),
 HANDLE_IOCTL(0x1260, broken_blkgetsize),
-HANDLE_IOCTL(BLKFRAGET, w_long),
 HANDLE_IOCTL(BLKSECTGET, w_long),
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans),
 HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans),
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/lmb.c linux-2.5.8-pre3/arch/ppc64/kernel/lmb.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/lmb.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/lmb.c	Tue Apr  9 18:35:19 2002
@@ -28,8 +28,8 @@
 
 struct lmb lmb = {
 	0,
-	{0,0,0,{{0,0,0}}},
-	{0,0,0,{{0,0,0}}}
+	{0,0,0,0,{{0,0,0}}},
+	{0,0,0,0,{{0,0,0}}}
 };
 
 
@@ -91,24 +91,54 @@
 void
 lmb_analyze(void)
 {
-	unsigned long i, physbase = 0;
-	unsigned long total_size = 0;
+	unsigned long i;
+	unsigned long mem_size = 0;
+	unsigned long io_size = 0;
 	unsigned long size_mask = 0;
 	unsigned long offset = reloc_offset();
 	struct lmb *_lmb = PTRRELOC(&lmb);
+#ifdef CONFIG_MSCHUNKS
+	unsigned long physbase = 0;
+#endif
 
 	for (i=0; i < _lmb->memory.cnt ;i++) {
-		unsigned long lmb_size = _lmb->memory.region[i].size;
+		unsigned long lmb_type = _lmb->memory.region[i].type;
+		unsigned long lmb_size;
+
+		if ( lmb_type != LMB_MEMORY_AREA )
+			continue;
+
+		lmb_size = _lmb->memory.region[i].size;
+
 #ifdef CONFIG_MSCHUNKS
 		_lmb->memory.region[i].physbase = physbase;
-		physbase   += lmb_size;
+		physbase += lmb_size;
 #else
 		_lmb->memory.region[i].physbase = _lmb->memory.region[i].base;
 #endif
-		total_size += lmb_size;
-		size_mask  |= lmb_size;
+		mem_size += lmb_size;
+		size_mask |= lmb_size;
+	}
+
+#ifdef CONFIG_MSCHUNKS
+	for (i=0; i < _lmb->memory.cnt ;i++) {
+		unsigned long lmb_type = _lmb->memory.region[i].type;
+		unsigned long lmb_size;
+
+		if ( lmb_type != LMB_IO_AREA )
+			continue;
+
+		lmb_size = _lmb->memory.region[i].size;
+
+		_lmb->memory.region[i].physbase = physbase;
+		physbase += lmb_size;
+		io_size += lmb_size;
+		size_mask |= lmb_size;
 	}
-	_lmb->memory.size = total_size;
+#endif /* CONFIG_MSCHUNKS */
+
+	_lmb->memory.size = mem_size;
+	_lmb->memory.iosize = io_size;
 	_lmb->memory.lcd_size = (1UL << cnt_trailing_zeros(size_mask));
 }
 
@@ -124,6 +154,7 @@
 
 }
 
+#ifdef CONFIG_MSCHUNKS
 /* This routine called with relocation disabled. */
 long
 lmb_add_io(unsigned long base, unsigned long size)
@@ -135,6 +166,7 @@
 	return lmb_add_region(_rgn, base, size, LMB_IO_AREA);
 
 }
+#endif /* CONFIG_MSCHUNKS */
 
 long
 lmb_reserve(unsigned long base, unsigned long size)
@@ -268,12 +300,16 @@
 {
 	unsigned long offset = reloc_offset();
 	struct lmb *_lmb = PTRRELOC(&lmb);
+#ifdef CONFIG_MSCHUNKS
+	return _lmb->memory.size;
+#else
 	struct lmb_region *_mem = &(_lmb->memory);
 	unsigned long idx = _mem->cnt-1;
 	unsigned long lastbase = _mem->region[idx].physbase;
 	unsigned long lastsize = _mem->region[idx].size;
-
+	
 	return (lastbase + lastsize);
+#endif /* CONFIG_MSCHUNKS */
 }
 
 unsigned long
@@ -282,22 +318,26 @@
 	unsigned long offset = reloc_offset();
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_mem = &(_lmb->memory);
-	unsigned long idx = _mem->cnt-1;
+	unsigned long idx;
+
+	for(idx=_mem->cnt-1; idx >= 0 ;idx--) {
+		if ( _mem->region[idx].type != LMB_MEMORY_AREA )
+			continue;
 #ifdef CONFIG_MSCHUNKS
-	unsigned long lastbase = _mem->region[idx].physbase;
+		return (_mem->region[idx].physbase + _mem->region[idx].size);
 #else
-	unsigned long lastbase = _mem->region[idx].base;
+		return (_mem->region[idx].base + _mem->region[idx].size);
 #endif /* CONFIG_MSCHUNKS */
-	unsigned long lastsize = _mem->region[idx].size;
+	}
 
-	return (lastbase + lastsize);
+	return 0;
 }
 
 
 unsigned long
 lmb_abs_to_phys(unsigned long aa)
 {
-	unsigned long i, pa = 0;
+	unsigned long i, pa = aa;
 	unsigned long offset = reloc_offset();
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_mem = &(_lmb->memory);
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/misc.S linux-2.5.8-pre3/arch/ppc64/kernel/misc.S
--- linux-2.5.8-pre2/arch/ppc64/kernel/misc.S	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/misc.S	Tue Apr  9 18:35:19 2002
@@ -496,25 +496,15 @@
  *   kernel_thread(fn, arg, flags)
  */
 _GLOBAL(kernel_thread)
+	/* XXX fix this when we optimise syscall entry to not save volatiles */
 	mr	r6,r3		/* function */
 	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
 	sc
 	cmpi	0,r3,0		/* parent or child? */
 	bnelr			/* return if parent */
-
-	li	r0,0		/* clear out p->thread.regs */
-	std	r0,THREAD+PT_REGS(r13)	/* since we don't have user ctx */
-
-	clrrdi	r5,r1,THREAD_SHIFT
-	ld	r0,TI_FLAGS(r5)
-	li	r7,_TIF_32BIT
-	andc	r0,r0,r7
-#ifdef CONFIG_PPC_ISERIES
-	ori	r0,r0,_TIF_RUN_LIGHT	/* Run light on */
-#endif
-	std	r0,TI_FLAGS(r5)
-
+	li	r0,0
+	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
 	ld	r2,8(r6)
 	ld	r6,0(r6)
 	mtlr	r6              /* fn addr in lr */
@@ -526,8 +516,7 @@
 
 #ifdef CONFIG_BINFMT_ELF32
 /* Why isn't this a) automatic, b) written in 'C'? */	
-	.data
-	.align 8
+	.balign 8
 _GLOBAL(sys_call_table32)
 	.llong .sys_ni_syscall	/* 0  -  old "setup()" system call */
 	.llong .sys32_exit
@@ -554,7 +543,7 @@
 	.llong .sys_oldumount
 	.llong .sys_setuid
 	.llong .sys_getuid
-	.llong .ppc64_sys_stime		/* 25 */
+	.llong .ppc64_sys32_stime       /* 25 */
 	.llong .sys32_ptrace
 	.llong .sys_alarm
 	.llong .sys32_fstat
@@ -738,12 +727,25 @@
 	.llong .sys_mincore		/* 206 */
 	.llong .sys_gettid		/* 207 */
 	.llong .sys_tkill		/* 208 */
-	.rept NR_syscalls-208
+	.llong .sys_setxattr
+	.llong .sys_lsetxattr	/* 210 */
+	.llong .sys_fsetxattr
+	.llong .sys_getxattr
+	.llong .sys_lgetxattr
+	.llong .sys_fgetxattr
+	.llong .sys_listxattr	/* 215 */
+	.llong .sys_llistxattr
+	.llong .sys_flistxattr
+	.llong .sys_removexattr
+	.llong .sys_lremovexattr
+	.llong .sys_fremovexattr	/* 220 */
+	.llong .sys_futex
+	.rept NR_syscalls-221
 		.llong .sys_ni_syscall
 	.endr
 #endif
-	.data
-	.align 8
+
+	.balign 8
 _GLOBAL(sys_call_table)
 	.llong .sys_ni_syscall	/* 0  -  old "setup()" system call */
 	.llong .sys_exit
@@ -954,6 +956,19 @@
 	.llong .sys_mincore		/* 206 */
 	.llong .sys_gettid		/* 207 */
 	.llong .sys_tkill		/* 208 */
-	.rept NR_syscalls-208
+	.llong .sys_setxattr
+	.llong .sys_lsetxattr	/* 210 */
+	.llong .sys_fsetxattr
+	.llong .sys_getxattr
+	.llong .sys_lgetxattr
+	.llong .sys_fgetxattr
+	.llong .sys_listxattr	/* 215 */
+	.llong .sys_llistxattr
+	.llong .sys_flistxattr
+	.llong .sys_removexattr
+	.llong .sys_lremovexattr
+	.llong .sys_fremovexattr	/* 220 */
+	.llong .sys_futex
+	.rept NR_syscalls-221
 	.llong .sys_ni_syscall
 	.endr
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/mk_defs.c linux-2.5.8-pre3/arch/ppc64/kernel/mk_defs.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/mk_defs.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/mk_defs.c	Tue Apr  9 18:35:19 2002
@@ -115,12 +115,14 @@
 	/* Interrupt register frame */
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
 
+	DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+
 	/* 288 = # of volatile regs, int & fp, for leaf routines */
 	/* which do not stack a frame.  See the PPC64 ABI.       */
 	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
 	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
-	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
-	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
+	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
 	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
 	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
 	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/nvram.c linux-2.5.8-pre3/arch/ppc64/kernel/nvram.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/nvram.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/arch/ppc64/kernel/nvram.c	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,140 @@
+/*
+ *  c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ * /dev/nvram driver for PPC64
+ *
+ * This perhaps should live in drivers/char
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/nvram.h>
+#include <asm/rtas.h>
+#include <asm/prom.h>
+
+static unsigned int rtas_nvram_size;
+static unsigned int nvram_fetch, nvram_store;
+static char nvram_buf[4];	/* assume this is in the first 4GB */
+
+static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
+{
+	switch (origin) {
+	case 1:
+		offset += file->f_pos;
+		break;
+	case 2:
+		offset += rtas_nvram_size;
+		break;
+	}
+	if (offset < 0)
+		return -EINVAL;
+	file->f_pos = offset;
+	return file->f_pos;
+}
+
+
+static ssize_t read_nvram(struct file *file, char *buf,
+			  size_t count, loff_t *ppos)
+{
+	unsigned int i;
+	unsigned long len;
+	char *p = buf;
+
+	if (verify_area(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+	if (*ppos >= rtas_nvram_size)
+		return 0;
+	for (i = *ppos; count > 0 && i < rtas_nvram_size; ++i, ++p, --count) {
+		if ((rtas_call(nvram_fetch, 3, 2, &len, i, __pa(nvram_buf), 1) != 0) ||
+		    len != 1)
+			return -EIO;
+		if (__put_user(nvram_buf[0], p))
+			return -EFAULT;
+	}
+	*ppos = i;
+	return p - buf;
+}
+
+static ssize_t write_nvram(struct file *file, const char *buf,
+			   size_t count, loff_t *ppos)
+{
+	unsigned int i;
+	unsigned long len;
+	const char *p = buf;
+	char c;
+
+	if (verify_area(VERIFY_READ, buf, count))
+		return -EFAULT;
+	if (*ppos >= rtas_nvram_size)
+		return 0;
+	for (i = *ppos; count > 0 && i < rtas_nvram_size; ++i, ++p, --count) {
+		if (__get_user(c, p))
+			return -EFAULT;
+		nvram_buf[0] = c;
+		if ((rtas_call(nvram_store, 3, 2, &len, i, __pa(nvram_buf), 1) != 0) ||
+		    len != 1)
+			return -EIO;
+	}
+	*ppos = i;
+	return p - buf;
+}
+
+static int nvram_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+struct file_operations nvram_fops = {
+	owner:		THIS_MODULE,
+	llseek:		nvram_llseek,
+	read:		read_nvram,
+	write:		write_nvram,
+	ioctl:		nvram_ioctl,
+};
+
+static struct miscdevice nvram_dev = {
+	NVRAM_MINOR,
+	"nvram",
+	&nvram_fops
+};
+
+int __init nvram_init(void)
+{
+	struct device_node *nvram;
+	unsigned int *nbytes_p, proplen;
+	if ((nvram = find_type_devices("nvram")) != NULL) {
+		nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
+		if (nbytes_p && proplen == sizeof(unsigned int)) {
+			rtas_nvram_size = *nbytes_p;
+		}
+	}
+	nvram_fetch = rtas_token("nvram-fetch");
+	nvram_store = rtas_token("nvram-store");
+	printk(KERN_INFO "PPC64 nvram contains %d bytes\n", rtas_nvram_size);
+
+	misc_register(&nvram_dev);
+	return 0;
+}
+
+void __exit nvram_cleanup(void)
+{
+        misc_deregister( &nvram_dev );
+}
+
+module_init(nvram_init);
+module_exit(nvram_cleanup);
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pSeries_htab.c linux-2.5.8-pre3/arch/ppc64/kernel/pSeries_htab.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/pSeries_htab.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pSeries_htab.c	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,471 @@
+/*
+ * pSeries hashtable management.
+ *
+ * SMP scalability work:
+ *    Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+
+#include <asm/abs_addr.h>
+#include <asm/machdep.h>
+#include <asm/mmu.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+/*
+ * Create a pte. Used during initialization only.
+ * We assume the PTE will fit in the primary PTEG.
+ */
+void pSeries_make_pte(HPTE *htab, unsigned long va, unsigned long pa,
+		      int mode, unsigned long hash_mask, int large)
+{
+	HPTE *hptep;
+	unsigned long hash, i;
+	unsigned long vpn;
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	hash = hpt_hash(vpn, large);
+
+	hptep  = htab + ((hash & hash_mask)*HPTES_PER_GROUP);
+
+	for (i = 0; i < 8; ++i, ++hptep) {
+		if (hptep->dw0.dw0.v == 0) {		/* !valid */
+			hptep->dw1.dword1 = pa | mode;
+			hptep->dw0.dword0 = 0;
+			hptep->dw0.dw0.avpn = va >> 23;
+			hptep->dw0.dw0.bolted = 1;	/* bolted */
+			if (large) {
+				hptep->dw0.dw0.l = 1;
+				hptep->dw0.dw0.avpn &= ~0x1UL;
+			}
+			hptep->dw0.dw0.v = 1;		/* make valid */
+			return;
+		}
+	}
+
+	/* We should _never_ get here and too early to call xmon. */
+	while(1)
+		;
+}
+
+#define HPTE_LOCK_BIT 3
+
+static inline void pSeries_lock_hpte(HPTE *hptep)
+{
+	unsigned long *word = &hptep->dw0.dword0;
+
+	while (1) {
+		if (!test_and_set_bit(HPTE_LOCK_BIT, word))
+			break;
+		while(test_bit(HPTE_LOCK_BIT, word))
+			barrier();
+	}
+}
+
+static inline void pSeries_unlock_hpte(HPTE *hptep)
+{
+	unsigned long *word = &hptep->dw0.dword0;
+
+	asm volatile("lwsync":::"memory");
+	clear_bit(HPTE_LOCK_BIT, word);
+}
+
+static spinlock_t pSeries_tlbie_lock = SPIN_LOCK_UNLOCKED;
+
+static long pSeries_insert_hpte(unsigned long hpte_group, unsigned long vpn,
+				unsigned long prpn, int secondary,
+				unsigned long hpteflags, int bolted, int large)
+{
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn(prpn);
+	HPTE *hptep = htab_data.htab + hpte_group;
+	Hpte_dword0 dw0;
+	HPTE lhpte;
+	int i;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		dw0 = hptep->dw0.dw0;
+
+		if (!dw0.v) {
+			/* retry with lock held */
+			pSeries_lock_hpte(hptep);
+			dw0 = hptep->dw0.dw0;
+			if (!dw0.v)
+				break;
+			pSeries_unlock_hpte(hptep);
+		}
+
+		hptep++;
+	}
+
+	if (i == HPTES_PER_GROUP)
+		return -1;
+
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
+
+	lhpte.dw0.dword0      = 0;
+	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.h       = secondary;
+	lhpte.dw0.dw0.bolted  = bolted;
+	lhpte.dw0.dw0.v       = 1;
+
+	if (large)
+		lhpte.dw0.dw0.l = 1;
+
+	hptep->dw1.dword1 = lhpte.dw1.dword1;
+
+	/* Guarantee the second dword is visible before the valid bit */
+	__asm__ __volatile__ ("eieio" : : : "memory");
+
+	/*
+	 * Now set the first dword including the valid bit
+	 * NOTE: this also unlocks the hpte
+	 */
+	hptep->dw0.dword0 = lhpte.dw0.dword0;
+
+	__asm__ __volatile__ ("ptesync" : : : "memory");
+
+	return i;
+}
+
+static long pSeries_remove_hpte(unsigned long hpte_group)
+{
+	HPTE *hptep;
+	Hpte_dword0 dw0;
+	int i;
+	int slot_offset;
+	unsigned long vsid, group, pi, pi_high;
+	unsigned long slot;
+	unsigned long flags;
+	int large;
+	unsigned long va;
+
+	/* pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
+
+	udbg_printf("remove_hpte in %d\n", slot_offset);
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+		hptep = htab_data.htab + hpte_group + slot_offset;
+		dw0 = hptep->dw0.dw0;
+
+		if (dw0.v && !dw0.bolted) {
+			/* retry with lock held */
+			pSeries_lock_hpte(hptep);
+			dw0 = hptep->dw0.dw0;
+			if (dw0.v && !dw0.bolted)
+				break;
+			pSeries_unlock_hpte(hptep);
+		}
+
+		slot_offset++;
+		slot_offset &= 0x7;
+	}
+
+	if (i == HPTES_PER_GROUP)
+		return -1;
+
+	large = dw0.l;
+
+	/* Invalidate the hpte. NOTE: this also unlocks it */
+	hptep->dw0.dword0 = 0;
+
+	/* Invalidate the tlb */
+	vsid = dw0.avpn >> 5;
+	slot = hptep - htab_data.htab;
+	group = slot >> 3;
+	if (dw0.h)
+		group = ~group;
+	pi = (vsid ^ group) & 0x7ff;
+	pi_high = (dw0.avpn & 0x1f) << 11;
+	pi |= pi_high;
+
+	if (large)
+		va = pi << LARGE_PAGE_SHIFT;
+	else
+		va = pi << PAGE_SHIFT;
+
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, large);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+
+	return i;
+}
+
+static inline void set_pp_bit(unsigned long pp, HPTE *addr)
+{
+	unsigned long old;
+	unsigned long *p = &addr->dw1.dword1;
+
+	__asm__ __volatile__(
+	"1:	ldarx	%0,0,%3\n\
+		rldimi	%0,%2,0,62\n\
+		stdcx.	%0,0,%3\n\
+		bne	1b"
+	: "=&r" (old), "=m" (*p)
+	: "r" (pp), "r" (p), "m" (*p)
+	: "cc");
+}
+
+/*
+ * Only works on small pages. Yes its ugly to have to check each slot in
+ * the group but we only use this during bootup.
+ */
+static long pSeries_hpte_find(unsigned long vpn)
+{
+	HPTE *hptep;
+	unsigned long hash;
+	unsigned long i, j;
+	long slot;
+	Hpte_dword0 dw0;
+
+	hash = hpt_hash(vpn, 0);
+
+	for (j = 0; j < 2; j++) {
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			hptep = htab_data.htab + slot;
+			dw0 = hptep->dw0.dw0;
+
+			if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
+			    (dw0.h == j)) {
+				/* HPTE matches */
+				if (j)
+					slot = -slot;
+				return slot;
+			}
+			++slot;
+		}
+		hash = ~hash;
+	}
+
+	return -1;
+}
+
+static long pSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
+				  unsigned long va, int large)
+{
+	HPTE *hptep = htab_data.htab + slot;
+	Hpte_dword0 dw0;
+	unsigned long vpn, avpn;
+	unsigned long flags;
+
+	udbg_printf("updatepp\n");
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	avpn = vpn >> 11;
+
+	pSeries_lock_hpte(hptep);
+
+	dw0 = hptep->dw0.dw0;
+
+	if ((dw0.avpn != avpn) || !dw0.v) {
+		pSeries_unlock_hpte(hptep);
+		udbg_printf("updatepp missed\n");
+		return -1;
+	}
+
+	set_pp_bit(newpp, hptep);
+
+	pSeries_unlock_hpte(hptep);
+
+	/* Ensure it is out of the tlb too */
+	/* XXX use tlbiel where possible */
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, large);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+
+	return 0;
+}
+
+/*
+ * Update the page protection bits. Intended to be used to create
+ * guard pages for kernel data structures on pages which are bolted
+ * in the HPT. Assumes pages being operated on will not be stolen.
+ * Does not work on large pages.
+ *
+ * No need to lock here because we should be the only user.
+ */
+static void pSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea)
+{
+	unsigned long vsid, va, vpn, flags;
+	long slot;
+	HPTE *hptep;
+
+	vsid = get_kernel_vsid(ea);
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
+
+	slot = pSeries_hpte_find(vpn);
+	if (slot == -1)
+		panic("could not find page to bolt\n");
+	hptep = htab_data.htab + slot;
+
+	set_pp_bit(newpp, hptep);
+
+	/* Ensure it is out of the tlb too */
+	/* XXX use tlbiel where possible */
+	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+	_tlbie(va, 0);
+	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+}
+
+static void pSeries_hpte_invalidate(unsigned long slot, unsigned long va,
+				    int large, int local)
+{
+	HPTE *hptep = htab_data.htab + slot;
+	Hpte_dword0 dw0;
+	unsigned long vpn, avpn;
+	unsigned long flags;
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	avpn = vpn >> 11;
+
+	pSeries_lock_hpte(hptep);
+
+	dw0 = hptep->dw0.dw0;
+
+	if ((dw0.avpn != avpn) || !dw0.v) {
+		pSeries_unlock_hpte(hptep);
+		udbg_printf("invalidate missed\n");
+		return;
+	}
+
+	/* Invalidate the hpte. NOTE: this also unlocks it */
+	hptep->dw0.dword0 = 0;
+
+	/* Invalidate the tlb */
+	if (!large && local && __is_processor(PV_POWER4)) {
+		_tlbiel(va, large);
+	} else {
+		spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+		_tlbie(va, large);
+		spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+	}
+}
+
+static void pSeries_flush_hash_range(unsigned long context,
+				     unsigned long number, int local)
+{
+	unsigned long vsid, vpn, va, hash, secondary, slot, flags, avpn;
+	int i, j;
+	unsigned long va_array[MAX_BATCH_FLUSH];
+	HPTE *hptep;
+	Hpte_dword0 dw0;
+	struct tlb_batch_data *ptes = &tlb_batch_array[smp_processor_id()][0];
+	/* XXX fix for large ptes */
+	unsigned long large = 0;
+	j = 0;
+	for (i = 0; i < number; i++) {
+		if ((ptes->addr >= USER_START) && (ptes->addr <= USER_END))
+			vsid = get_vsid(context, ptes->addr);
+		else
+			vsid = get_kernel_vsid(ptes->addr);
+
+		va = (vsid << 28) | (ptes->addr & 0x0fffffff);
+		va_array[j] = va;
+		if (large)
+			vpn = va >> LARGE_PAGE_SHIFT;
+		else
+			vpn = va >> PAGE_SHIFT;
+		hash = hpt_hash(vpn, large);
+		secondary = (pte_val(ptes->pte) & _PAGE_SECONDARY) >> 15;
+		if (secondary)
+			hash = ~hash;
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		slot += (pte_val(ptes->pte) & _PAGE_GROUP_IX) >> 12;
+
+		hptep = htab_data.htab + slot;
+		avpn = vpn >> 11;
+
+		pSeries_lock_hpte(hptep);
+
+		dw0 = hptep->dw0.dw0;
+
+		ptes++;
+
+		if ((dw0.avpn != avpn) || !dw0.v) {
+			pSeries_unlock_hpte(hptep);
+			udbg_printf("invalidate missed\n");
+			continue;
+		}
+
+		j++;
+
+		/* Invalidate the hpte. NOTE: this also unlocks it */
+		hptep->dw0.dword0 = 0;
+	}
+
+	if (!large && local && __is_processor(PV_POWER4)) {
+		asm volatile("ptesync":::"memory");
+
+		for (i = 0; i < j; i++) {
+			asm volatile("\n\
+			clrldi  %0,%0,16\n\
+			tlbiel   %0"
+			: : "r" (va_array[i]) : "memory" );
+		}
+
+		asm volatile("ptesync":::"memory");
+	} else {
+		/* XXX double check that it is safe to take this late */
+		spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+
+		asm volatile("ptesync":::"memory");
+
+		for (i = 0; i < j; i++) {
+			asm volatile("\n\
+			clrldi  %0,%0,16\n\
+			tlbie   %0"
+			: : "r" (va_array[i]) : "memory" );
+		}
+
+		asm volatile("eieio; tlbsync; ptesync":::"memory");
+
+		spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+	}
+}
+
+void hpte_init_pSeries(void)
+{
+	struct device_node *root;
+	const char *model;
+
+	ppc_md.hpte_invalidate	= pSeries_hpte_invalidate;
+	ppc_md.hpte_updatepp	= pSeries_hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = pSeries_hpte_updateboltedpp;
+	ppc_md.insert_hpte	= pSeries_insert_hpte;
+	ppc_md.remove_hpte	= pSeries_remove_hpte;
+	ppc_md.make_pte		= pSeries_make_pte;
+
+	/* Disable TLB batching on nighthawk */
+	root = find_path_device("/");
+	if (root) {
+		model = get_property(root, "model", NULL);
+		if (strcmp(model, "CHRP IBM,9076-N81"))
+			ppc_md.flush_hash_range = pSeries_flush_hash_range;
+	}
+}
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pSeries_lpar.c linux-2.5.8-pre3/arch/ppc64/kernel/pSeries_lpar.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/pSeries_lpar.c	Mon Mar 18 12:37:19 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pSeries_lpar.c	Tue Apr  9 18:35:19 2002
@@ -32,6 +32,7 @@
 #include <asm/pci_dma.h>
 #include <linux/pci.h>
 #include <asm/Naca.h>
+#include <asm/tlbflush.h>
 
 /* Status return values */
 #define H_Success	0
@@ -51,6 +52,7 @@
 #define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
 #define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
 #define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
+#define H_ANDCOND		(1UL<<(63-33))
 #define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
 #define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
 #define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
@@ -214,357 +216,6 @@
 			   xirr_ret, &dummy, &dummy);
 }
 
-/*
- * The following section contains code that ultimately should
- * be put in the relavent file (htab.c, xics.c, etc).  It has
- * been put here for the time being in order to ease maintainence
- * of the pSeries LPAR code until it can all be put into CVS.
- */
-static void hpte_invalidate_pSeriesLP(unsigned long slot)
-{
-	HPTE old_pte;
-	unsigned long lpar_rc;
-	unsigned long flags = 0;
-			
-	lpar_rc = plpar_pte_remove(flags,
-				   slot,
-				   0,
-				   &old_pte.dw0.dword0, 
-				   &old_pte.dw1.dword1);
-	if (lpar_rc != H_Success) BUG();
-}
-
-/* NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
- * the low 3 bits of flags happen to line up.  So no transform is needed.
- * We can probably optimize here and assume the high bits of newpp are
- * already zero.  For now I am paranoid.
- */
-static void hpte_updatepp_pSeriesLP(long slot, unsigned long newpp, unsigned long va)
-{
-	unsigned long lpar_rc;
-	unsigned long flags;
-	flags =   newpp & 3;
-	lpar_rc = plpar_pte_protect( flags,
-				     slot,
-				     0);
-	if (lpar_rc != H_Success) {
-		udbg_printf( " bad return code from pte protect rc = %lx \n", lpar_rc); 
-		for (;;);
-	}
-}
-
-static void hpte_updateboltedpp_pSeriesLP(unsigned long newpp, unsigned long ea)
-{
-	unsigned long lpar_rc;
-	unsigned long vsid,va,vpn,flags;
-	long slot;
-
-	vsid = get_kernel_vsid( ea );
-	va = ( vsid << 28 ) | ( ea & 0x0fffffff );
-	vpn = va >> PAGE_SHIFT;
-
-	slot = ppc_md.hpte_find( vpn );
-	flags =   newpp & 3;
-	lpar_rc = plpar_pte_protect( flags,
-				     slot,
-				     0);
-	if (lpar_rc != H_Success) {
-		udbg_printf( " bad return code from pte bolted protect rc = %lx \n", lpar_rc); 
-		for (;;);
-	}
-}
-
-
-static unsigned long hpte_getword0_pSeriesLP(unsigned long slot)
-{
-	unsigned long dword0;
-	unsigned long lpar_rc;
-	unsigned long dummy_word1;
-	unsigned long flags;
-	/* Read 1 pte at a time                        */
-	/* Do not need RPN to logical page translation */
-	/* No cross CEC PFT access                     */
-	flags = 0;
-	
-	lpar_rc = plpar_pte_read(flags,
-				 slot,
-				 &dword0, &dummy_word1);
-	if (lpar_rc != H_Success) {
-		udbg_printf(" error on pte read in get_hpte0 rc = %lx \n", lpar_rc);
-		for (;;);
-	}
-
-	return(dword0);
-}
-
-static long hpte_selectslot_pSeriesLP(unsigned long vpn)
-{
-	unsigned long primary_hash;
-	unsigned long hpteg_slot;
-	unsigned i, k;
-	unsigned long flags;
-	HPTE  pte_read;
-	unsigned long lpar_rc;
-
-	/* Search the primary group for an available slot */
-	primary_hash = hpt_hash(vpn, 0);
-
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-	/* Read 1 pte at a time                        */
-	/* Do not need RPN to logical page translation */
-	/* No cross CEC PFT access                     */
-	flags = 0;
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		/* read the hpte entry from the slot */
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + i,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf(" read of hardware page table failed rc = %lx \n", lpar_rc); 
-			for (;;);
-		}
-		if ( pte_read.dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-
-	}
-
-
-	/* Search the secondary group for an available slot */
-	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		/* read the hpte entry from the slot */
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + i,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf(" read of hardware page table failed2 rc = %lx  \n", lpar_rc); 
-			for (;;);
-		}
-		if ( pte_read.dw0.dw0.v == 0 ) {
-			/* If an available slot found, return it */
-			return hpteg_slot + i;
-		}
-
-	}
-
-	/* No available entry found in secondary group */
-
-
-	/* Select an entry in the primary group to replace */
-
-	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;
-
-	k = htab_data.next_round_robin++ & 0x7;
-
-	for (i=0; i<HPTES_PER_GROUP; ++i) {
-		if (k == HPTES_PER_GROUP)
-			k = 0;
-
-		lpar_rc = plpar_pte_read(flags,
-					 hpteg_slot + k,
-					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);
-		if (lpar_rc != H_Success) {
-			udbg_printf( " pte read failed - rc = %lx", lpar_rc); 
-			for (;;);
-		}
-		if (  ! pte_read.dw0.dw0.bolted)
-		{
-			hpteg_slot += k;
-			/* Invalidate the current entry */
-			ppc_md.hpte_invalidate(hpteg_slot); 
-			return hpteg_slot;
-		}
-		++k;
-	}
-
-	/* No non-bolted entry found in primary group - time to panic */
-	udbg_printf("select_hpte_slot - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);
-	udbg_printf("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);
-	for (;;);
-
-	/* never executes - avoid compiler errors */
-	return 0;
-}
-
-
-static void hpte_create_valid_pSeriesLP(unsigned long slot, unsigned long vpn,
-					unsigned long prpn, unsigned hash, 
-					void *ptep, unsigned hpteflags, 
-					unsigned bolted)
-{
-	/* Local copy of HPTE */
-	struct {
-		/* Local copy of first doubleword of HPTE */
-		union {
-			unsigned long d;
-			Hpte_dword0   h;
-		} dw0;
-		/* Local copy of second doubleword of HPTE */
-		union {
-			unsigned long     d;
-			Hpte_dword1       h;
-			Hpte_dword1_flags f;
-		} dw1;
-	} lhpte;
-	
-	unsigned long avpn = vpn >> 11;
-	unsigned long arpn = physRpn_to_absRpn( prpn );
-
-	unsigned long lpar_rc;
-	unsigned long flags;
-	HPTE ret_hpte;
-
-	/* Fill in the local HPTE with absolute rpn, avpn and flags */
-	lhpte.dw1.d        = 0;
-	lhpte.dw1.h.rpn    = arpn;
-	lhpte.dw1.f.flags  = hpteflags;
-
-	lhpte.dw0.d        = 0;
-	lhpte.dw0.h.avpn   = avpn;
-	lhpte.dw0.h.h      = hash;
-	lhpte.dw0.h.bolted = bolted;
-	lhpte.dw0.h.v      = 1;
-
-	/* Now fill in the actual HPTE */
-	/* Set CEC cookie to 0                  */
-	/* Large page = 0                       */
-	/* Zero page = 0                        */
-	/* I-cache Invalidate = 0               */
-	/* I-cache synchronize = 0              */
-	/* Exact = 1 - only modify exact entry  */
-	flags = H_EXACT;
-
-	if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
-		lhpte.dw1.f.flags &= ~_PAGE_COHERENT;
-#if 1
-	__asm__ __volatile__ (
-		 H_ENTER_r3
-		 "mr	4, %1\n"
-		 "mr	5, %2\n"
-		 "mr	6, %3\n"
-		 "mr	7, %4\n"
-		 HSC
-		 "mr	%0, 3\n"
-		 : "=r" (lpar_rc)
-		 : "r" (flags), "r" (slot), "r" (lhpte.dw0.d), "r" (lhpte.dw1.d)
-		 : "r3", "r4", "r5", "r6", "r7", "cc");
-#else
-	lpar_rc =  plpar_pte_enter(flags,
-				   slot,
-				   lhpte.dw0.d,
-				   lhpte.dw1.d,
-				   &ret_hpte.dw0.dword0,
-				   &ret_hpte.dw1.dword1);
-#endif
-	if (lpar_rc != H_Success) {
-		udbg_printf("error on pte enter lapar rc = %ld\n",lpar_rc);
-		udbg_printf("ent: s=%lx, dw0=%lx, dw1=%lx\n", slot, lhpte.dw0.d, lhpte.dw1.d);
-		/* xmon_backtrace("backtrace"); */
-		for (;;);
-	}
-}
-
-static long hpte_find_pSeriesLP(unsigned long vpn)
-{
-	union {
-		unsigned long d;
-		Hpte_dword0   h;
-	} hpte_dw0;
-	long slot;
-	unsigned long hash;
-	unsigned long i,j;
-
-	hash = hpt_hash(vpn, 0);
-	for ( j=0; j<2; ++j ) {
-		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
-		for ( i=0; i<HPTES_PER_GROUP; ++i ) {
-			hpte_dw0.d = hpte_getword0_pSeriesLP( slot );
-			if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) &&
-			     ( hpte_dw0.h.v ) &&
-			     ( hpte_dw0.h.h == j ) ) {
-				/* HPTE matches */
-				if ( j )
-					slot = -slot;
-				return slot;
-			}
-			++slot;
-		}
-		hash = ~hash;
-	}
-	return -1;
-} 
-
-/*
- * Create a pte - LPAR .  Used during initialization only.
- * We assume the PTE will fit in the primary PTEG.
- */
-void make_pte_LPAR(HPTE *htab,
-		   unsigned long va, unsigned long pa, int mode,
-		   unsigned long hash_mask, int large)
-{
-	HPTE  local_hpte, ret_hpte;
-	unsigned long hash, slot, flags,lpar_rc, vpn;
-
-	if (large)
-		vpn = va >> 24;
-	else
-		vpn = va >> 12;
-
-	hash = hpt_hash(vpn, large);
-
-	slot = ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	local_hpte.dw1.dword1 = pa | mode;
-	local_hpte.dw0.dword0 = 0;
-	local_hpte.dw0.dw0.avpn = va >> 23;
-	local_hpte.dw0.dw0.bolted = 1;				/* bolted */
-	local_hpte.dw0.dw0.v = 1;
-
-	/* Set CEC cookie to 0                   */
-	/* Large page = 0                        */
-	/* Zero page = 0                         */
-	/* I-cache Invalidate = 0                */
-	/* I-cache synchronize = 0               */
-	/* Exact = 0 - modify any entry in group */
-	flags = 0;
-#if 1
-	__asm__ __volatile__ (
-		 H_ENTER_r3
-		 "mr	4, %1\n"
-		 "mr	5, %2\n"
-		 "mr	6, %3\n"
-		 "mr	7, %4\n"
-		 HSC
-		 "mr	%0, 3\n"
-		 : "=r" (lpar_rc)
-		 : "r" (flags), "r" (slot), "r" (local_hpte.dw0.dword0), "r" (local_hpte.dw1.dword1)
-		 : "r3", "r4", "r5", "r6", "r7", "cc");
-#else
-	lpar_rc =  plpar_pte_enter(flags,
-				   slot,
-				   local_hpte.dw0.dword0,
-				   local_hpte.dw1.dword1,
-				   &ret_hpte.dw0.dword0,
-				   &ret_hpte.dw1.dword1);
-#endif
-#if 0 /* NOTE: we explicitly do not check return status here because it is
-       * "normal" for early boot code to map io regions for which a partition
-       * has no access.  However, we will die if we actually fault on these
-       * "permission denied" pages.
-       */
-	if (lpar_rc != H_Success) {
-		/* pSeriesLP_init_early(); */
-		udbg_printf("flags=%lx, slot=%lx, dword0=%lx, dword1=%lx, rc=%d\n", flags, slot, local_hpte.dw0.dword0,local_hpte.dw1.dword1, lpar_rc);
-		BUG();
-	}
-#endif
-}
-
 static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, 
 				unsigned long uaddr, int direction )
 {
@@ -785,19 +436,14 @@
 	}
 }
 
+void pSeries_lpar_mm_init(void);
 
 /* This is called early in setup.c.
  * Use it to setup page table ppc_md stuff as well as udbg.
  */
 void pSeriesLP_init_early(void)
 {
-	ppc_md.hpte_invalidate   = hpte_invalidate_pSeriesLP;
-	ppc_md.hpte_updatepp     = hpte_updatepp_pSeriesLP;
-	ppc_md.hpte_updateboltedpp  = hpte_updateboltedpp_pSeriesLP;
-	ppc_md.hpte_getword0     = hpte_getword0_pSeriesLP;
-	ppc_md.hpte_selectslot   = hpte_selectslot_pSeriesLP;
-	ppc_md.hpte_create_valid = hpte_create_valid_pSeriesLP;
-	ppc_md.hpte_find	 = hpte_find_pSeriesLP;
+	pSeries_lpar_mm_init();
 
 	ppc_md.tce_build	 = tce_build_pSeriesLP;
 	ppc_md.tce_free		 = tce_free_pSeriesLP;
@@ -891,3 +537,318 @@
 	}
 	return 0;
 }
+
+
+
+
+
+
+/*
+ * Create a pte - LPAR .  Used during initialization only.
+ * We assume the PTE will fit in the primary PTEG.
+ */
+void pSeries_lpar_make_pte(HPTE *htab, unsigned long va, unsigned long pa,
+			   int mode, unsigned long hash_mask, int large)
+{
+	HPTE local_hpte;
+	unsigned long hash, slot, flags, lpar_rc, vpn;
+	unsigned long dummy1, dummy2;
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	hash = hpt_hash(vpn, large);
+
+	slot = ((hash & hash_mask)*HPTES_PER_GROUP);
+
+	local_hpte.dw1.dword1 = pa | mode;
+	local_hpte.dw0.dword0 = 0;
+	local_hpte.dw0.dw0.avpn = va >> 23;
+	local_hpte.dw0.dw0.bolted = 1;		/* bolted */
+	if (large) {
+		local_hpte.dw0.dw0.l = 1;	/* large page */
+		local_hpte.dw0.dw0.avpn &= ~0x1UL;
+	}
+	local_hpte.dw0.dw0.v = 1;
+
+	/* Set CEC cookie to 0                   */
+	/* Zero page = 0                         */
+	/* I-cache Invalidate = 0                */
+	/* I-cache synchronize = 0               */
+	/* Exact = 0 - modify any entry in group */
+	flags = 0;
+
+	lpar_rc =  plpar_pte_enter(flags, slot, local_hpte.dw0.dword0,
+				   local_hpte.dw1.dword1, &dummy1, &dummy2);
+
+	if (lpar_rc == H_PTEG_Full) {
+		while(1)
+			;
+	}
+
+	/*
+	 * NOTE: we explicitly do not check return status here because it is
+	 * "normal" for early boot code to map io regions for which a partition
+	 * has no access.  However, we will die if we actually fault on these
+	 * "permission denied" pages.
+	 */
+}
+
+static long pSeries_lpar_insert_hpte(unsigned long hpte_group,
+				     unsigned long vpn, unsigned long prpn,
+				     int secondary, unsigned long hpteflags,
+				     int bolted, int large)
+{
+	unsigned long avpn = vpn >> 11;
+	unsigned long arpn = physRpn_to_absRpn(prpn);
+	unsigned long lpar_rc;
+	unsigned long flags;
+	unsigned long slot;
+	HPTE lhpte;
+
+	/* Fill in the local HPTE with absolute rpn, avpn and flags */
+	lhpte.dw1.dword1      = 0;
+	lhpte.dw1.dw1.rpn     = arpn;
+	lhpte.dw1.flags.flags = hpteflags;
+
+	lhpte.dw0.dword0      = 0;
+	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.h       = secondary;
+	lhpte.dw0.dw0.bolted  = bolted;
+	lhpte.dw0.dw0.v       = 1;
+
+	if (large)
+		lhpte.dw0.dw0.l = 1;
+
+	/* Now fill in the actual HPTE */
+	/* Set CEC cookie to 0         */
+	/* Large page = 0              */
+	/* Zero page = 0               */
+	/* I-cache Invalidate = 0      */
+	/* I-cache synchronize = 0     */
+	/* Exact = 0                   */
+	flags = 0;
+
+	/* XXX why is this here? - Anton */
+	if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
+		lhpte.dw1.flags.flags &= ~_PAGE_COHERENT;
+
+	__asm__ __volatile__ (
+		H_ENTER_r3
+		"mr    4, %2\n"
+                "mr    5, %3\n"
+                "mr    6, %4\n"
+                "mr    7, %5\n"
+                HSC    
+                "mr    %0, 3\n"
+                "mr    %1, 4\n"
+		: "=r" (lpar_rc), "=r" (slot)
+		: "r" (flags), "r" (hpte_group), "r" (lhpte.dw0.dword0),
+		"r" (lhpte.dw1.dword1)
+		: "r3", "r4", "r5", "r6", "r7", "cc");
+
+	if (lpar_rc == H_PTEG_Full)
+		return -1;
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from pte enter rc = %lx\n", lpar_rc);
+
+	return slot;
+}
+
+static spinlock_t pSeries_lpar_tlbie_lock = SPIN_LOCK_UNLOCKED;
+
+static long pSeries_lpar_remove_hpte(unsigned long hpte_group)
+{
+	unsigned long slot_offset;
+	unsigned long lpar_rc;
+	int i;
+	unsigned long dummy1, dummy2;
+
+	/* pick a random slot to start at */
+	slot_offset = mftb() & 0x7;
+
+	for (i = 0; i < HPTES_PER_GROUP; i++) {
+
+		/* dont remove a bolted entry */
+		lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset,
+					   (0x1UL << 4), &dummy1, &dummy2);
+
+		if (lpar_rc == H_Success)
+			return i;
+
+		if (lpar_rc != H_Not_Found)
+			panic("Bad return code from pte remove rc = %lx\n",
+			      lpar_rc);
+
+		slot_offset++;
+		slot_offset &= 0x7;
+	}
+
+	return -1;
+}
+
+/*
+ * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
+ * the low 3 bits of flags happen to line up.  So no transform is needed.
+ * We can probably optimize here and assume the high bits of newpp are
+ * already zero.  For now I am paranoid.
+ */
+static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp,
+				       unsigned long va, int large)
+{
+	unsigned long lpar_rc;
+	unsigned long flags;
+	flags = (newpp & 3) | H_AVPN;
+	unsigned long vpn = va >> PAGE_SHIFT;
+
+	udbg_printf("updatepp\n");
+
+	lpar_rc = plpar_pte_protect(flags, slot, (vpn >> 4) & ~0x7fUL);
+
+	if (lpar_rc == H_Not_Found) {
+		udbg_printf("updatepp missed\n");
+		return -1;
+	}
+
+	if (lpar_rc != H_Success)
+		panic("bad return code from pte protect rc = %lx\n", lpar_rc);
+
+	return 0;
+}
+
+static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot)
+{
+	unsigned long dword0;
+	unsigned long lpar_rc;
+	unsigned long dummy_word1;
+	unsigned long flags;
+
+	/* Read 1 pte at a time                        */
+	/* Do not need RPN to logical page translation */
+	/* No cross CEC PFT access                     */
+	flags = 0;
+	
+	lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1);
+
+	if (lpar_rc != H_Success)
+		panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc);
+
+	return dword0;
+}
+
+static long pSeries_lpar_hpte_find(unsigned long vpn)
+{
+	unsigned long hash;
+	unsigned long i, j;
+	long slot;
+	union {
+		unsigned long dword0;
+		Hpte_dword0 dw0;
+	} hpte_dw0;
+	Hpte_dword0 dw0;
+
+	hash = hpt_hash(vpn, 0);
+
+	for (j = 0; j < 2; j++) {
+		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+		for (i = 0; i < HPTES_PER_GROUP; i++) {
+			hpte_dw0.dword0 = pSeries_lpar_hpte_getword0(slot);
+			dw0 = hpte_dw0.dw0;
+
+			if ((dw0.avpn == (vpn >> 11)) && dw0.v &&
+			    (dw0.h == j)) {
+				/* HPTE matches */
+				if (j)
+					slot = -slot;
+				return slot;
+			}
+			++slot;
+		}
+		hash = ~hash;
+	}
+
+	return -1;
+} 
+
+static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
+					     unsigned long ea)
+{
+	unsigned long lpar_rc;
+	unsigned long vsid, va, vpn, flags;
+	long slot;
+
+	vsid = get_kernel_vsid(ea);
+	va = (vsid << 28) | (ea & 0x0fffffff);
+	vpn = va >> PAGE_SHIFT;
+
+	slot = pSeries_lpar_hpte_find(vpn);
+	if (slot == -1)
+		panic("updateboltedpp: Could not find page to bolt\n");
+
+	flags = newpp & 3;
+	lpar_rc = plpar_pte_protect(flags, slot, 0);
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from pte bolted protect rc = %lx\n",
+		      lpar_rc); 
+}
+
+static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
+					 int large, int local)
+{
+	unsigned long vpn, avpn;
+	unsigned long lpar_rc;
+	unsigned long dummy1, dummy2;
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
+
+	avpn = vpn >> 11;
+
+	lpar_rc = plpar_pte_remove(H_AVPN, slot, (vpn >> 4) & ~0x7fUL, &dummy1,
+				   &dummy2);
+
+	if (lpar_rc == H_Not_Found) {
+		udbg_printf("invalidate missed\n");
+		return;
+	}
+
+	if (lpar_rc != H_Success)
+		panic("Bad return code from invalidate rc = %lx\n", lpar_rc);
+}
+
+/*
+ * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
+ * lock.
+ */
+void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number,
+				   int local)
+{
+	int i;
+	struct tlb_batch_data *ptes =
+		&tlb_batch_array[smp_processor_id()][0];
+	unsigned long flags;
+
+	spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
+	for (i = 0; i < number; i++) {
+		flush_hash_page(context, ptes->addr, ptes->pte, local);
+		ptes++;
+	}
+	spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
+}
+
+void pSeries_lpar_mm_init(void)
+{
+	ppc_md.hpte_invalidate  = pSeries_lpar_hpte_invalidate;
+	ppc_md.hpte_updatepp    = pSeries_lpar_hpte_updatepp;
+	ppc_md.hpte_updateboltedpp = pSeries_lpar_hpte_updateboltedpp;
+	ppc_md.insert_hpte      = pSeries_lpar_insert_hpte;
+	ppc_md.remove_hpte      = pSeries_lpar_remove_hpte;
+	ppc_md.make_pte         = pSeries_lpar_make_pte;
+	ppc_md.flush_hash_range	= pSeries_lpar_flush_hash_range;
+}
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pSeries_pci.c linux-2.5.8-pre3/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/pSeries_pci.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pSeries_pci.c	Tue Apr  9 18:35:19 2002
@@ -757,34 +757,6 @@
 	return NULL;
 }
 
-/***********************************************************************
- * find_floppy(void) 
- *	
- * Finds the default floppy device, if the system has one, and returns 
- * the pci_dev for the isa bridge for the floppy device.  
- *
- * Note: This functions finds the first "fdc" device and then looks to 
- * the parent device which should be the isa bridge device.  If there 
- * is more than one floppy on the system, it will find the first one 
- * and maybe that is okay. 
- ***********************************************************************/
-struct pci_dev*
-find_floppy(void)
-{
-	struct device_node *floppy_dn;
-	struct pci_dev *floppy_dev = NULL;
-	int *reg; 
-
-	floppy_dn = find_type_devices("fdc");
-	if (floppy_dn && floppy_dn->parent) {
-		if ((reg = (unsigned int *)get_property(floppy_dn->parent,"reg", 0)) != NULL)
-			floppy_dev  = pci_find_slot((reg[0] & 0x00ff0000) >> 16, (reg[0] & 0x0000ff00) >> 8);
-	}
-	PPCDBG(PPCDBG_BUSWALK,"\tFloppy pci_dev\n");
-	PPCDBGCALL(PPCDBG_BUSWALK, dumpPci_Dev(floppy_dev) );
-	return floppy_dev;
-}
-
 /*********************************************************************** 
  * ppc64_pcibios_init
  *  
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pacaData.c linux-2.5.8-pre3/arch/ppc64/kernel/pacaData.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/pacaData.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pacaData.c	Tue Apr  9 18:35:19 2002
@@ -42,9 +42,9 @@
                 next_round_robin: 1     /* Round robin index */             \
         },                                                                  \
         lpQueuePtr: (lpq),              /* &xItLpQueue,                  */ \
-        xRtas: {                                                            \
+        /* xRtas: {                                                            \
                 lock: SPIN_LOCK_UNLOCKED                                    \
-        },                                                                  \
+        }, */                                                                  \
         xProcStart: (start),            /* Processor start */               \
         xLpPaca: {                                                          \
                 xDesc: 0xd397d781,      /* "LpPa"          */               \
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pci.c linux-2.5.8-pre3/arch/ppc64/kernel/pci.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/pci.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pci.c	Tue Apr  9 18:35:19 2002
@@ -58,7 +58,6 @@
 static void fixup_windbond_82c105(struct pci_dev* dev);
 void        fixup_resources(struct pci_dev* dev);
 
-struct pci_dev *find_floppy(void);
 void   iSeries_pcibios_init(void);
 void   pSeries_pcibios_init(void);
 
@@ -94,8 +93,8 @@
 
 static int pci_bus_count;
 
-/* Floppy dev for ppc64_fd_dma_setup().  May be null if no floppy in the system. */
-struct pci_dev *ppc64_floppy_dev = NULL;
+/* Cached ISA bridge dev. */
+struct pci_dev *ppc64_isabridge_dev = NULL;
 
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_TRIDENT,	PCI_ANY_ID, fixup_broken_pcnet32 },
@@ -492,7 +491,10 @@
 	create_tce_tables();
 	PPCDBG(PPCDBG_BUSWALK,"pSeries create_tce_tables()\n");
 #endif
-	ppc64_floppy_dev = find_floppy();
+
+	/* Cache the location of the ISA bridge (if we have one) */
+	if (ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL))
+		printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name);
 
 	printk("PCI: Probing PCI hardware done\n");
 	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware done.\n");
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pci.h linux-2.5.8-pre3/arch/ppc64/kernel/pci.h
--- linux-2.5.8-pre2/arch/ppc64/kernel/pci.h	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pci.h	Tue Apr  9 18:35:19 2002
@@ -46,7 +46,7 @@
 extern int    device_Location(struct pci_dev*,char*);
 extern int    format_device_location(struct pci_dev*,char*, int );
 
-extern struct pci_dev *ppc64_floppy_dev;
+extern struct pci_dev *ppc64_isabridge_dev;	/* may be NULL if no ISA bus */
 
 /*******************************************************************
  * PCI device_node operations
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pci_dma.c linux-2.5.8-pre3/arch/ppc64/kernel/pci_dma.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/pci_dma.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pci_dma.c	Tue Apr  9 18:35:19 2002
@@ -131,8 +131,12 @@
 	return 0;
 }
 
-static inline struct TceTable *get_tce_table(struct pci_dev *dev) {
-
+static inline struct TceTable *get_tce_table(struct pci_dev *dev)
+{
+	if (!dev)
+		dev = ppc64_isabridge_dev;
+	if (!dev)
+		return NULL;
 	if ( ( _machine == _MACH_iSeries ) && ( dev->bus ) ) 
 		return tceTables[dev->bus->number];
 	/* On the iSeries, the virtual bus will take this path.  There is a */
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/pmac_nvram.c linux-2.5.8-pre3/arch/ppc64/kernel/pmac_nvram.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/pmac_nvram.c	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/pmac_nvram.c	Wed Dec 31 16:00:00 1969
@@ -1,358 +0,0 @@
-/*
- *  c 2001 PPC 64 Team, IBM Corp
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- *
- * Miscellaneous procedures for dealing with the PowerMac hardware.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/nvram.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <asm/init.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-#undef DEBUG
-
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static char* nvram_image;
-static int core99_bank = 0;
-sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
-
-#define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
- 
-#define CORE99_SIGNATURE	0x5a
-#define CORE99_ADLER_START	0x14
-
-/* Core99 nvram is a flash */
-#define CORE99_FLASH_STATUS_DONE	0x80
-#define CORE99_FLASH_STATUS_ERR		0x38
-#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
-#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
-#define CORE99_FLASH_CMD_RESET		0xff
-#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
-
-/* CHRP NVRAM header */
-struct chrp_header {
-	u8		signature;
-	u8		cksum;
-	u16		len;
-	char		name[12];
-	u8		data[0];
-};
-
-struct core99_header {
-	struct chrp_header	hdr;
-	u32			adler;
-	u32			generation;
-	u32			reserved[2];
-};
-
-static int nvram_partitions[3];
-
-static u8
-chrp_checksum(struct chrp_header* hdr)
-{
-	u8 *ptr;
-	u16 sum = hdr->signature;
-	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
-		sum += *ptr;
-	while (sum > 0xFF)
-		sum = (sum & 0xFF) + (sum>>8);
-	return sum;
-}
-
-static u32
-core99_calc_adler(u8 *buffer)
-{
-	int cnt;
-	u32 low, high;
-
-   	buffer += CORE99_ADLER_START;
-	low = 1;
-	high = 0;
-	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
-		if ((cnt % 5000) == 0) {
-			high  %= 65521UL;
-			high %= 65521UL;
-		}
-		low += buffer[cnt];
-		high += low;
-	}
-	low  %= 65521UL;
-	high %= 65521UL;
-  
-	return (high << 16) | low;
-}
-
-static u32
-core99_check(u8* datas)
-{
-	struct core99_header* hdr99 = (struct core99_header*)datas;
-
-	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
-#ifdef DEBUG
-		printk("Invalid signature\n");
-#endif		
-		return 0;
-	}
-	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
-#ifdef DEBUG
-		printk("Invalid checksum\n");
-#endif
-		return 0;
-	}
-	if (hdr99->adler != core99_calc_adler(datas)) {
-#ifdef DEBUG
-		printk("Invalid adler\n");
-#endif
-		return 0;
-	}
-	return hdr99->generation;
-}
-
-static int
-core99_erase_bank(int bank)
-{
-	int stat, i;
-	
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-	
-	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
-	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
-	do { stat = in_8(base); }
-	while(!(stat & CORE99_FLASH_STATUS_DONE));
-	out_8(base, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on erase !\n", stat);
-		return -ENXIO;
-	}
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != 0xff) {
-			printk("nvram: flash erase failed !\n");
-			return -ENXIO;
-		}
-	return 0;
-}
-
-static int
-core99_write_bank(int bank, u8* datas)
-{
-	int i, stat = 0;
-	
-	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-	
-	for (i=0; i<NVRAM_SIZE; i++) {
-		out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
-		out_8(base+i, datas[i]);
-		do { stat = in_8(base); }
-		while(!(stat & CORE99_FLASH_STATUS_DONE));
-		if (stat & CORE99_FLASH_STATUS_ERR)
-			break;
-	}
-	out_8(base, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on write !\n", stat);
-		return -ENXIO;
-	}
-	for (i=0; i<NVRAM_SIZE; i++)
-		if (base[i] != datas[i]) {
-			printk("nvram: flash write failed !\n");
-			return -ENXIO;
-		}
-	return 0;	
-}
-
-
-__init
-void pmac_nvram_init(void)
-{
-	struct device_node *dp;
-
-	nvram_naddrs = 0;
-
-	dp = find_devices("nvram");
-	if (dp == NULL) {
-		printk(KERN_ERR "Can't find NVRAM device\n");
-		return;
-	}
-	nvram_naddrs = dp->n_addrs;
-	is_core_99 = device_is_compatible(dp, "nvram,flash");
-	if (is_core_99) {
-		int i;
-		u32 gen_bank0, gen_bank1;
-		
-		if (nvram_naddrs < 1) {
-			printk(KERN_ERR "nvram: no address\n");
-			return;
-		}
-		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
-		if (!nvram_image) {
-			printk(KERN_ERR "nvram: can't allocate image\n");
-			return;
-		}
-		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
-#ifdef DEBUG
-		printk("nvram: Checking bank 0...\n");
-#endif
-		gen_bank0 = core99_check((u8 *)nvram_data);
-		gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
-		core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
-#ifdef DEBUG
-		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
-		printk("nvram: Active bank is: %d\n", core99_bank);
-#endif
-		for (i=0; i<NVRAM_SIZE; i++)
-			nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
-	} else if (_machine == _MACH_pSeries && nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_mult = 1;
-	} else if (nvram_naddrs == 1) {
-		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
-	} else if (nvram_naddrs == 2) {
-		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
-		nvram_naddrs = -1;
-	} else {
-		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
-		       nvram_naddrs);
-	}
-}
-
-void
-pmac_nvram_update(void)
-{
-	struct core99_header* hdr99;
-	
-	if (!is_core_99 || !nvram_data || !nvram_image)
-		return;
-	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
-		NVRAM_SIZE))
-		return;
-#ifdef DEBUG
-	printk("Updating nvram...\n");
-#endif
-	hdr99 = (struct core99_header*)nvram_image;
-	hdr99->generation++;
-	hdr99->hdr.signature = CORE99_SIGNATURE;
-	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
-	hdr99->adler = core99_calc_adler(nvram_image);
-	core99_bank = core99_bank ? 0 : 1;
-	if (core99_erase_bank(core99_bank)) {
-		printk("nvram: Error erasing bank %d\n", core99_bank);
-		return;
-	}
-	if (core99_write_bank(core99_bank, nvram_image))
-		printk("nvram: Error writing bank %d\n", core99_bank);
-}
-
-__openfirmware
-unsigned char nvram_read_byte(int addr)
-{
-	#ifdef CONFIG_ADB_PMU  // -aglitke
-	  struct adb_request req;
-	#endif
-
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1:
-		if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		return req.reply[1];
-#endif
-	case 1:
-		if (is_core_99)
-			return nvram_image[addr];
-		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		return nvram_data[(addr & 0x1f) << 4];
-	}
-	return 0;
-}
-
-__openfirmware
-void nvram_write_byte(unsigned char val, int addr)
-{
-	#ifdef CONFIG_ADB_PMU  // -aglitke
-	   struct adb_request req;
-	#endif
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1:
-		if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff, val))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		break;
-#endif
-	case 1:
-		if (is_core_99) {
-			nvram_image[addr] = val;
-			break;
-		}
-		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
-		break;
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		nvram_data[(addr & 0x1f) << 4] = val;
-		break;
-	}
-	eieio();
-}
-
-int
-pmac_get_partition(int partition)
-{
-	return nvram_partitions[partition];
-}
-
-u8
-pmac_xpram_read(int xpaddr)
-{
-	int offset = nvram_partitions[pmac_nvram_XPRAM];
-	
-	if (offset < 0)
-		return 0;
-		
-	return nvram_read_byte(xpaddr + offset);
-}
-
-void
-pmac_xpram_write(int xpaddr, u8 data)
-{
-	int offset = nvram_partitions[pmac_nvram_XPRAM];
-	
-	if (offset < 0)
-		return;
-		
-	nvram_write_byte(xpaddr + offset, data);
-}
-
-
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/ppc_ksyms.c linux-2.5.8-pre3/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/ppc_ksyms.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/ppc_ksyms.c	Tue Apr  9 18:35:19 2002
@@ -34,9 +34,6 @@
 #include <asm/bitops.h>
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
@@ -45,9 +42,8 @@
 #include <asm/machdep.h>
 #include <asm/hw_irq.h>
 #include <asm/abs_addr.h>
-#ifdef CONFIG_SMP
 #include <asm/smplock.h>
-#endif /* CONFIG_SMP */
+#include <asm/cacheflush.h>
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iSeries/iSeries_pci.h>
 #include <asm/iSeries/iSeries_proc.h>
@@ -109,7 +105,6 @@
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strnlen);
@@ -238,9 +233,6 @@
 EXPORT_SYMBOL(find_all_nodes);
 EXPORT_SYMBOL(get_property);
 
-#ifndef CONFIG_PPC_ISERIES
-EXPORT_SYMBOL_NOVERS(sys_ctrler); /* tibit */
-#endif
 #ifdef CONFIG_NVRAM
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/process.c linux-2.5.8-pre3/arch/ppc64/kernel/process.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/process.c	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/process.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/process.c
+ *  linux/arch/ppc64/kernel/process.c
  *
  *  Derived from "arch/i386/kernel/process.c"
  *    Copyright (C) 1995  Linus Torvalds
@@ -45,19 +45,18 @@
 #include <asm/iSeries/HvCallHpt.h>
 #include <asm/Naca.h>
 
+#include "ppc_defs.h"
+
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
-extern unsigned long _get_SP(void);
 
 struct task_struct *last_task_used_math = NULL;
 
 struct mm_struct ioremap_mm = { pgd             : ioremap_dir  
                                ,page_table_lock : SPIN_LOCK_UNLOCKED };
 
-char *sysmap = NULL; 
+char *sysmap = NULL;
 unsigned long sysmap_size = 0;
 
-extern char __toc_start;
-
 void
 enable_kernel_fp(void)
 {
@@ -84,10 +83,7 @@
 _switch_to(struct task_struct *prev, struct task_struct *new)
 {
 	struct thread_struct *new_thread, *old_thread;
-	unsigned long s;
-	
-	__save_flags(s);
-	__cli();
+	unsigned long flags;
 
 #ifdef CONFIG_SMP
 	/* avoid complexity of lazy save/restore of fpu
@@ -99,14 +95,16 @@
 	 * every switch, just a save.
 	 *  -- Cort
 	 */
-	if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) )
+	if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP))
 		giveup_fpu(prev);
 #endif /* CONFIG_SMP */
 
 	new_thread = &new->thread;
 	old_thread = &current->thread;
+
+	__save_and_cli(flags);
 	_switch(old_thread, new_thread);
-	__restore_flags(s);
+	__restore_flags(flags);
 }
 
 void show_regs(struct pt_regs * regs)
@@ -172,45 +170,50 @@
 int
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	    unsigned long unused,
-	    struct task_struct * p, struct pt_regs * regs)
+	    struct task_struct *p, struct pt_regs *regs)
 {
-	unsigned long msr;
 	struct pt_regs *childregs, *kregs;
 	extern void ret_from_fork(void);
-
-	/* XXX get rid of the -2 Anton */
+	unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE;
 
 	/* Copy registers */
-	childregs = ((struct pt_regs *)
-		     ((unsigned long)p->thread_info + THREAD_SIZE 
-		      - STACK_FRAME_OVERHEAD)) - 2;
+	sp -= sizeof(struct pt_regs);
+	childregs = (struct pt_regs *) sp;
 	*childregs = *regs;
+	if ((childregs->msr & MSR_PR) == 0) {
+		/* for kernel thread, set `current' and stackptr in new task */
+		childregs->gpr[1] = sp + sizeof(struct pt_regs);
+		childregs->gpr[13] = (unsigned long) p;
+		p->thread.regs = NULL;	/* no user register state */
+		clear_ti_thread_flag(p->thread_info, TIF_32BIT);
+#ifdef CONFIG_PPC_ISERIES
+		set_ti_thread_flag(p->thread_info, TIF_RUN_LIGHT);
+#endif
+	} else
+		p->thread.regs = childregs;
 	childregs->gpr[3] = 0;  /* Result from fork() */
-	p->thread.regs = childregs;
-	p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
-	p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
-	kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD);
-	/* The PPC64 compiler makes use of a TOC to contain function 
+	sp -= STACK_FRAME_OVERHEAD;
+
+	/*
+	 * The way this works is that at some point in the future
+	 * some task will call _switch to switch to the new task.
+	 * That will pop off the stack frame created below and start
+	 * the new task running at ret_from_fork.  The new task will
+	 * do some house keeping and then return from the fork or clone
+	 * system call, using the stack frame created above.
+	 */
+	sp -= sizeof(struct pt_regs);
+	kregs = (struct pt_regs *) sp;
+	sp -= STACK_FRAME_OVERHEAD;
+	p->thread.ksp = sp;
+
+	/*
+	 * The PPC64 ABI makes use of a TOC to contain function 
 	 * pointers.  The function (ret_from_except) is actually a pointer
 	 * to the TOC entry.  The first entry is a pointer to the actual
 	 * function.
  	 */
 	kregs->nip = *((unsigned long *)ret_from_fork);
-	asm volatile("mfmsr %0" : "=r" (msr):);
-	kregs->msr = msr;
-	kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
-	kregs->gpr[2] = (((unsigned long)&__toc_start) + 0x8000);
-
-	if (usp >= (unsigned long) regs) {
-		/* Stack is in kernel space - must adjust */
-		childregs->gpr[1] = (unsigned long)(childregs + 1);
-		*((unsigned long *) childregs->gpr[1]) = 0;
-		childregs->gpr[13] = (unsigned long) p;
-	} else {
-		/* Provided stack is in user space */
-		childregs->gpr[1] = usp;
-	}
-	p->thread.last_syscall = -1;
 
 	/*
 	 * copy fpu info - assume lazy fpu switch now always
@@ -223,6 +226,8 @@
 	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
 	p->thread.fpscr = current->thread.fpscr;
 
+	p->thread.last_syscall = -1;
+
 	return 0;
 }
 
@@ -239,7 +244,6 @@
 	unsigned long *entry = (unsigned long *)nip;
 	unsigned long *toc   = entry + 1;
 
-
 	set_fs(USER_DS);
 	memset(regs->gpr, 0, sizeof(regs->gpr));
 	memset(&regs->ctr, 0, 4 * sizeof(regs->ctr));
@@ -252,53 +256,27 @@
 	current->thread.fpscr = 0;
 }
 
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
-			 struct pt_regs *regs)
+int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+	      struct pt_regs *regs)
 {
-	unsigned long clone_flags = p1;
-	int res;
-
-	res = do_fork(clone_flags, regs->gpr[1], regs, 0);
-#ifdef CONFIG_SMP
-	/* When we clone the idle task we keep the same pid but
-	 * the return value of 0 for both causes problems.
-	 * -- Cort
-	 */
-	if ((current->pid == 0) && (current == &init_task))
-		res = 1;
-#endif /* CONFIG_SMP */
-
-	return res;
+	return do_fork(p1, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
-			struct pt_regs *regs)
+int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+	     struct pt_regs *regs)
 {
-	int res;
-	
-	res = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
-  
-#ifdef CONFIG_SMP
-	/* When we clone the idle task we keep the same pid but
-	 * the return value of 0 for both causes problems.
-	 * -- Cort
-	 */
-	if ((current->pid == 0) && (current == &init_task))
-		res = 1;
-#endif /* CONFIG_SMP */
-	
-	return res;
+	return do_fork(SIGCHLD, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
+int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
 			 struct pt_regs *regs)
 {
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
 }
 
-asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
-			  unsigned long a3, unsigned long a4, unsigned long a5,
-			  struct pt_regs *regs)
+int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+	       unsigned long a3, unsigned long a4, unsigned long a5,
+	       struct pt_regs *regs)
 {
 	int error;
 	char * filename;
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/prom.c linux-2.5.8-pre3/arch/ppc64/kernel/prom.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/prom.c	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/prom.c	Tue Apr  9 18:35:19 2002
@@ -204,7 +204,13 @@
 
 #ifdef CONFIG_MSCHUNKS
 static unsigned long prom_initialize_mschunks(unsigned long);
+#ifdef DEBUG_PROM
+void prom_dump_mschunks_mapping(void);
+#endif /* DEBUG_PROM */
 #endif /* CONFIG_MSCHUNKS */
+#ifdef DEBUG_PROM
+void prom_dump_lmb(void);
+#endif
 
 extern unsigned long reloc_offset(void);
 
@@ -536,10 +542,11 @@
         unsigned long i, offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
 	union lmb_reg_property reg;
-	unsigned long mem_size, lmb_base, lmb_size;
+	unsigned long lmb_base, lmb_size;
 	unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
 
 #ifdef CONFIG_MSCHUNKS
+	unsigned long max_addr = 0;
 #if 1
 	/* Fix me: 630 3G-4G IO hack here... -Peter (PPPBBB) */
 	unsigned long io_base = 3UL<<30;
@@ -550,7 +557,7 @@
 	unsigned long io_base = <real io base here>;
 	unsigned long io_size = <real io size here>;
 #endif
-#endif
+#endif /* CONFIG_MSCHUNKS */
 
 	lmb_init();
 
@@ -582,24 +589,32 @@
 			 	 */
 				have_630 = 0;
 			}
-#endif
+#endif /* CONFIG_MSCHUNKS */
 			if ( lmb_add(lmb_base, lmb_size) < 0 )
 				prom_print(RELOC("Too many LMB's, discarding this one...\n"));
-			else
-				mem_size =+ lmb_size;
+#ifdef CONFIG_MSCHUNKS
+			else if ( max_addr < (lmb_base+lmb_size-1) )
+				max_addr = lmb_base+lmb_size-1;
+#endif /* CONFIG_MSCHUNKS */
 		}
 
 	}
 
 #ifdef CONFIG_MSCHUNKS
-	if ( have_630 && lmb_addrs_overlap(0,mem_size,io_base,io_size) )
+	if ( have_630 && lmb_addrs_overlap(0,max_addr,io_base,io_size) )
 		lmb_add_io(io_base, io_size);
-#endif
+#endif /* CONFIG_MSCHUNKS */
 
 	lmb_analyze();
+#ifdef DEBUG_PROM
+	prom_dump_lmb();
+#endif /* DEBUG_PROM */
 
 #ifdef CONFIG_MSCHUNKS
 	mem = prom_initialize_mschunks(mem);
+#ifdef DEBUG_PROM
+	prom_dump_mschunks_mapping();
+#endif /* DEBUG_PROM */
 #endif /* CONFIG_MSCHUNKS */
 
 	return mem;
@@ -711,53 +726,152 @@
 	struct lmb *_lmb  = PTRRELOC(&lmb);
 	struct msChunks *_msChunks = PTRRELOC(&msChunks);
 	unsigned long i, pchunk = 0;
-	unsigned long mem_size = _lmb->memory.size;
+	unsigned long addr_range = _lmb->memory.size + _lmb->memory.iosize;
 	unsigned long chunk_size = _lmb->memory.lcd_size;
 
-#if 1
-	/* Fix me: 630 3G-4G IO hack here... -Peter (PPPBBB) */
-	unsigned long io_base = 3UL<<30;
-	unsigned long io_size = 1UL<<30;
 
+	mem = msChunks_alloc(mem, addr_range / chunk_size, chunk_size);
+
+	/* First create phys -> abs mapping for memory/dram */
 	for (i=0; i < _lmb->memory.cnt ;i++) {
 		unsigned long base = _lmb->memory.region[i].base;
 		unsigned long size = _lmb->memory.region[i].size;
-		if ( lmb_addrs_overlap(base,size,io_base,io_size) ) {
-			/* If we really have dram here, then we don't
-			 * have a 630! -Peter
-			 */
-			io_base = mem_size;
-			io_size = 1;
-			break;
-		}
-	}
-#else
-	unsigned long io_base = <real io base here>;
-	unsigned long io_size = <real io size here>;
-#endif
+		unsigned long achunk = addr_to_chunk(base);
+		unsigned long end_achunk = addr_to_chunk(base+size);
 
-	if ( lmb_addrs_overlap(0,mem_size,io_base,io_size) ) {
-		lmb_add(io_base, io_size);
-		lmb_reserve(io_base, io_size);
-	}
+		if(_lmb->memory.region[i].type != LMB_MEMORY_AREA)
+			continue;
 
-	mem = msChunks_alloc(mem, mem_size / chunk_size, chunk_size);
+		_lmb->memory.region[i].physbase = chunk_to_addr(pchunk);
+		for (; achunk < end_achunk ;) {
+			PTRRELOC(_msChunks->abs)[pchunk++] = achunk++;
+		}
+	}
 
+#ifdef CONFIG_MSCHUNKS
+	/* Now create phys -> abs mapping for IO */
 	for (i=0; i < _lmb->memory.cnt ;i++) {
 		unsigned long base = _lmb->memory.region[i].base;
 		unsigned long size = _lmb->memory.region[i].size;
 		unsigned long achunk = addr_to_chunk(base);
 		unsigned long end_achunk = addr_to_chunk(base+size);
+
+		if(_lmb->memory.region[i].type != LMB_IO_AREA)
+			continue;
+
 		_lmb->memory.region[i].physbase = chunk_to_addr(pchunk);
 		for (; achunk < end_achunk ;) {
 			PTRRELOC(_msChunks->abs)[pchunk++] = achunk++;
 		}
 	}
+#endif /* CONFIG_MSCHUNKS */
 
 	return mem;
 }
+
+#ifdef DEBUG_PROM
+void
+prom_dump_mschunks_mapping(void)
+{
+        unsigned long offset = reloc_offset();
+	struct msChunks *_msChunks = PTRRELOC(&msChunks);
+	unsigned long chunk;
+
+        prom_print(RELOC("\nprom_dump_mschunks_mapping:\n"));
+        prom_print(RELOC("    msChunks.num_chunks         = 0x"));
+        prom_print_hex(_msChunks->num_chunks);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.chunk_size         = 0x"));
+        prom_print_hex(_msChunks->chunk_size);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.chunk_shift        = 0x"));
+        prom_print_hex(_msChunks->chunk_shift);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.chunk_mask         = 0x"));
+        prom_print_hex(_msChunks->chunk_mask);
+	prom_print_nl();
+        prom_print(RELOC("    msChunks.abs                = 0x"));
+        prom_print_hex(_msChunks->abs);
+	prom_print_nl();
+
+        prom_print(RELOC("    msChunks mapping:\n"));
+	for(chunk=0; chunk < _msChunks->num_chunks ;chunk++) {
+        	prom_print(RELOC("        phys 0x"));
+        	prom_print_hex(chunk);
+        	prom_print(RELOC(" -> abs 0x"));
+        	prom_print_hex(PTRRELOC(_msChunks->abs)[chunk]);
+		prom_print_nl();
+	}
+
+}
+#endif /* DEBUG_PROM */
 #endif /* CONFIG_MSCHUNKS */
 
+#ifdef DEBUG_PROM
+void
+prom_dump_lmb(void)
+{
+        unsigned long i;
+        unsigned long offset = reloc_offset();
+	struct lmb *_lmb  = PTRRELOC(&lmb);
+
+        prom_print(RELOC("\nprom_dump_lmb:\n"));
+        prom_print(RELOC("    memory.cnt                  = 0x"));
+        prom_print_hex(_lmb->memory.cnt);
+	prom_print_nl();
+        prom_print(RELOC("    memory.size                 = 0x"));
+        prom_print_hex(_lmb->memory.size);
+	prom_print_nl();
+        prom_print(RELOC("    memory.lcd_size             = 0x"));
+        prom_print_hex(_lmb->memory.lcd_size);
+	prom_print_nl();
+        for (i=0; i < _lmb->memory.cnt ;i++) {
+                prom_print(RELOC("    memory.region[0x"));
+		prom_print_hex(i);
+		prom_print(RELOC("].base       = 0x"));
+                prom_print_hex(_lmb->memory.region[i].base);
+		prom_print_nl();
+                prom_print(RELOC("                      .physbase = 0x"));
+                prom_print_hex(_lmb->memory.region[i].physbase);
+		prom_print_nl();
+                prom_print(RELOC("                      .size     = 0x"));
+                prom_print_hex(_lmb->memory.region[i].size);
+		prom_print_nl();
+                prom_print(RELOC("                      .type     = 0x"));
+                prom_print_hex(_lmb->memory.region[i].type);
+		prom_print_nl();
+        }
+
+	prom_print_nl();
+        prom_print(RELOC("    reserved.cnt                  = 0x"));
+        prom_print_hex(_lmb->reserved.cnt);
+	prom_print_nl();
+        prom_print(RELOC("    reserved.size                 = 0x"));
+        prom_print_hex(_lmb->reserved.size);
+	prom_print_nl();
+        prom_print(RELOC("    reserved.lcd_size             = 0x"));
+        prom_print_hex(_lmb->reserved.lcd_size);
+	prom_print_nl();
+        for (i=0; i < _lmb->reserved.cnt ;i++) {
+                prom_print(RELOC("    reserved.region[0x"));
+		prom_print_hex(i);
+		prom_print(RELOC("].base       = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].base);
+		prom_print_nl();
+                prom_print(RELOC("                      .physbase = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].physbase);
+		prom_print_nl();
+                prom_print(RELOC("                      .size     = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].size);
+		prom_print_nl();
+                prom_print(RELOC("                      .type     = 0x"));
+                prom_print_hex(_lmb->reserved.region[i].type);
+		prom_print_nl();
+        }
+}
+#endif /* DEBUG_PROM */
+
+
 void
 prom_initialize_tce_table(void)
 {
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/rtasd.c linux-2.5.8-pre3/arch/ppc64/kernel/rtasd.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/rtasd.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/rtasd.c	Tue Apr  9 18:35:19 2002
@@ -224,7 +224,6 @@
 
 	cpu = 0;
 	set_cpus_allowed(current, 1UL << cpu_logical_map(cpu));
-	schedule();
 
 	while(1) {
 		do {
@@ -262,9 +261,7 @@
 
 
 		/* Check all cpus for pending events before sleeping*/
-		if (first_pass) {
-			schedule();
-		} else {
+		if (!first_pass) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout((HZ*60/rtas_event_scan_rate) / 2);
 		}
@@ -277,7 +274,7 @@
 	return -EINVAL;
 }
 
-static void __init rtas_init(void)
+static int __init rtas_init(void)
 {
 	struct proc_dir_entry *rtas_dir, *entry;
 
@@ -296,6 +293,8 @@
 		printk(KERN_ERR "Failed to start RTAS daemon\n");
 
 	printk(KERN_ERR "RTAS daemon started\n");
+
+	return 0;
 }
 
 static int __init surveillance_setup(char *str)
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/semaphore.c linux-2.5.8-pre3/arch/ppc64/kernel/semaphore.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/semaphore.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/semaphore.c	Tue Apr  9 18:35:19 2002
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
+#include <asm/errno.h>
 
 /*
  * Atomically update sem->count.
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/setup.c linux-2.5.8-pre3/arch/ppc64/kernel/setup.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/setup.c	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/setup.c	Tue Apr  9 18:35:19 2002
@@ -277,6 +277,9 @@
 	ppc_md.halt();
 }
 
+unsigned long ppc_proc_freq;
+unsigned long ppc_tb_freq;
+
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
 	unsigned long cpu_id = (unsigned long)v - 1;
@@ -286,10 +289,6 @@
 
 #ifdef CONFIG_SMP
 	if (cpu_id == NR_CPUS) {
-		unsigned long bogosum = smp_num_cpus * loops_per_jiffy;
-		seq_printf(m, "total bogomips\t: %lu.%02lu\n",
-			   bogosum/(500000/HZ),
-			   bogosum/(5000/HZ) % 100);
 
 		if (ppc_md.get_cpuinfo != NULL)
 			ppc_md.get_cpuinfo(m);
@@ -357,10 +356,6 @@
 
 	seq_printf(m, "revision\t: %hd.%hd\n", maj, min);
 	
-	seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
-		   loops_per_jiffy/(500000/HZ),
-		   loops_per_jiffy/(5000/HZ) % 100);
-
 	return 0;
 }
 
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/signal.c linux-2.5.8-pre3/arch/ppc64/kernel/signal.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/signal.c	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/signal.c	Tue Apr  9 18:35:19 2002
@@ -35,6 +35,7 @@
 #include <asm/pgtable.h>
 #include <asm/ppcdebug.h>
 #include <asm/unistd.h>
+#include <asm/cacheflush.h>
 
 #define DEBUG_SIG 0
 
@@ -676,8 +677,8 @@
 				info.si_signo = signr;
 				info.si_errno = 0;
 				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+				info.si_pid = current->parent->pid;
+				info.si_uid = current->parent->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
@@ -722,7 +723,7 @@
 			case SIGSTOP:
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+				if (!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/signal32.c linux-2.5.8-pre3/arch/ppc64/kernel/signal32.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/signal32.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/signal32.c	Tue Apr  9 18:35:19 2002
@@ -1375,8 +1375,8 @@
 				info.si_signo = signr;
 				info.si_errno = 0;
 				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+				info.si_pid = current->parent->pid;
+				info.si_uid = current->parent->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
@@ -1416,7 +1416,7 @@
 			case SIGSTOP:
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+				if (!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/smp.c linux-2.5.8-pre3/arch/ppc64/kernel/smp.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/smp.c	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/smp.c	Tue Apr  9 18:35:19 2002
@@ -86,7 +86,11 @@
 /*
  * XICS only has a single IPI, so encode the messages per CPU
  */
-volatile unsigned long xics_ipi_message[NR_CPUS] = {0};
+struct xics_ipi_struct {
+	        volatile unsigned long value;
+} ____cacheline_aligned;
+
+struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
 #define smp_message_pass(t,m,d,w) ppc_md.smp_message_pass((t),(m),(d),(w))
 
@@ -322,10 +326,10 @@
 		if (target == MSG_ALL || target == i
 		    || (target == MSG_ALL_BUT_SELF
 			&& i != smp_processor_id())) {
-			set_bit(msg, &xics_ipi_message[i]);
+			set_bit(msg, &xics_ipi_message[i].value);
 			mb();
 			xics_cause_IPI(i);
-			}
+		}
 	}
 }
 
@@ -360,37 +364,6 @@
 	}
 }
 
-static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
-static task_t *new_task;
-
-/*
- * This function sends a 'task migration' IPI to another CPU.
- * Must be called from syscall contexts, with interrupts *enabled*.
- */
-void smp_migrate_task(int cpu, task_t *p)
-{
-	/*
-	 * The target CPU will unlock the migration spinlock:
-	 */
-	spin_lock(&migration_lock);
-	new_task = p;
-
-	smp_message_pass(cpu, PPC_MSG_MIGRATE_TASK, 0, 0);
-}
-
-/*
- * Task migration callback.
- */
-static void smp_task_migration_interrupt(void)
-{
-	task_t *p;
-
-	/* Should we ACK the IPI interrupt early? */
-	p = new_task;
-	spin_unlock(&migration_lock);
-	sched_task_migrated(p);
-}
-
 void smp_message_recv(int msg, struct pt_regs *regs)
 {
 	switch( msg ) {
@@ -401,9 +374,11 @@
 		/* XXX Do we have to do this? */
 		set_need_resched();
 		break;
+#if 0
 	case PPC_MSG_MIGRATE_TASK:
-		smp_task_migration_interrupt();
+		/* spare */
 		break;
+#endif
 #ifdef CONFIG_XMON
 	case PPC_MSG_XMON_BREAK:
 		xmon(regs);
@@ -418,17 +393,6 @@
 
 void smp_send_reschedule(int cpu)
 {
-	/*
-	 * This is only used if `cpu' is running an idle task,
-	 * so it will reschedule itself anyway...
-	 *
-	 * This isn't the case anymore since the other CPU could be
-	 * sleeping and won't reschedule until the next interrupt (such
-	 * as the timer).
-	 *  -- Cort
-	 */
-	/* This is only used if `cpu' is running an idle task,
-	   so it will reschedule itself anyway... */
 	smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0);
 }
 
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/stab.c linux-2.5.8-pre3/arch/ppc64/kernel/stab.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/stab.c	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/stab.c	Tue Apr  9 18:35:19 2002
@@ -18,10 +18,10 @@
 #include <asm/Naca.h>
 #include <asm/pmc.h>
 
-inline int make_ste(unsigned long stab, 
-		    unsigned long esid, unsigned long vsid);
-inline void make_slbe(unsigned long esid, unsigned long vsid,
-		      int large);
+int make_ste(unsigned long stab, 
+	     unsigned long esid, unsigned long vsid);
+void make_slbe(unsigned long esid, unsigned long vsid,
+	       int large);
 extern struct Naca *naca;
 
 /*
@@ -56,8 +56,7 @@
 /*
  * Create a segment table entry for the given esid/vsid pair.
  */ 
-inline int
-make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
+int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
 {
 	unsigned long entry, group, old_esid, castout_entry, i;
 	unsigned int global_entry;
@@ -146,11 +145,11 @@
 
 /*
  * Create a segment buffer entry for the given esid/vsid pair.
- */ 
-inline void make_slbe(unsigned long esid, unsigned long vsid, int large)
+ */
+void make_slbe(unsigned long esid, unsigned long vsid, int large)
 {
+	int kernel_segment = 0;
 	unsigned long entry, castout_entry;
-	slb_dword0 castout_esid_data;
 	union {
 		unsigned long word0;
 		slb_dword0    data;
@@ -159,7 +158,10 @@
 		unsigned long word0;
 		slb_dword1    data;
 	} vsid_data;
-	
+
+	if (REGION_ID(esid << SID_SHIFT) >= KERNEL_REGION_ID)
+		kernel_segment = 1;
+
 	/*
 	 * Find an empty entry, if one exists.
 	 */
@@ -175,6 +177,8 @@
 			vsid_data.data.kp = 1;
 			if (large)
 				vsid_data.data.l = 1;
+			if (kernel_segment)
+				vsid_data.data.c = 1;
 
 			esid_data.word0 = 0;
 			esid_data.data.esid = esid;
@@ -200,21 +204,13 @@
 	PMC_SW_PROCESSOR(stab_capacity_castouts); 
 
 	castout_entry = get_paca()->xStab_data.next_round_robin;
-	__asm__ __volatile__("slbmfee  %0,%1" 
-			     : "=r" (castout_esid_data) 
-			     : "r" (castout_entry)); 
-
 	entry = castout_entry; 
 	castout_entry++; 
-	if(castout_entry >= naca->slb_size) {
+	if (castout_entry >= naca->slb_size)
 		castout_entry = 1; 
-	}
 	get_paca()->xStab_data.next_round_robin = castout_entry;
 
-	/* Invalidate the old entry. */
-	castout_esid_data.v = 0; /* Set the class to 0 */
 	/* slbie not needed as the previous mapping is still valid. */
-	__asm__ __volatile__("slbie  %0" : : "r" (castout_esid_data)); 
 	
 	/* 
 	 * Write the new SLB entry.
@@ -224,6 +220,8 @@
 	vsid_data.data.kp = 1;
 	if (large)
 		vsid_data.data.l = 1;
+	if (kernel_segment)
+		vsid_data.data.c = 1;
 	
 	esid_data.word0 = 0;
 	esid_data.data.esid = esid;
@@ -300,7 +298,7 @@
 
 #define STAB_PRESSURE 0
 
-void flush_stab(void)
+void flush_stab(struct task_struct *tsk, struct mm_struct *mm)
 {
 	STE *stab = (STE *) get_paca()->xStab_data.virt;
 	unsigned char *segments = get_paca()->xSegments;
@@ -349,12 +347,57 @@
 		/* Force flush to complete.  */
 		__asm__ __volatile__ ("sync" : : : "memory");  
 	} else {
+/* XXX The commented out code will only work for 32 bit tasks */
+#if 1
 		unsigned long flags;
-
-		PMC_SW_PROCESSOR(stab_invalidations); 
-
 		__save_and_cli(flags);
 		__asm__ __volatile__("isync; slbia; isync":::"memory");
 		__restore_flags(flags);
+#else
+		union {
+			unsigned long word0;
+			slb_dword0 data;
+		} esid_data;
+		unsigned long esid;
+
+		__asm__ __volatile__("isync" : : : "memory");
+		for (esid = 0; esid < 16; esid++) {
+			esid_data.word0 = 0;
+			esid_data.data.esid = esid;
+			__asm__ __volatile__("slbie %0" : : "r" (esid_data));
+		}
+		__asm__ __volatile__("isync" : : : "memory");
+#endif
+
+		PMC_SW_PROCESSOR(stab_invalidations);
+
+		if (test_tsk_thread_flag(tsk, TIF_32BIT)) {
+			unsigned long esid, vsid;
+
+			for (esid = 0; esid < 16; esid++) {
+				vsid = get_vsid(mm->context, esid << SID_SHIFT);
+				make_slbe(esid, vsid, 0);
+			}
+		} else {
+			unsigned long pc = KSTK_EIP(tsk);
+			unsigned long stack = KSTK_ESP(tsk);
+			unsigned long pc_segment = pc & ~SID_MASK;
+			unsigned long stack_segment = stack & ~SID_MASK;
+			unsigned long vsid;
+
+			if (pc) {
+				if (REGION_ID(pc) >= KERNEL_REGION_ID)
+					BUG();
+				vsid = get_vsid(mm->context, pc);
+				make_slbe(GET_ESID(pc), vsid, 0);
+			}
+
+			if (stack && (pc_segment != stack_segment)) {
+				if (REGION_ID(stack) >= KERNEL_REGION_ID)
+					BUG();
+				vsid = get_vsid(mm->context, stack);
+				make_slbe(GET_ESID(stack), vsid, 0);
+			}
+		}
 	}
 }
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/sys_ppc32.c linux-2.5.8-pre3/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/sys_ppc32.c	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/sys_ppc32.c	Tue Apr  9 18:35:19 2002
@@ -932,8 +932,8 @@
 	err |= put_user(stat->ino, &statbuf->st_ino);
 	err |= put_user(stat->mode, &statbuf->st_mode);
 	err |= put_user(stat->nlink, &statbuf->st_nlink);
-	err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
-	err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
+	err |= put_user(stat->uid, &statbuf->st_uid);
+	err |= put_user(stat->gid, &statbuf->st_gid);
 	err |= put_user(stat->rdev, &statbuf->st_rdev);
 	if (stat->size > MAX_NON_LFS)
 		return -EOVERFLOW;
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/time.c linux-2.5.8-pre3/arch/ppc64/kernel/time.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/time.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/time.c	Tue Apr  9 18:35:19 2002
@@ -53,6 +53,7 @@
 #include <asm/nvram.h>
 #include <asm/cache.h>
 #include <asm/machdep.h>
+#include <asm/init.h>
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iSeries/HvCallXm.h>
 #endif
@@ -83,6 +84,7 @@
 unsigned long xtime_sync_interval;
 unsigned long tb_to_xs;
 unsigned      tb_to_us;
+unsigned long processor_freq;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
 struct gettimeofday_struct do_gtod;
@@ -97,6 +99,10 @@
 extern unsigned long prof_shift;
 extern char _stext;
 
+void ppc_adjtimex(void);
+
+static unsigned adjusting_time = 0;
+
 static inline void ppc_do_profile (unsigned long nip)
 {
 	if (!prof_buffer)
@@ -269,6 +275,8 @@
 			timer_sync_xtime( cur_tb );
 			timer_check_rtc();
 			write_unlock(&xtime_lock);
+			if ( adjusting_time && (time_adjust == 0) )
+				ppc_adjtimex();
 		}
 		paca->next_jiffy_update_tb += tb_ticks_per_jiffy;
 	}
@@ -386,13 +394,35 @@
  * fields itself.  This way, the fields which are used for 
  * do_settimeofday get updated too.
  */
-
-long ppc64_sys_stime(int * tptr)
+long ppc64_sys32_stime(int* tptr)
 {
 	int value;
 	struct timeval myTimeval;
 
-	PPCDBG(PPCDBG_SYS32, "ppc64_sys_stime - entered - tptr=%p, *tptr=0x%x \n", tptr, *tptr);
+	if (!capable(CAP_SYS_TIME))
+		return -EPERM;
+
+	if (get_user(value, tptr))
+		return -EFAULT;
+
+	myTimeval.tv_sec = value;
+	myTimeval.tv_usec = 0;
+
+	do_settimeofday(&myTimeval);
+
+	return 0;
+}
+
+/*
+ * This function is a copy of the architecture independent function
+ * but which calls do_settimeofday rather than setting the xtime
+ * fields itself.  This way, the fields which are used for 
+ * do_settimeofday get updated too.
+ */
+long ppc64_sys_stime(long* tptr)
+{
+	long value;
+	struct timeval myTimeval;
 
 	if (!capable(CAP_SYS_TIME))
 		return -EPERM;
@@ -405,7 +435,6 @@
 
 	do_settimeofday(&myTimeval);
 
-	PPCDBG(PPCDBG_SYS32, "ppc64_sys_stime - exiting w/ 0 \n");
 	return 0;
 }
 
@@ -426,6 +455,7 @@
 	tb_last_stamp = get_tb();
 	do_gtod.tb_orig_stamp = tb_last_stamp;
 	do_gtod.varp = &do_gtod.vars[0];
+	do_gtod.var_idx = 0;
 	do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
 	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;
 	do_gtod.varp->tb_to_xs = tb_to_xs;
@@ -434,6 +464,8 @@
 	xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
 	next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
 
+	time_freq = 0;
+
 	xtime.tv_usec = 0;
 	last_rtc_update = xtime.tv_sec;
 	write_unlock_irqrestore(&xtime_lock, flags);
@@ -452,10 +484,12 @@
  * to microseconds to keep do_gettimeofday synchronized 
  * with ntpd.
 
- * Use the time_freq and time_offset computed by adjtimex to 
+ * Use the time_adjust, time_freq and time_offset computed by adjtimex to 
  * adjust the frequency.
 */
 
+/* #define DEBUG_PPC_ADJTIMEX 1 */
+
 void ppc_adjtimex(void)
 {
 	unsigned long den, new_tb_ticks_per_sec, tb_ticks, old_xsec, new_tb_to_xs, new_xsec, new_stamp_xsec;
@@ -464,7 +498,12 @@
 	struct div_result divres; 
 	unsigned long flags;
 	struct gettimeofday_vars * temp_varp;
+	unsigned temp_idx;
+	long singleshot_ppm = 0;
 
+	/* Compute parts per million frequency adjustment to accomplish the time adjustment
+	   implied by time_offset to be applied over the elapsed time indicated by time_constant.
+	   Use SHIFT_USEC to get it into the same units as time_freq. */
 	if ( time_offset < 0 ) {
 		ltemp = -time_offset;
 		ltemp <<= SHIFT_USEC - SHIFT_UPDATE;
@@ -476,8 +515,40 @@
 		ltemp <<= SHIFT_USEC - SHIFT_UPDATE;
 		ltemp >>= SHIFT_KG + time_constant;
 	}
-	delta_freq = time_freq + ltemp;
-
+	
+	/* If there is a single shot time adjustment in progress */
+	if ( time_adjust ) {
+#ifdef DEBUG_PPC_ADJTIMEX
+		printk("ppc_adjtimex: ");
+		if ( adjusting_time == 0 )
+			printk("starting ");
+		printk("single shot time_adjust = %ld\n", time_adjust);
+#endif	
+	
+		adjusting_time = 1;
+		
+		/* Compute parts per million frequency adjustment to match time_adjust */
+		singleshot_ppm = tickadj * HZ;	
+		/* The adjustment should be tickadj*HZ to match the code in linux/kernel/timer.c, but
+		   experiments show that this is too large. 3/4 of tickadj*HZ seems about right */
+		singleshot_ppm -= singleshot_ppm / 4;
+		/* Use SHIFT_USEC to get it into the same units as time_freq */	
+		singleshot_ppm <<= SHIFT_USEC;
+		if ( time_adjust < 0 )
+			singleshot_ppm = -singleshot_ppm;
+	}
+	else {
+#ifdef DEBUG_PPC_ADJTIMEX
+		if ( adjusting_time )
+			printk("ppc_adjtimex: ending single shot time_adjust\n");
+#endif
+		adjusting_time = 0;
+	}
+	
+	/* Add up all of the frequency adjustments */
+	delta_freq = time_freq + ltemp + singleshot_ppm;
+	
+	/* Compute a new value for tb_ticks_per_sec based on the frequency adjustment */
 	den = 1000000 * (1 << (SHIFT_USEC - 8));
 	if ( delta_freq < 0 ) {
 		tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( (-delta_freq) >> (SHIFT_USEC - 8))) / den;
@@ -487,6 +558,16 @@
 		tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( delta_freq >> (SHIFT_USEC - 8))) / den;
 		new_tb_ticks_per_sec = tb_ticks_per_sec - tb_ticks_per_sec_delta;
 	}
+	
+#ifdef DEBUG_PPC_ADJTIMEX
+	printk("ppc_adjtimex: ltemp = %ld, time_freq = %ld, singleshot_ppm = %ld\n", ltemp, time_freq, singleshot_ppm);
+	printk("ppc_adjtimex: tb_ticks_per_sec - base = %ld  new = %ld\n", tb_ticks_per_sec, new_tb_ticks_per_sec);
+#endif
+				
+	/* Compute a new value of tb_to_xs (used to convert tb to microseconds and a new value of 
+	   stamp_xsec which is the time (in 1/2^20 second units) corresponding to tb_orig_stamp.  This 
+	   new value of stamp_xsec compensates for the change in frequency (implied by the new tb_to_xs)
+	   which guarantees that the current time remains the same */ 
 	tb_ticks = get_tb() - do_gtod.tb_orig_stamp;
 	div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres );
 	new_tb_to_xs = divres.result_low;
@@ -496,14 +577,23 @@
 	old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs );
 	new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec;
 
-	if (do_gtod.varp == &do_gtod.vars[0])
+	/* There are two copies of tb_to_xs and stamp_xsec so that no lock is needed to access and use these
+	   values in do_gettimeofday.  We alternate the copies and as long as a reasonable time elapses between
+	   changes, there will never be inconsistent values.  ntpd has a minimum of one minute between updates */
+
+	if (do_gtod.var_idx == 0) {
 		temp_varp = &do_gtod.vars[1];
-	else
+		temp_idx  = 1;
+	}
+	else {
 		temp_varp = &do_gtod.vars[0];
+		temp_idx  = 0;
+	}
 	temp_varp->tb_to_xs = new_tb_to_xs;
 	temp_varp->stamp_xsec = new_stamp_xsec;
 	mb();
 	do_gtod.varp = temp_varp;
+	do_gtod.var_idx = temp_idx;
 
 	write_unlock_irqrestore( &xtime_lock, flags );
 
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/udbg.c linux-2.5.8-pre3/arch/ppc64/kernel/udbg.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/udbg.c	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/udbg.c	Tue Apr  9 18:35:19 2002
@@ -209,10 +209,10 @@
 
 /* Special print used by PPCDBG() macro */
 void
-udbg_ppcdbg(unsigned long flags, const char *fmt, ...)
+udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
 {
 	unsigned long flags;
-	unsigned long active_debugs = flags & naca->debug_switch;
+	unsigned long active_debugs = debug_flags & naca->debug_switch;
 
 	if ( active_debugs ) {
 		va_list ap;
diff -urN linux-2.5.8-pre2/arch/ppc64/kernel/xics.c linux-2.5.8-pre3/arch/ppc64/kernel/xics.c
--- linux-2.5.8-pre2/arch/ppc64/kernel/xics.c	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/arch/ppc64/kernel/xics.c	Tue Apr  9 18:35:19 2002
@@ -84,7 +84,7 @@
 unsigned long long intr_base = 0;
 int xics_irq_8259_cascade = 0;
 int xics_irq_8259_cascade_real = 0;
-unsigned int default_server = 0;
+unsigned int default_server = 0xFF;
 unsigned int default_distrib_server = 0;
 
 /* RTAS service tokens */
@@ -197,9 +197,7 @@
 }
 
 void
-xics_mask_and_ack_irq(
-	u_int	irq
-	)
+xics_mask_and_ack_irq(u_int	irq)
 {
 	int cpu = smp_processor_id();
 
@@ -241,27 +239,39 @@
 	return irq;
 }
 
+struct xics_ipi_struct {
+	volatile unsigned long value;
+} ____cacheline_aligned;
+
+extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
 #ifdef CONFIG_SMP
 void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
-	extern volatile unsigned long xics_ipi_message[];
 	int cpu = smp_processor_id();
 
 	ops->qirr_info(cpu, 0xff);
-	while (xics_ipi_message[cpu]) {
-		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu])) {
+	while (xics_ipi_message[cpu].value) {
+		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu].value)) {
 			mb();
 			smp_message_recv(PPC_MSG_CALL_FUNCTION, regs);
 		}
-		if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu])) {
+		if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu].value)) {
 			mb();
 			smp_message_recv(PPC_MSG_RESCHEDULE, regs);
 		}
-		if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, &xics_ipi_message[cpu])) {
+#if 0
+		if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, &xics_ipi_message[cpu].value)) {
 			mb();
 			smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
 		}
+#endif
+#ifdef CONFIG_XMON
+		if (test_and_clear_bit(PPC_MSG_XMON_BREAK, &xics_ipi_message[cpu].value)) {
+			mb();
+			smp_message_recv(PPC_MSG_XMON_BREAK, regs);
+		}
+#endif
 	}
 }
 
diff -urN linux-2.5.8-pre2/arch/ppc64/lib/checksum.S linux-2.5.8-pre3/arch/ppc64/lib/checksum.S
--- linux-2.5.8-pre2/arch/ppc64/lib/checksum.S	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/arch/ppc64/lib/checksum.S	Tue Apr  9 18:35:19 2002
@@ -17,8 +17,6 @@
 #include <asm/errno.h>
 #include "../kernel/ppc_asm.tmpl"
 
-	.text
-
 /*
  * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header
  * len is in words and is always >= 5.
diff -urN linux-2.5.8-pre2/arch/ppc64/lib/string.S linux-2.5.8-pre3/arch/ppc64/lib/string.S
--- linux-2.5.8-pre2/arch/ppc64/lib/string.S	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/arch/ppc64/lib/string.S	Tue Apr  9 18:35:19 2002
@@ -120,54 +120,6 @@
 	subf	r3,r3,r4
 	blr
 
-/*
- * Use dcbz on the complete cache lines in the destination
- * to set them to zero.  This requires that the destination
- * area is cacheable.  -- paulus
- */
-_GLOBAL(cacheable_memzero)
-	mr	r5,r4
-	li	r4,0
-	addi	r6,r3,-4
-	cmplwi	0,r5,4
-	blt	7f
-	stwu	r4,4(r6)
-	beqlr
-	andi.	r0,r6,3
-	add	r5,r0,r5
-	subf	r6,r0,r6
-	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
-	add	r8,r7,r5
-	srwi	r9,r8,LG_CACHELINE_BYTES
-	addic.	r9,r9,-1	/* total number of complete cachelines */
-	ble	2f
-	xori	r0,r7,CACHELINE_MASK & ~3
-	srwi.	r0,r0,2
-	beq	3f
-	mtctr	r0
-4:	stwu	r4,4(r6)
-	bdnz	4b
-3:	mtctr	r9
-	li	r7,4
-10:	dcbz	r7,r6
-	addi	r6,r6,CACHELINE_BYTES
-	bdnz	10b
-	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
-	addi	r5,r5,4
-2:	srwi	r0,r5,2
-	mtctr	r0
-	bdz	6f
-1:	stwu	r4,4(r6)
-	bdnz	1b
-6:	andi.	r5,r5,3
-7:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r6,r6,3
-8:	stbu	r4,1(r6)
-	bdnz	8b
-	blr
-
 _GLOBAL(memset)
 	rlwimi	r4,r4,8,16,23
 	rlwimi	r4,r4,16,0,15
@@ -193,91 +145,6 @@
 	bdnz	8b
 	blr
 
-_GLOBAL(bcopy)
-	mr	r6,r3
-	mr	r3,r4
-	mr	r4,r6
-	b	.memcpy
-
-/*
- * This version uses dcbz on the complete cache lines in the
- * destination area to reduce memory traffic.  This requires that
- * the destination area is cacheable.
- * We only use this version if the source and dest don't overlap.
- * -- paulus.
- */
-_GLOBAL(cacheable_memcpy)
-	add	r7,r3,r5		/* test if the src & dst overlap */
-	add	r8,r4,r5
-	cmplw	0,r4,r7
-	cmplw	1,r3,r8
-	crand	0,0,4			/* cr0.lt &= cr1.lt */
-	blt	.memcpy			/* if regions overlap */
-
-	addi	r4,r4,-4
-	addi	r6,r3,-4
-	neg	r0,r3
-	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
-	beq	58f
-
-	cmplw	0,r5,r0			/* is this more than total to do? */
-	blt	63f			/* if not much to do */
-	andi.	r8,r0,3			/* get it word-aligned first */
-	subf	r5,r0,r5
-	mtctr	r8
-	beq+	61f
-70:	lbz	r9,4(r4)		/* do some bytes */
-	stb	r9,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	70b
-61:	srwi.	r0,r0,2
-	mtctr	r0
-	beq	58f
-72:	lwzu	r9,4(r4)		/* do some words */
-	stwu	r9,4(r6)
-	bdnz	72b
-
-58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
-	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
-	li	r11,4
-	mtctr	r0
-	beq	63f
-53:
-	dcbz	r11,r6
-	COPY_16_BYTES
-#if CACHE_LINE_SIZE >= 32
-	COPY_16_BYTES
-#if CACHE_LINE_SIZE >= 64
-	COPY_16_BYTES
-	COPY_16_BYTES
-#if CACHE_LINE_SIZE >= 128
-	COPY_16_BYTES
-	COPY_16_BYTES
-	COPY_16_BYTES
-	COPY_16_BYTES
-#endif
-#endif
-#endif
-	bdnz	53b
-
-63:	srwi.	r0,r5,2
-	mtctr	r0
-	beq	64f
-30:	lwzu	r0,4(r4)
-	stwu	r0,4(r6)
-	bdnz	30b
-
-64:	andi.	r0,r5,3
-	mtctr	r0
-	beq+	65f
-40:	lbz	r0,4(r4)
-	stb	r0,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	40b
-65:	blr
-
 _GLOBAL(memmove)
 	cmplw	0,r3,r4
 	bgt	.backwards_memcpy
diff -urN linux-2.5.8-pre2/arch/ppc64/mm/init.c linux-2.5.8-pre3/arch/ppc64/mm/init.c
--- linux-2.5.8-pre2/arch/ppc64/mm/init.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/arch/ppc64/mm/init.c	Tue Apr  9 18:35:19 2002
@@ -113,23 +113,6 @@
  */
 mmu_gather_t     mmu_gathers[NR_CPUS];
 
-int do_check_pgt_cache(int low, int high)
-{
-	int freed = 0;
-
-	if (pgtable_cache_size > high) {
-		do {
-			if (pgd_quicklist)
-				free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed;
-			if (pmd_quicklist)
-				free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed;
-			if (pte_quicklist)
-				free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed;
-		} while (pgtable_cache_size > low);
-	}
-	return freed;	
-}
-
 void show_mem(void)
 {
 	int i,free = 0,total = 0,reserved = 0;
@@ -155,7 +138,6 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	printk("%d pages in page table cache\n",(int)pgtable_cache_size);
 	show_buffers();
 }
 
@@ -260,7 +242,7 @@
 		spin_lock(&ioremap_mm.page_table_lock);
 		pgdp = pgd_offset_i(ea);
 		pmdp = pmd_alloc(&ioremap_mm, pgdp, ea);
-		ptep = pte_alloc(&ioremap_mm, pmdp, ea);
+		ptep = pte_alloc_kernel(&ioremap_mm, pmdp, ea);
 
 		pa = absolute_to_phys(pa);
 		set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
@@ -271,7 +253,7 @@
 		 * entry in the hardware page table. 
  		 */
 		vsid = get_kernel_vsid(ea);
-		make_pte(htab_data.htab,
+		ppc_md.make_pte(htab_data.htab,
 			(vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea)
 			pa, 
 			_PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX,
@@ -280,42 +262,37 @@
 }
 
 void
-local_flush_tlb_all(void)
-{
-	/* Implemented to just flush the vmalloc area.
-	 * vmalloc is the only user of flush_tlb_all.
-	 */
-	local_flush_tlb_range( NULL, VMALLOC_START, VMALLOC_END );
-}
-
-void
-local_flush_tlb_mm(struct mm_struct *mm)
+flush_tlb_mm(struct mm_struct *mm)
 {
-	if ( mm->map_count ) {
+	if (mm->map_count) {
 		struct vm_area_struct *mp;
-		for ( mp = mm->mmap; mp != NULL; mp = mp->vm_next )
-			local_flush_tlb_range( mm, mp->vm_start, mp->vm_end );
-	}
-	else	/* MIKEC: It is not clear why this is needed */
+		for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
+			__flush_tlb_range(mm, mp->vm_start, mp->vm_end);
+	} else {
+		/* MIKEC: It is not clear why this is needed */
 		/* paulus: it is needed to clear out stale HPTEs
 		 * when an address space (represented by an mm_struct)
 		 * is being destroyed. */
-		local_flush_tlb_range( mm, USER_START, USER_END );
-}
+		__flush_tlb_range(mm, USER_START, USER_END);
+	}
 
+	/* XXX are there races with checking cpu_vm_mask? - Anton */
+	mm->cpu_vm_mask = 0;
+}
 
 /*
  * Callers should hold the mm->page_table_lock
  */
 void
-local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
 {
 	unsigned long context = 0;
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *ptep;
 	pte_t pte;
-	
+	int local = 0;
+
 	switch( REGION_ID(vmaddr) ) {
 	case VMALLOC_REGION_ID:
 		pgd = pgd_offset_k( vmaddr );
@@ -326,28 +303,34 @@
 	case USER_REGION_ID:
 		pgd = pgd_offset( vma->vm_mm, vmaddr );
 		context = vma->vm_mm->context;
+
+		/* XXX are there races with checking cpu_vm_mask? - Anton */
+		if (vma->vm_mm->cpu_vm_mask == (1 << smp_processor_id()))
+			local = 1;
+
 		break;
 	default:
-		panic("local_flush_tlb_page: invalid region 0x%016lx", vmaddr);
+		panic("flush_tlb_page: invalid region 0x%016lx", vmaddr);
 	
 	}
 
-
 	if (!pgd_none(*pgd)) {
 		pmd = pmd_offset(pgd, vmaddr);
 		if (!pmd_none(*pmd)) {
-			ptep = pte_offset(pmd, vmaddr);
+			ptep = pte_offset_kernel(pmd, vmaddr);
 			/* Check if HPTE might exist and flush it if so */
 			pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
 			if ( pte_val(pte) & _PAGE_HASHPTE ) {
-				flush_hash_page(context, vmaddr, pte);
+				flush_hash_page(context, vmaddr, pte, local);
 			}
 		}
 	}
 }
 
+struct tlb_batch_data tlb_batch_array[NR_CPUS][MAX_BATCH_FLUSH];
+
 void
-local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+__flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
 	pgd_t *pgd;
 	pmd_t *pmd;
@@ -355,6 +338,9 @@
 	pte_t pte;
 	unsigned long pgd_end, pmd_end;
 	unsigned long context;
+	int i = 0;
+	struct tlb_batch_data *ptes = &tlb_batch_array[smp_processor_id()][0];
+	int local = 0;
 
 	if ( start >= end )
 		panic("flush_tlb_range: start (%016lx) greater than end (%016lx)\n", start, end );
@@ -374,6 +360,12 @@
 	case USER_REGION_ID:
 		pgd = pgd_offset( mm, start );
 		context = mm->context;
+
+		/* XXX are there races with checking cpu_vm_mask? - Anton */
+		if (mm->cpu_vm_mask == (1 << smp_processor_id())) {
+			local = 1;
+		}
+
 		break;
 	default:
 		panic("flush_tlb_range: invalid region for start (%016lx) and end (%016lx)\n", start, end);
@@ -391,12 +383,21 @@
 				if ( pmd_end > end )
 					pmd_end = end;
 				if ( !pmd_none( *pmd ) ) {
-					ptep = pte_offset( pmd, start );
+					ptep = pte_offset_kernel( pmd, start );
 					do {
 						if ( pte_val(*ptep) & _PAGE_HASHPTE ) {
 							pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
-							if ( pte_val(pte) & _PAGE_HASHPTE )
-								flush_hash_page( context, start, pte );
+							if ( pte_val(pte) & _PAGE_HASHPTE ) {
+								ptes->pte = pte;
+								ptes->addr = start;
+								ptes++;
+								i++;
+								if (i == MAX_BATCH_FLUSH) {
+									flush_hash_range(context, MAX_BATCH_FLUSH, local);
+									i = 0;
+									ptes = &tlb_batch_array[smp_processor_id()][0];
+								}
+							}
 						}
 						start += PAGE_SIZE;
 						++ptep;
@@ -411,6 +412,9 @@
 			start = pgd_end;
 		++pgd;
 	} while ( start < end );
+
+	if (i)
+		flush_hash_range(context, i, local);
 }
 
 
@@ -517,8 +521,14 @@
 
 	/* add all physical memory to the bootmem map */
 	for (i=0; i < lmb.memory.cnt ;i++) {
-		unsigned long physbase = lmb.memory.region[i].physbase;
-		unsigned long size = lmb.memory.region[i].size;
+		unsigned long physbase, size;
+		unsigned long type = lmb.memory.region[i].type;
+
+		if ( type != LMB_MEMORY_AREA )
+			continue;
+
+		physbase = lmb.memory.region[i].physbase;
+		size = lmb.memory.region[i].size;
 		free_bootmem(physbase, size);
 	}
 	/* reserve the sections we're already using */
@@ -559,6 +569,8 @@
 extern unsigned long dprof_len;
 extern unsigned int * dprof_buffer;
 
+void initialize_paca_hardware_interrupt_stack(void);
+
 void __init mem_init(void)
 {
 	extern char *sysmap; 
@@ -611,8 +623,8 @@
 	       PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM()));
 	mem_init_done = 1;
 
-    /* set the last page of each hardware interrupt stack to be protected       */
-    initialize_paca_hardware_interrupt_stack();
+	/* set the last page of each hardware interrupt stack to be protected */
+	initialize_paca_hardware_interrupt_stack();
 
 #ifdef CONFIG_PPC_ISERIES
 	create_virtual_bus_tce_table();
@@ -661,3 +673,34 @@
 	maddr = (unsigned long)page_address(page) + (addr & ~PAGE_MASK);
 	flush_icache_range(maddr, maddr + len);
 }
+
+extern pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea);
+int __hash_page(unsigned long ea, unsigned long access, unsigned long vsid,
+		pte_t *ptep);
+
+/*
+ * This is called at the end of handling a user page fault, when the
+ * fault has been handled by updating a PTE in the linux page tables.
+ * We use it to preload an HPTE into the hash table corresponding to
+ * the updated linux PTE.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea,
+		      pte_t pte)
+{
+	unsigned long vsid;
+	void *pgdir;
+	pte_t *ptep;
+
+	/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
+	if (!pte_young(pte))
+		return;
+
+	pgdir = vma->vm_mm->pgd;
+	if (pgdir == NULL)
+		return;
+
+	ptep = find_linux_pte(pgdir, ea);
+	vsid = get_vsid(vma->vm_mm->context, ea);
+
+	__hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep);
+}
diff -urN linux-2.5.8-pre2/arch/ppc64/vmlinux.lds linux-2.5.8-pre3/arch/ppc64/vmlinux.lds
--- linux-2.5.8-pre2/arch/ppc64/vmlinux.lds	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/arch/ppc64/vmlinux.lds	Tue Apr  9 18:35:19 2002
@@ -109,8 +109,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
-
-
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
diff -urN linux-2.5.8-pre2/arch/ppc64/xmon/start.c linux-2.5.8-pre3/arch/ppc64/xmon/start.c
--- linux-2.5.8-pre2/arch/ppc64/xmon/start.c	Mon Mar 18 12:37:15 2002
+++ linux-2.5.8-pre3/arch/ppc64/xmon/start.c	Tue Apr  9 18:35:19 2002
@@ -7,12 +7,11 @@
  *      2 of the License, or (at your option) any later version.
  */
 #include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sysrq.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/page.h>
-#include <linux/pmu.h>
-#include <linux/kernel.h>
-#include <linux/sysrq.h>
 #include <asm/prom.h>
 #include <asm/processor.h>
 
diff -urN linux-2.5.8-pre2/arch/ppc64/xmon/xmon.c linux-2.5.8-pre3/arch/ppc64/xmon/xmon.c
--- linux-2.5.8-pre2/arch/ppc64/xmon/xmon.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/arch/ppc64/xmon/xmon.c	Tue Apr  9 18:35:19 2002
@@ -12,6 +12,8 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
+#include <linux/mm.h>
+#include <linux/reboot.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
 #include <asm/prom.h>
@@ -22,13 +24,9 @@
 #include <asm/mmu_context.h>
 #include <asm/Naca.h>
 #include <asm/Paca.h>
+#include <asm/ppcdebug.h>
 #include "nonstdio.h"
 #include "privinst.h"
-#include <linux/mm.h>
-
-#include <asm/ppcdebug.h>
-
-#include <asm/Paca.h>
 
 #define scanhex	xmon_scanhex
 #define skipbl	xmon_skipbl
@@ -132,8 +130,6 @@
 static void mem_map_lock_pages(void);
 static void mem_map_check_hash(void);
 static void mem_check_dup_rpn (void);
-static void show_task(struct task_struct * p);
-static void xmon_show_state(void);
 static void debug_trace(void);
 
 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long);
@@ -181,6 +177,7 @@
   T	Enable/Disable PPCDBG flags\n\
   x	exit monitor\n\
   z	reboot\n\
+  Z	halt\n\
 ";
 
 static int xmon_trace[NR_CPUS];
@@ -262,8 +259,10 @@
 
 static inline void disable_surveillance(void)
 {
+#ifndef CONFIG_PPC_ISERIES
         rtas_call(rtas_token("set-indicator"), 3, 1, NULL, SURVEILLANCE_TOKEN,
 		  0, 0);
+#endif
 }
 
 void
@@ -620,8 +619,13 @@
 		}
 		switch (cmd) {
 		case 'z':
+			printf("Rebooting machine now...");
 			machine_restart(NULL);
 			break;
+		case 'Z':
+			printf("Halting machine now...");
+			machine_halt();
+			break;
 		case 'm':
 			cmd = inchar();
 			switch (cmd) {
@@ -710,7 +714,7 @@
 			printf(help_string);
 			break;
 		case 'p':
-			xmon_show_state();
+			show_state();
 			break;
 		case 'b':
 			bpt_cmds();
@@ -1211,7 +1215,7 @@
 
 	instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
 	instrs[1] = 0x4e800020;
-	opd[0] = instrs;
+	opd[0] = (unsigned long)instrs;
 	opd[1] = 0;
 	opd[2] = 0;
 	store_inst(instrs);
@@ -1230,7 +1234,7 @@
 
 	instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
 	instrs[1] = 0x4e800020;
-	opd[0] = instrs;
+	opd[0] = (unsigned long)instrs;
 	opd[1] = 0;
 	opd[2] = 0;
 	store_inst(instrs);
@@ -2799,111 +2803,6 @@
 	printf("\nDone -------------------\n");
 }
 
-
-
-static void show_task(struct task_struct * p)
-{
-	/* unsigned long free = 0;  --Unused */
-	int state;
-	static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
-
-	printf("--------------------------------------------------------------------------\n");
-	printf("%-11.11s pid: %5.5lx ppid: %5.5lx state: ", 
-	       p->comm, p->pid, p->p_pptr->pid);
-	state = p->state ? ffz(~p->state) + 1 : 0;
-	if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
-		printf(stat_nam[state]);
-	else
-		printf(" ");
-	if (p == current)
-		printf(" pc: current task       ");
-	else
-		printf(" pc: 0x%16.16lx ", thread_saved_pc(&p->thread));
-
-	if (p->p_cptr)
-		printf("%5d ", p->p_cptr->pid);
-	else
-		printf("      ");
-	if (!p->mm)
-		printf(" (L-TLB) ");
-	else
-		printf(" (NOTLB) ");
-	if (p->p_ysptr)
-		printf("%7d", p->p_ysptr->pid);
-	else
-		printf("       ");
-	if (p->p_osptr)
-		printf(" %5d\n", p->p_osptr->pid);
-	else
-		printf("\n");
-
-	{
-		struct sigqueue *q;
-		char s[sizeof(sigset_t)*2+1], b[sizeof(sigset_t)*2+1]; 
-
-		render_sigset_t(&p->pending.signal, s);
-		render_sigset_t(&p->blocked, b);
-		printf("            sig: %d %s %s :", signal_pending(p), s, b);
-		for (q = p->pending.head; q ; q = q->next)
-			printf(" %d", q->info.si_signo);
-		printf(" X\n");
-	}
-
-	printf("            pers   : %lx  current : %lx", 
-	       p->personality, p);
-	printf("\n");
-
-	printf("            thread : 0x%16.16lx  ksp   : 0x%16.16lx\n", 
-	       &(p->thread), (p->thread.ksp));
-	printf("            pgdir : 0x%16.16lx\n", (p->thread.pgdir));
-	printf("            regs   : 0x%16.16lx  sysc  : 0x%16.16lx\n", 
-	       (p->thread.regs), (p->thread.last_syscall));
-	if(p->thread.regs) {
-	  printf("            nip    : 0x%16.16lx  msr   : 0x%16.16lx\n", 
-		 ((p->thread.regs)->nip), ((p->thread.regs)->msr)); 
-	  printf("            ctr    : 0x%16.16lx  link  : 0x%16.16lx\n", 
-		 ((p->thread.regs)->ctr), ((p->thread.regs)->link));
-	  printf("            xer    : 0x%16.16lx  ccr   : 0x%16.16lx\n", 
-		 ((p->thread.regs)->xer), ((p->thread.regs)->ccr)); 
-	  printf("            trap   : 0x%16.16lx\n", 
-		 ((p->thread.regs)->trap));
-	  printf("            dar    : 0x%16.16lx  dsis  : 0x%16.16lx\n", 
-		 ((p->thread.regs)->dar), ((p->thread.regs)->dsisr));
-	  printf("            rslt   : 0x%16.16lx  org3  : 0x%16.16lx\n", 
-		 ((p->thread.regs)->result), (p->thread.regs->orig_gpr3));
-	}
-
-	if(p->mm) {
-	  struct mm_struct *mm = p->mm; 
-	  printf("            mm     : 0x%16.16lx  pgd   : 0x%16.16lx\n", 
-		 mm, mm->pgd);
-	  printf("            context: 0x%16.16lx  mmap  : 0x%16.16lx\n", 
-		 mm->context, mm->mmap);
-	  
-	  printf("\n");
-	}
-
-}
-
-static void xmon_show_state(void)
-{
-	struct task_struct *p;
-
-#if (BITS_PER_LONG == 32)
-	printf("\n"
-	       "                         free                        sibling\n");
-	printf("task name   st PC              stack   pid father child younger older\n");
-#else
-	printf("\n"
-	       "                                 free                        sibling\n");
-	printf("  task                 PC        stack   pid father child younger older\n");
-#endif
-	read_lock(&tasklist_lock);
-	for_each_task(p)
-		show_task(p);
-	read_unlock(&tasklist_lock);
-}
-
 static void debug_trace(void) {
         unsigned long val, cmd, on;
 
diff -urN linux-2.5.8-pre2/drivers/acpi/Makefile linux-2.5.8-pre3/drivers/acpi/Makefile
--- linux-2.5.8-pre2/drivers/acpi/Makefile	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/acpi/Makefile	Tue Apr  9 18:35:19 2002
@@ -9,7 +9,7 @@
 ACPI_CFLAGS	:= -D_LINUX -I$(CURDIR)/include
 
 ifdef CONFIG_ACPI_DEBUG
-  ACPI_CFLAGS	+= -DACPI_DEBUG -Wno-unused
+  ACPI_CFLAGS	+= -DACPI_DEBUG
 endif
 
 EXTRA_CFLAGS	+= $(ACPI_CFLAGS)
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_ac.c linux-2.5.8-pre3/drivers/acpi/acpi_ac.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_ac.c	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_ac.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_ac.c - ACPI AC Adapter Driver ($Revision: 22 $)
+ *  acpi_ac.c - ACPI AC Adapter Driver ($Revision: 23 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -296,6 +296,7 @@
 	struct acpi_ac		*ac = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_ac_remove");
+
 	if (!device || !acpi_driver_data(device))
 		return_VALUE(-EINVAL);
 
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_battery.c linux-2.5.8-pre3/drivers/acpi/acpi_battery.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_battery.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_battery.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_battery.c - ACPI Battery Driver ($Revision: 31 $)
+ *  acpi_battery.c - ACPI Battery Driver ($Revision: 32 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -112,8 +112,9 @@
 	struct acpi_battery	*battery,
 	struct acpi_battery_info **bif)
 {
+	int			result = 0;
 	acpi_status 		status = 0;
-	acpi_buffer 		buffer = {0, NULL};
+	acpi_buffer 		buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	acpi_buffer		format = {sizeof(ACPI_BATTERY_FORMAT_BIF),
 						ACPI_BATTERY_FORMAT_BIF};
 	acpi_buffer		data = {0, NULL};
@@ -126,9 +127,11 @@
 
 	/* Evalute _BIF */
 
-	status = acpi_evaluate(battery->handle, "_BIF", NULL, &buffer);
-	if (ACPI_FAILURE(status))
+	status = acpi_evaluate_object(battery->handle, "_BIF", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BIF\n"));
 		return_VALUE(-ENODEV);
+	}
 
 	package = (acpi_object *) buffer.pointer;
 
@@ -136,29 +139,33 @@
 
 	status = acpi_extract_package(package, &format, &data);
 	if (status != AE_BUFFER_OVERFLOW) {
-		kfree(buffer.pointer);
-		return_VALUE(-ENODEV);
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
+		result = -ENODEV;
+		goto end;
 	}
 
 	data.pointer = kmalloc(data.length, GFP_KERNEL);
 	if (!data.pointer) {
-		kfree(buffer.pointer);
-		return_VALUE(-ENOMEM);
+		result = -ENOMEM;
+		goto end;
 	}
 	memset(data.pointer, 0, data.length);
 
 	status = acpi_extract_package(package, &format, &data);
 	if (ACPI_FAILURE(status)) {
-		kfree(buffer.pointer);
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
 		kfree(data.pointer);
-		return_VALUE(-ENODEV);
+		result = -ENODEV;
+		goto end;
 	}
 
+end:
 	kfree(buffer.pointer);
 
-	(*bif) = data.pointer;
+	if (0 == result)
+		(*bif) = (struct acpi_battery_info *) data.pointer;
 
-	return_VALUE(0);
+	return_VALUE(result);
 }
 
 static int
@@ -166,8 +173,9 @@
 	struct acpi_battery	*battery,
 	struct acpi_battery_status **bst)
 {
+	int			result = 0;
 	acpi_status 		status = 0;
-	acpi_buffer 		buffer = {0, NULL};
+	acpi_buffer 		buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	acpi_buffer		format = {sizeof(ACPI_BATTERY_FORMAT_BST),
 						ACPI_BATTERY_FORMAT_BST};
 	acpi_buffer		data = {0, NULL};
@@ -180,9 +188,11 @@
 
 	/* Evalute _BST */
 
-	status = acpi_evaluate(battery->handle, "_BST", NULL, &buffer);
-	if (ACPI_FAILURE(status))
+	status = acpi_evaluate_object(battery->handle, "_BST", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BST\n"));
 		return_VALUE(-ENODEV);
+	}
 
 	package = (acpi_object *) buffer.pointer;
 
@@ -190,29 +200,33 @@
 
 	status = acpi_extract_package(package, &format, &data);
 	if (status != AE_BUFFER_OVERFLOW) {
-		kfree(buffer.pointer);
-		return_VALUE(-ENODEV);
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
+		result = -ENODEV;
+		goto end;
 	}
 
 	data.pointer = kmalloc(data.length, GFP_KERNEL);
 	if (!data.pointer) {
-		kfree(buffer.pointer);
-		return_VALUE(-ENOMEM);
+		result = -ENOMEM;
+		goto end;
 	}
 	memset(data.pointer, 0, data.length);
 
 	status = acpi_extract_package(package, &format, &data);
 	if (ACPI_FAILURE(status)) {
-		kfree(buffer.pointer);
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
 		kfree(data.pointer);
-		return_VALUE(-ENODEV);
+		result = -ENODEV;
+		goto end;
 	}
 
+end:
 	kfree(buffer.pointer);
 
-	(*bst) = data.pointer;
+	if (0 == result)
+		(*bst) = (struct acpi_battery_status *) data.pointer;
 
-	return_VALUE(0);
+	return_VALUE(result);
 }
 
 
@@ -328,7 +342,7 @@
 {
 	int			result = 0;
 	struct acpi_battery	*battery = (struct acpi_battery *) data;
-	struct acpi_battery_info *bif = 0;
+	struct acpi_battery_info *bif = NULL;
 	char			*units = "?";
 	char			*p = page;
 	int			len = 0;
@@ -403,8 +417,7 @@
 		bif->oem_info);
 
 end:
-	if (bif)
-		kfree(bif);
+	kfree(bif);
 
 	len = (p - page);
 	if (len <= off+count) *eof = 1;
@@ -490,8 +503,7 @@
 			(u32) bst->present_voltage);
 
 end:
-	if (bst)
-		kfree(bst);
+	kfree(bst);
 
 	len = (p - page);
 	if (len <= off+count) *eof = 1;
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_bus.c linux-2.5.8-pre3/drivers/acpi/acpi_bus.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_bus.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_bus.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_bus.c - ACPI Bus Driver ($Revision: 56 $)
+ *  acpi_bus.c - ACPI Bus Driver ($Revision: 66 $)
  *
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
  *
@@ -77,6 +77,8 @@
 	{"SONY  ", "U0      ", 0x20010313, ACPI_TABLE_DSDT, less_than_or_equal, "ACPI driver problem", 1},
 	/* Compaq Presario 800, Insyde BIOS */
 	{"INT440", "SYSFexxx", 0x00001001, ACPI_TABLE_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1},
+	/* IBM 600E - _ADR should return 7, but it returns 1 */
+	{"IBM   ", "TP600E  ", 0x00000105, ACPI_TABLE_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
 	{""}
 };
 
@@ -266,34 +268,6 @@
 }
 
 
-static void
-acpi_bus_data_handler_powerf (
-	acpi_handle		handle,
-	u32			function,
-	void			*context)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_data_handler_powerf");
-
-	/* TBD */
-
-	return_VOID;
-}
-
-
-static void
-acpi_bus_data_handler_sleepf (
-	acpi_handle		handle,
-	u32			function,
-	void			*context)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_data_handler_sleepf");
-
-	/* TBD */
-
-	return_VOID;
-}
-
-
 int
 acpi_bus_get_device (
 	acpi_handle		handle,
@@ -1044,8 +1018,10 @@
 	if (!device || !driver)
 		return -EINVAL;
 
-	if (0 != strstr(driver->ids, device->pnp.hardware_id))
-		return 0;
+	if (device->flags.hardware_id) {
+		if (0 != strstr(driver->ids, device->pnp.hardware_id))
+			return 0;
+	}
 
 	if (device->flags.compatible_ids) {
 		acpi_status	status = AE_OK;
@@ -1055,8 +1031,8 @@
 
 		memset(cid, 0, sizeof(cid));
 
-		status = acpi_evaluate_object(device->handle, "_CID", 
-			NULL, &buffer);
+		status = acpi_evaluate_object(device->handle, "_CID", NULL, 
+			&buffer);
 		if (ACPI_FAILURE(status) || !buffer.pointer)
 			return -ENOENT;
 
@@ -1072,10 +1048,11 @@
 			break;
 		case ACPI_TYPE_PACKAGE:
 			/* TBD: Support CID packages */
-		default:
-			return -ENOENT;
 		}
 
+		if (!cid[0])
+			return -ENOENT;
+
 		if (0 != strstr(cid, device->pnp.hardware_id))
 			return 0;
 	}
@@ -1144,13 +1121,13 @@
 
 
 /**
- * acpi_bus_bind 
+ * acpi_bus_attach 
  * -------------
  * Callback for acpi_bus_walk() used to find devices that match a specific 
- * driver's criteria and bind the driver to the device.
+ * driver's criteria and then attach the driver.
  */
 static int
-acpi_bus_bind (
+acpi_bus_attach (
 	struct acpi_device	*device, 
 	int			level, 
 	void			*data)
@@ -1158,7 +1135,7 @@
 	int			result = 0;
 	struct acpi_driver	*driver = NULL;
 
-	ACPI_FUNCTION_TRACE("acpi_bus_bind");
+	ACPI_FUNCTION_TRACE("acpi_bus_attach");
 
 	if (!device || !data)
 		return_VALUE(-EINVAL);
@@ -1191,13 +1168,13 @@
 
 
 /**
- * acpi_bus_unbind 
- * ---------------
+ * acpi_bus_unattach 
+ * -----------------
  * Callback for acpi_bus_walk() used to find devices that match a specific 
- * driver's criteria and unbind the driver from the device.
+ * driver's criteria and unattach the driver.
  */
 static int
-acpi_bus_unbind (
+acpi_bus_unattach (
 	struct acpi_device	*device, 
 	int			level, 
 	void			*data)
@@ -1205,7 +1182,7 @@
 	int			result = 0;
 	struct acpi_driver	*driver = (struct acpi_driver *) data;
 
-	ACPI_FUNCTION_TRACE("acpi_bus_unbind");
+	ACPI_FUNCTION_TRACE("acpi_bus_unattach");
 
 	if (!device || !driver)
 		return_VALUE(-EINVAL);
@@ -1291,7 +1268,7 @@
 	list_add_tail(&driver->node, &acpi_bus_drivers);
 	up(&acpi_bus_drivers_lock);
 
-	acpi_bus_walk(acpi_root, acpi_bus_bind, 
+	acpi_bus_walk(acpi_root, acpi_bus_attach, 
 		WALK_DOWN, driver);
 
 	return_VALUE(driver->references);
@@ -1313,7 +1290,7 @@
 	if (!driver)
 		return_VALUE(-EINVAL);
 
-	acpi_bus_walk(acpi_root, acpi_bus_unbind, WALK_UP, driver);
+	acpi_bus_walk(acpi_root, acpi_bus_unattach, WALK_UP, driver);
 
 	if (driver->references)
 		return_VALUE(driver->references);
@@ -1395,8 +1372,8 @@
 	char			bus_id[5] = {'?',0};
 	acpi_buffer		buffer = {sizeof(bus_id), bus_id};
 	acpi_device_info	info;
-	char			*hid = "?";
-	char			*uid = "0";
+	char			*hid = NULL;
+	char			*uid = NULL;
 	int			i = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_bus_add");
@@ -1414,6 +1391,37 @@
 	device->handle = handle;
 	device->parent = parent;
 
+	memset(&info, 0, sizeof(acpi_device_info));
+
+	/*
+	 * Bus ID
+	 * ------
+	 * The device's Bus ID is simply the object name.
+	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
+	 */
+	switch (type) {
+	case ACPI_BUS_TYPE_SYSTEM:
+		sprintf(device->pnp.bus_id, "%s", "ACPI");
+		break;
+	case ACPI_BUS_TYPE_POWER_BUTTON:
+		sprintf(device->pnp.bus_id, "%s", "PWRF");
+		break;
+	case ACPI_BUS_TYPE_SLEEP_BUTTON:
+		sprintf(device->pnp.bus_id, "%s", "SLPF");
+		break;
+	default:
+		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+		/* Clean up trailing underscores (if any) */
+		for (i = 3; i > 1; i--) {
+			if (bus_id[i] == '_')
+				bus_id[i] = '\0';
+			else
+				break;
+		}
+		sprintf(device->pnp.bus_id, "%s", bus_id);
+		break;
+	}
+
 	/*
 	 * Flags
 	 * -----
@@ -1457,35 +1465,6 @@
 	 */
 
 	/*
-	 * Bus ID
-	 * ------
-	 * The device's Bus ID is simply the object name.
-	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
-	 */
-	switch (type) {
-	case ACPI_BUS_TYPE_SYSTEM:
-		sprintf(device->pnp.bus_id, "%s", "ACPI");
-		break;
-	case ACPI_BUS_TYPE_POWER_BUTTON:
-		sprintf(device->pnp.bus_id, "%s", "PWRF");
-		break;
-	case ACPI_BUS_TYPE_SLEEP_BUTTON:
-		sprintf(device->pnp.bus_id, "%s", "SLPF");
-		break;
-	default:
-		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		/* Clean up trailing underscores (if any) */
-		for (i = 3; i > 1; i--) {
-			if (bus_id[i] == '_')
-				bus_id[i] = '\0';
-			else
-				break;
-		}
-		sprintf(device->pnp.bus_id, "%s", bus_id);
-		break;
-	}
-
-	/*
 	 * Hardware ID, Unique ID, & Bus Address
 	 * -------------------------------------
 	 */
@@ -1505,8 +1484,10 @@
 			hid = info.hardware_id;
 		if (info.valid & ACPI_VALID_UID)
 			uid = info.unique_id;
-		if (info.valid & ACPI_VALID_ADR)
+		if (info.valid & ACPI_VALID_ADR) {
 			device->pnp.bus_address = info.address;
+			device->flags.bus_address = 1;
+		}
 		break;
 	case ACPI_BUS_TYPE_POWER:
 		hid = ACPI_POWER_HID;
@@ -1528,8 +1509,25 @@
 		break;
 	}
 
-	sprintf(device->pnp.hardware_id, "%s", hid);
-	sprintf(device->pnp.unique_id, "%s", uid);
+	/* 
+	 * \_SB
+	 * ----
+	 * Fix for the system root bus device -- the only root-level device.
+	 */
+	if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
+		hid = ACPI_BUS_HID;
+		sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME);
+		sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS);
+	}
+
+	if (hid) {
+		sprintf(device->pnp.hardware_id, "%s", hid);
+		device->flags.hardware_id = 1;
+	}
+	if (uid) {
+		sprintf(device->pnp.unique_id, "%s", uid);
+		device->flags.unique_id = 1;
+	}
 
 	/*
 	 * Power Management
@@ -1555,18 +1553,13 @@
 	 * Context
 	 * -------
 	 * Attach this 'struct acpi_device' to the ACPI object.  This makes
-	 * resolutions from handle->device very efficient.  Note that since we
-	 * attach multiple context to the root object (system device plus all
-	 * fixed-feature devices) we must use alternate handlers.
+	 * resolutions from handle->device very efficient.  Note that we need
+	 * to be careful with fixed-feature devices as they all attach to the
+	 * root object.
 	 */
 	switch (type) {
 	case ACPI_BUS_TYPE_POWER_BUTTON:
-		status = acpi_attach_data(device->handle,
-			acpi_bus_data_handler_powerf, device);
-		break;
 	case ACPI_BUS_TYPE_SLEEP_BUTTON:
-		status = acpi_attach_data(device->handle,
-			acpi_bus_data_handler_sleepf, device);
 		break;
 	default:
 		status = acpi_attach_data(device->handle,
@@ -1591,21 +1584,9 @@
 	else
 		list_add_tail(&device->node, &device->parent->children);
 
-	/* 
-	 * \_SB
-	 * ----
-	 * Fix for the system root bus device -- the only root-level device.
-	 */
-	if ((type == ACPI_BUS_TYPE_DEVICE) && (parent == ACPI_ROOT_OBJECT)) {
-		sprintf(device->pnp.hardware_id, "%s", ACPI_BUS_HID);
-		sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME);
-		sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS);
-	}
-
 #ifdef CONFIG_ACPI_DEBUG
 	{
 		char		*type_string = NULL;
-		char		*message = NULL;
 		char		name[80] = {'?','\0'};
 		acpi_buffer	buffer = {sizeof(name), name};
 
@@ -1640,7 +1621,7 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s %s [%p]\n", 
 			type_string, name, handle));
 	}
-#endif
+#endif /*CONFIG_ACPI_DEBUG*/
 
 	/*
 	 * Global Device Hierarchy:
@@ -1650,14 +1631,30 @@
 	acpi_device_register(device, parent);
 
 	/*
-	 * Find Driver
-	 * -----------
-	 * Check to see if there's a driver installed for this kind of device.
+	 * Bind _ADR-Based Devices
+	 * -----------------------
+	 * If there's a a bus address (_ADR) then we utilize the parent's 
+	 * 'bind' function (if exists) to bind the ACPI- and natively-
+	 * enumerated device representations.
 	 */
-	acpi_bus_find_driver(device);
+	if (device->flags.bus_address) {
+		if (device->parent && device->parent->ops.bind)
+			device->parent->ops.bind(device);
+	}
 
-end:
+	/*
+	 * Locate & Attach Driver
+	 * ----------------------
+	 * If there's a hardware id (_HID) or compatible ids (_CID) we check
+	 * to see if there's a driver installed for this kind of device.  Note
+	 * that drivers can install before or after a device in enumerated.
+	 *
+	 * TBD: Assumes LDM provides driver hot-plug capability.
+	 */
+	if (device->flags.hardware_id || device->flags.compatible_ids)
+		acpi_bus_find_driver(device);
 
+end:
 	if (0 != result) {
 		kfree(device);
 		return_VALUE(result);
@@ -1774,13 +1771,11 @@
 		 * If the device is present, enabled, and functioning then
 		 * parse its scope (depth-first).  Note that we need to
 		 * represent absent devices to facilitate PnP notifications
-		 * -- but we only the subtree head (not all of its children,
+		 * -- but only the subtree head (not all of its children,
 		 * which will be enumerated when the parent is inserted).
 		 *
 		 * TBD: Need notifications and other detection mechanisms
 		 *	in place before we can fully implement this.
-		 *
-		 * if (STRUCT_TO_INT(child->status) & 0x0B) {
 		 */
 		if (child->status.present) {
 			status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
@@ -1884,6 +1879,55 @@
 
 
 static int __init
+acpi_bus_init_irq (void)
+{
+	int			result = 0;
+	acpi_status		status = AE_OK;
+	acpi_object		arg = {ACPI_TYPE_INTEGER};
+	acpi_object_list        arg_list = {1, &arg};
+	int			irq_model = 0;
+	char			*message = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_init_irq");
+
+	/* 
+	 * Let the system know what interrupt model we are using by
+	 * evaluating the \_PIC object, if exists.
+	 */
+	result = acpi_get_interrupt_model(&irq_model);
+	if (0 != result)
+		return_VALUE(result);
+
+	switch (irq_model) {
+	case ACPI_INT_MODEL_PIC:
+		message = "PIC";
+		break;
+	case ACPI_INT_MODEL_IOAPIC:
+		message = "IOAPIC";
+		break;
+	case ACPI_INT_MODEL_IOSAPIC:
+		message = "IOSAPIC";
+		break;
+	default:
+		message = "UNKNOWN";
+		break;
+	}
+
+	printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
+
+	arg.integer.value = irq_model;
+
+	status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
+	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	return_VALUE(0);
+}
+
+
+static int __init
 acpi_bus_init (void)
 {
 	int			result = 0;
@@ -1928,7 +1972,7 @@
 	progress++;
 
 	/*
-	 * [2] Get a separate copy of the FADT for use by other drivers.
+	 * [3] Get a separate copy of the FADT for use by other drivers.
 	 */
 	status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer);
 	if (ACPI_FAILURE(status)) {
@@ -1940,7 +1984,7 @@
 	progress++;
 
 	/*
-	 * [3] Enable the ACPI Core Subsystem.
+	 * [4] Enable the ACPI Core Subsystem.
 	 */
 	status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
 	if (ACPI_FAILURE(status)) {
@@ -1954,7 +1998,14 @@
 	progress++;
 
 	/*
-	 * [4] Register for all standard device notifications.
+	 * [5] Register for all standard device notifications.
+	 */
+	result = acpi_bus_init_irq();
+	if (0 != result)
+		goto end;
+
+	/*
+	 * [6] Register for all standard device notifications.
 	 */
 	status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL);
 	if (ACPI_FAILURE(status)) {
@@ -1966,7 +2017,7 @@
 	progress++;
 
 	/*
-	 * [5] Create the root device.
+	 * [7] Create the root device.
 	 */
 	result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, 
 		ACPI_BUS_TYPE_SYSTEM);
@@ -1976,7 +2027,7 @@
 	progress++;
 
 	/*
-	 * [6] Create the root file system.
+	 * [8] Create the root file system.
 	 */
 	acpi_device_dir(acpi_root) = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
 	if (!acpi_root) {
@@ -1988,7 +2039,7 @@
 	progress++;
 
 	/*
-	 * [7] Install drivers required for proper enumeration of the
+	 * [9] Install drivers required for proper enumeration of the
 	 *     ACPI namespace.
 	 */
 	acpi_system_init();	/* ACPI System */
@@ -2003,7 +2054,7 @@
 	progress++;
 
 	/*
-	 * [8] Enumerate devices in the ACPI namespace.
+	 * [10] Enumerate devices in the ACPI namespace.
 	 */
 
 	result = acpi_bus_scan_fixed(acpi_root);
@@ -2017,11 +2068,12 @@
 end:
 	if (0 != result) {
 		switch (progress) {
-		case 9:
-		case 8: remove_proc_entry("ACPI", NULL);
-		case 7: acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
-		case 6: acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
+		case 10:
+		case 9: remove_proc_entry("ACPI", NULL);
+		case 8: acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+		case 7: acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
 				ACPI_SYSTEM_NOTIFY, &acpi_bus_notify);
+		case 6:
 		case 5:
 		case 4:
 		case 3:
@@ -2085,6 +2137,9 @@
 	printk(KERN_INFO PREFIX "Core Subsystem revision %08x\n",
 		ACPI_CA_VERSION);
 
+	/* Initial core debug level excludes drivers, so include them now */
+	acpi_set_debug(ACPI_DEBUG_LOW);
+
 	if (acpi_disabled) {
 		printk(KERN_INFO PREFIX "Disabled via command line (acpi=off)\n");
 		return -ENODEV;
@@ -2143,3 +2198,4 @@
 #endif
 
 __setup("acpi=", acpi_setup);
+
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_bus.h linux-2.5.8-pre3/drivers/acpi/acpi_bus.h
--- linux-2.5.8-pre2/drivers/acpi/acpi_bus.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_bus.h	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_bus.h - ACPI Bus Driver ($Revision: 17 $)
+ *  acpi_bus.h - ACPI Bus Driver ($Revision: 19 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -96,8 +96,9 @@
 typedef int (*acpi_op_suspend)	(struct acpi_device *device, int state);
 typedef int (*acpi_op_resume)	(struct acpi_device *device, int state);
 typedef int (*acpi_op_scan)	(struct acpi_device *device);
+typedef int (*acpi_op_bind)	(struct acpi_device *device);
 
-struct acpi_driver_ops {
+struct acpi_device_ops {
 	acpi_op_add		add;
 	acpi_op_remove		remove;
 	acpi_op_lock		lock;
@@ -106,6 +107,7 @@
 	acpi_op_suspend		suspend;
 	acpi_op_resume		resume;
 	acpi_op_scan		scan;
+	acpi_op_bind		bind;
 };
 
 struct acpi_driver {
@@ -114,7 +116,7 @@
 	char			class[80];
 	int			references;
 	char			*ids;		/* Supported Hardware IDs */
-	struct acpi_driver_ops	ops;
+	struct acpi_device_ops	ops;
 };
 
 enum acpi_blacklist_predicates
@@ -157,14 +159,18 @@
 /* Flags */
 
 struct acpi_device_flags {
-	u8			dynamic_status:1;
-	u8			compatible_ids:1;
-	u8			removable:1;
-	u8			ejectable:1;
-	u8			lockable:1;
-	u8			suprise_removal_ok:1;
-	u8			power_manageable:1;
-	u8			performance_manageable:1;
+	u32			dynamic_status:1;
+	u32			hardware_id:1;
+	u32			compatible_ids:1;
+	u32			bus_address:1;
+	u32			unique_id:1;
+	u32			removable:1;
+	u32			ejectable:1;
+	u32			lockable:1;
+	u32			suprise_removal_ok:1;
+	u32			power_manageable:1;
+	u32			performance_manageable:1;
+	u32			reserved:21;
 };
 
 
@@ -206,13 +212,13 @@
 /* Power Management */
 
 struct acpi_device_power_flags {
-	u8			explicit_get:1;		     /* _PSC present? */
-	u8			power_resources:1;	   /* Power resources */
-	u8			inrush_current:1;	  /* Serialize Dx->D0 */
-	u8			wake_capable:1;		 /* Wakeup supported? */
-	u8			wake_enabled:1;		/* Enabled for wakeup */
-	u8			power_removed:1;	   /* Optimize Dx->D0 */
-	u8			reserved:2;
+	u32			explicit_get:1;		     /* _PSC present? */
+	u32			power_resources:1;	   /* Power resources */
+	u32			inrush_current:1;	  /* Serialize Dx->D0 */
+	u32			wake_capable:1;		 /* Wakeup supported? */
+	u32			wake_enabled:1;		/* Enabled for wakeup */
+	u32			power_removed:1;	   /* Optimize Dx->D0 */
+	u32			reserved:26;
 };
 
 struct acpi_device_power_state {
@@ -270,6 +276,7 @@
 	struct acpi_device_power power;
 	struct acpi_device_perf	performance;
 	struct acpi_device_dir	dir;
+	struct acpi_device_ops	ops;
 	struct acpi_driver	*driver;
 	void			*driver_data;
 #ifdef CONFIG_LDM
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_button.c linux-2.5.8-pre3/drivers/acpi/acpi_button.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_button.c	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_button.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_button.c - ACPI Button Driver ($Revision: 22 $)
+ *  acpi_button.c - ACPI Button Driver ($Revision: 24 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -69,7 +69,7 @@
 #include <linux/compatmac.h>
 #include <linux/proc_fs.h>
 
-struct proc_dir_entry		*acpi_button_dir = NULL;
+static struct proc_dir_entry	*acpi_button_dir = NULL;
 
 
 static int
@@ -81,7 +81,6 @@
 	int 			*eof,
 	void			*data)
 {
-	int			result = 0;
 	struct acpi_button	*button = (struct acpi_button *) data;
 	char			*p = page;
 	int			len = 0;
@@ -111,22 +110,42 @@
 	struct acpi_device	*device)
 {
 	struct proc_dir_entry	*entry = NULL;
+	struct acpi_button	*button = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_button_add_fs");
 
+	if (!device || !acpi_driver_data(device))
+		return_VALUE(-EINVAL);
+
+	button = acpi_driver_data(device);
+
 	if (!acpi_button_dir) {
 		acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
 		if (!acpi_button_dir)
 			return_VALUE(-ENODEV);
 	}
 
-	if (!acpi_device_dir(device)) {
-		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+	switch (button->type) {
+	case ACPI_BUTTON_TYPE_POWER:
+	case ACPI_BUTTON_TYPE_POWERF:
+		entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, 
 			acpi_button_dir);
-		if (!acpi_device_dir(device))
-			return_VALUE(-ENODEV);
+		break;
+	case ACPI_BUTTON_TYPE_SLEEP:
+	case ACPI_BUTTON_TYPE_SLEEPF:
+		entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, 
+			acpi_button_dir);
+		break;
+	case ACPI_BUTTON_TYPE_LID:
+		entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, 
+			acpi_button_dir);
+		break;
 	}
 
+	acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
+	if (!acpi_device_dir(device))
+		return_VALUE(-ENODEV);
+
 	/* 'info' [R] */
 	entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
 		S_IRUGO, acpi_device_dir(device));
@@ -227,37 +246,46 @@
 
 	button->device = device;
 	button->handle = device->handle;
-	sprintf(acpi_device_class(device), "%s", ACPI_BUTTON_CLASS);
 	acpi_driver_data(device) = button;
 
 	/*
 	 * Determine the button type (via hid), as fixed-feature buttons
 	 * need to be handled a bit differently than generic-space.
 	 */
-	if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
-		button->type = ACPI_BUTTON_TYPE_POWERF;
-		sprintf(acpi_device_name(device), "%s",
-			ACPI_BUTTON_DEVICE_NAME_POWERF);
-	}
-	else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
-		button->type = ACPI_BUTTON_TYPE_SLEEPF;
-		sprintf(acpi_device_name(device), "%s",
-			ACPI_BUTTON_DEVICE_NAME_SLEEPF);
-	}
-	else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
+	if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
 		button->type = ACPI_BUTTON_TYPE_POWER;
 		sprintf(acpi_device_name(device), "%s",
 			ACPI_BUTTON_DEVICE_NAME_POWER);
+		sprintf(acpi_device_class(device), "%s/%s", 
+			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
+	}
+	else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
+		button->type = ACPI_BUTTON_TYPE_POWERF;
+		sprintf(acpi_device_name(device), "%s",
+			ACPI_BUTTON_DEVICE_NAME_POWERF);
+		sprintf(acpi_device_class(device), "%s/%s", 
+			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
 	}
 	else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
 		button->type = ACPI_BUTTON_TYPE_SLEEP;
 		sprintf(acpi_device_name(device), "%s",
 			ACPI_BUTTON_DEVICE_NAME_SLEEP);
+		sprintf(acpi_device_class(device), "%s/%s", 
+			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
+	}
+	else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
+		button->type = ACPI_BUTTON_TYPE_SLEEPF;
+		sprintf(acpi_device_name(device), "%s",
+			ACPI_BUTTON_DEVICE_NAME_SLEEPF);
+		sprintf(acpi_device_class(device), "%s/%s", 
+			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
 	}
 	else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
 		button->type = ACPI_BUTTON_TYPE_LID;
 		sprintf(acpi_device_name(device), "%s",
 			ACPI_BUTTON_DEVICE_NAME_LID);
+		sprintf(acpi_device_class(device), "%s/%s", 
+			ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
 	}
 	else {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_drivers.h linux-2.5.8-pre3/drivers/acpi/acpi_drivers.h
--- linux-2.5.8-pre2/drivers/acpi/acpi_drivers.h	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_drivers.h	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_drivers.h  ($Revision: 17 $)
+ *  acpi_drivers.h  ($Revision: 23 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -30,7 +30,7 @@
 #include "acpi_bus.h"
 
 
-#define ACPI_DRIVER_VERSION		0x20020308
+#define ACPI_DRIVER_VERSION		0x20020404
 #define ACPI_MAX_STRING			80
 
 
@@ -84,26 +84,32 @@
    -------------------------------------------------------------------------- */
 
 #define ACPI_BUTTON_COMPONENT		0x00080000
-#define ACPI_BUTTON_CLASS		"button"
-#define ACPI_BUTTON_HID_LID		"PNP0C0D"
-#define ACPI_BUTTON_HID_POWER		"PNP0C0C"	
-#define ACPI_BUTTON_HID_POWERF		"ACPI_FPB"
-#define ACPI_BUTTON_HID_SLEEP		"PNP0C0E"
-#define ACPI_BUTTON_HID_SLEEPF		"ACPI_FSB"
 #define ACPI_BUTTON_DRIVER_NAME		"ACPI Button Driver"
-#define ACPI_BUTTON_DEVICE_NAME_POWER	"Power Button"
-#define ACPI_BUTTON_DEVICE_NAME_POWERF	"Power Button"
-#define ACPI_BUTTON_DEVICE_NAME_SLEEP	"Sleep Button"
-#define ACPI_BUTTON_DEVICE_NAME_SLEEPF	"Sleep Button"
-#define ACPI_BUTTON_DEVICE_NAME_LID	"Lid Switch"
+#define ACPI_BUTTON_CLASS		"button"
 #define ACPI_BUTTON_FILE_INFO		"info"
 #define ACPI_BUTTON_TYPE_UNKNOWN	0x00
+#define ACPI_BUTTON_NOTIFY_STATUS	0x80
+
+#define ACPI_BUTTON_SUBCLASS_POWER	"power"
+#define ACPI_BUTTON_HID_POWER		"PNP0C0C"	
+#define ACPI_BUTTON_HID_POWERF		"ACPI_FPB"
+#define ACPI_BUTTON_DEVICE_NAME_POWER	"Power Button (CM)"
+#define ACPI_BUTTON_DEVICE_NAME_POWERF	"Power Button (FF)"
 #define ACPI_BUTTON_TYPE_POWER		0x01
 #define ACPI_BUTTON_TYPE_POWERF		0x02
+
+#define ACPI_BUTTON_SUBCLASS_SLEEP	"sleep"
+#define ACPI_BUTTON_HID_SLEEP		"PNP0C0E"
+#define ACPI_BUTTON_HID_SLEEPF		"ACPI_FSB"
+#define ACPI_BUTTON_DEVICE_NAME_SLEEP	"Sleep Button (CM)"
+#define ACPI_BUTTON_DEVICE_NAME_SLEEPF	"Sleep Button (FF)"
 #define ACPI_BUTTON_TYPE_SLEEP		0x03
 #define ACPI_BUTTON_TYPE_SLEEPF		0x04
+
+#define ACPI_BUTTON_SUBCLASS_LID	"lid"
+#define ACPI_BUTTON_HID_LID		"PNP0C0D"
+#define ACPI_BUTTON_DEVICE_NAME_LID	"Lid Switch"
 #define ACPI_BUTTON_TYPE_LID		0x05
-#define ACPI_BUTTON_NOTIFY_STATUS	0x80
 
 
 /* --------------------------------------------------------------------------
@@ -217,7 +223,7 @@
 #define ACPI_PROCESSOR_LIMIT_INCREMENT	0x01
 #define ACPI_PROCESSOR_LIMIT_DECREMENT	0x02
 
-int acpi_processor_set_limit(acpi_handle handle, int flags, int *state);
+int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
 
 
 /* --------------------------------------------------------------------------
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_ec.c linux-2.5.8-pre3/drivers/acpi/acpi_ec.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_ec.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_ec.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 27 $)
+ *  acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 28 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -345,7 +345,7 @@
 	if (0 != acpi_ec_query(ec, &value))
 		return;
 
-	query_data = kmalloc(sizeof(struct acpi_ec_query_data), GFP_KERNEL);
+	query_data = kmalloc(sizeof(struct acpi_ec_query_data), GFP_ATOMIC);
 	if (!query_data)
 		return;
 	query_data->handle = ec->handle;
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_osl.c linux-2.5.8-pre3/drivers/acpi/acpi_osl.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_osl.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_osl.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_osl.c - OS-dependent functions ($Revision: 65 $)
+ *  acpi_osl.c - OS-dependent functions ($Revision: 69 $)
  *
  *  Copyright (C) 2000 Andrew Henroid
  *  Copyright (C) 2001 Andrew Grover
@@ -125,13 +125,13 @@
 }
 
 void *
-acpi_os_allocate(u32 size)
+acpi_os_allocate(ACPI_SIZE size)
 {
 	return kmalloc(size, GFP_KERNEL);
 }
 
 void *
-acpi_os_callocate(u32 size)
+acpi_os_callocate(ACPI_SIZE size)
 {
 	void *ptr = acpi_os_allocate(size);
 	if (ptr)
@@ -148,21 +148,22 @@
 
 
 acpi_status
-acpi_os_get_root_pointer(u32 flags, ACPI_PHYSICAL_ADDRESS *phys_addr)
+acpi_os_get_root_pointer(u32 flags, ACPI_POINTER *addr)
 {
 #ifndef CONFIG_ACPI_EFI
-	if (ACPI_FAILURE(acpi_find_root_pointer(flags, phys_addr))) {
+	if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
 		printk(KERN_ERR PREFIX "System description tables not found\n");
 		return AE_NOT_FOUND;
 	}
 #else /*CONFIG_ACPI_EFI*/
+	addr->pointer_type = ACPI_PHYSICAL_POINTER;
 	if (efi.acpi20)
-		*phys_addr = (ACPI_PHYSICAL_ADDRESS) efi.acpi20;
+		addr->pointer.physical = (ACPI_PHYSICAL_ADDRESS) efi.acpi20;
 	else if (efi.acpi)
-		*phys_addr = (ACPI_PHYSICAL_ADDRESS) efi.acpi;
+		addr->pointer.physical = (ACPI_PHYSICAL_ADDRESS) efi.acpi;
 	else {
 		printk(KERN_ERR PREFIX "System description tables not found\n");
-		*phys_addr = 0;
+		addr->pointer.physical = 0;
 		return AE_NOT_FOUND;
 	}
 #endif /*CONFIG_ACPI_EFI*/
@@ -171,7 +172,7 @@
 }
 
 acpi_status
-acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, u32 size, void **virt)
+acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size, void **virt)
 {
 	if (phys > ULONG_MAX) {
 		printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -189,7 +190,7 @@
 }
 
 void
-acpi_os_unmap_memory(void *virt, u32 size)
+acpi_os_unmap_memory(void *virt, ACPI_SIZE size)
 {
 	iounmap(virt);
 }
@@ -441,14 +442,14 @@
 	ACPI_FUNCTION_TRACE ("os_load_module");
 
 	if (!module_name)
-		return AE_BAD_PARAMETER;
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 
 	if (0 > request_module(module_name)) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to load module [%s].\n", module_name));
-		return AE_ERROR;
+		return_ACPI_STATUS (AE_ERROR);
 	}
 
-	return AE_OK;
+	return_ACPI_STATUS (AE_OK);
 }
 
 acpi_status
@@ -481,7 +482,7 @@
 	strcpy(current->comm, "kacpidpc");
 
 	if (!dpc || !dpc->function)
-		return AE_BAD_PARAMETER;
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Executing function [%p(%p)].\n", dpc->function, dpc->context));
 
@@ -489,7 +490,7 @@
 
 	kfree(dpc);
 
-	return 1;
+	return_ACPI_STATUS (AE_OK);
 }
 
 static void
@@ -504,7 +505,7 @@
 	dpc = (ACPI_OS_DPC*)context;
 	if (!dpc) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
-		return;
+		return_VOID;
 	}
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating new thread to run function [%p(%p)].\n", dpc->function, dpc->context));
@@ -515,6 +516,7 @@
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to kernel_thread() failed.\n"));
 		acpi_os_free(dpc);
 	}
+    return_VOID;
 }
 
 acpi_status
@@ -531,7 +533,7 @@
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Scheduling function [%p(%p)] for deferred execution.\n", function, context));
 
 	if (!function)
-		return AE_BAD_PARAMETER;
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 
 	/*
 	 * Queue via DPC:
@@ -554,7 +556,7 @@
 		 */
 		dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_ATOMIC);
 		if (!dpc)
-			return AE_NO_MEMORY;
+			return_ACPI_STATUS (AE_NO_MEMORY);
 
 		dpc->function = function;
 		dpc->context = context;
@@ -578,7 +580,7 @@
 		 */
 		dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_KERNEL);
 		if (!dpc)
-			return AE_NO_MEMORY;
+			return_ACPI_STATUS (AE_NO_MEMORY);
 
 		dpc->function = function;
 		dpc->context = context;
@@ -587,7 +589,7 @@
 		break;
 	}
 
-	return status;
+	return_ACPI_STATUS (status);
 }
 
 
@@ -603,7 +605,7 @@
 
 	sem = acpi_os_callocate(sizeof(struct semaphore));
 	if (!sem)
-		return AE_NO_MEMORY;
+		return_ACPI_STATUS (AE_NO_MEMORY);
 
 	sema_init(sem, initial_units);
 
@@ -611,7 +613,7 @@
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating semaphore[%p|%d].\n", *handle, initial_units));
 
-	return AE_OK;
+	return_ACPI_STATUS (AE_OK);
 }
 
 
@@ -631,13 +633,13 @@
 	ACPI_FUNCTION_TRACE ("os_delete_semaphore");
 
 	if (!sem)
-		return AE_BAD_PARAMETER;
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting semaphore[%p].\n", handle));
 
 	acpi_os_free(sem); sem =  NULL;
 
-	return AE_OK;
+	return_ACPI_STATUS (AE_OK);
 }
 
 
@@ -663,10 +665,10 @@
 	ACPI_FUNCTION_TRACE ("os_wait_semaphore");
 
 	if (!sem || (units < 1))
-		return AE_BAD_PARAMETER;
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 
 	if (units > 1)
-		return AE_SUPPORT;
+		return_ACPI_STATUS (AE_SUPPORT);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout));
 
@@ -724,7 +726,7 @@
 		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Acquired semaphore[%p|%d|%d]\n", handle, units, timeout));
 	}
 
-	return status;
+	return_ACPI_STATUS (status);
 }
 
 
@@ -741,16 +743,16 @@
 	ACPI_FUNCTION_TRACE ("os_signal_semaphore");
 
 	if (!sem || (units < 1))
-		return AE_BAD_PARAMETER;
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 
 	if (units > 1)
-		return AE_SUPPORT;
+		return_ACPI_STATUS (AE_SUPPORT);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Signaling semaphore[%p|%d]\n", handle, units));
 
 	up(sem);
 
-	return AE_OK;
+	return_ACPI_STATUS (AE_OK);
 }
 
 u32
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_pci_link.c linux-2.5.8-pre3/drivers/acpi/acpi_pci_link.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_pci_link.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_pci_link.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 19 $)
+ *  acpi_pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 22 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -92,35 +92,23 @@
    -------------------------------------------------------------------------- */
 
 static int
-acpi_pci_link_get_current (
+acpi_pci_link_get_possible (
 	struct acpi_pci_link	*link)
 {
-	int			result = 0;
+	int                     result = 0;
 	acpi_status		status = AE_OK;
-	acpi_buffer		buffer = {0, NULL};
+	acpi_buffer		buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	acpi_resource		*resource = NULL;
+	int			i = 0;
 
-	ACPI_FUNCTION_TRACE("acpi_pci_link_get_current");
+	ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible");
 
-	if (!link || !link->handle)
+	if (!link)
 		return_VALUE(-EINVAL);
 
-	link->irq.active = 0;
-
-	status = acpi_get_current_resources(link->handle, &buffer);
-	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
-		return_VALUE(-ENODEV);
-	}
-
-	buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
-	if (!buffer.pointer)
-		return_VALUE(-ENOMEM);
-	memset(buffer.pointer, 0, buffer.length);
-
-	status = acpi_get_current_resources(link->handle, &buffer);
-	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
+	status = acpi_get_possible_resources(link->handle, &buffer);
+	if (ACPI_FAILURE(status) || !buffer.pointer) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -131,69 +119,84 @@
 	case ACPI_RSTYPE_IRQ:
 	{
 		acpi_resource_irq *p = &resource->data.irq;
-		if (p->number_of_interrupts > 0)
-			link->irq.active = p->interrupts[0];
-		else {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Blank IRQ resource\n"));
+
+		if (!p || !p->number_of_interrupts) {
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN, 
+				"Blank IRQ resource\n"));
 			result = -ENODEV;
 			goto end;
 		}
+
+		for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
+			link->irq.possible[i] = p->interrupts[i];
+			link->irq.possible_count++;
+		}
+
+		link->irq.flags.trigger = p->edge_level;
+		link->irq.flags.polarity = p->active_high_low;
+		link->irq.flags.shareable = p->shared_exclusive;
+
 		break;
 	}
 	case ACPI_RSTYPE_EXT_IRQ:
 	{
 		acpi_resource_ext_irq *p = &resource->data.extended_irq;
-		if (p->number_of_interrupts > 0)
-			link->irq.active = p->interrupts[0];
-		else {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Blank IRQ resource\n"));
+
+		if (!p || !p->number_of_interrupts) {
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN, 
+				"Blank IRQ resource\n"));
 			result = -ENODEV;
 			goto end;
 		}
+
+		for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
+			link->irq.possible[i] = p->interrupts[i];
+			link->irq.possible_count++;
+		}
+
+		link->irq.flags.trigger = p->edge_level;
+		link->irq.flags.polarity = p->active_high_low;
+		link->irq.flags.shareable = p->shared_exclusive;
+
 		break;
 	}
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
-			"First resource is not an IRQ entry\n"));
+			"Resource is not an IRQ entry\n"));
+		result = -ENODEV;
+		goto end;
 		break;
 	}
+	
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Found %d possible IRQs\n", link->irq.possible_count));
 
 end:
 	kfree(buffer.pointer);
 
-	return_VALUE(0);
+	return_VALUE(result);
 }
 
 
 static int
-acpi_pci_link_get_possible (
+acpi_pci_link_get_current (
 	struct acpi_pci_link	*link)
 {
-	int                     result = 0;
+	int			result = 0;
 	acpi_status		status = AE_OK;
-	acpi_buffer		buffer = {0, NULL};
+	acpi_buffer		buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	acpi_resource		*resource = NULL;
-	int			i = 0;
 
-	ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible");
+	ACPI_FUNCTION_TRACE("acpi_pci_link_get_current");
 
-	if (!link)
+	if (!link || !link->handle)
 		return_VALUE(-EINVAL);
 
-	status = acpi_get_possible_resources(link->handle, &buffer);
-	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
-		return_VALUE(-ENODEV);
-	}
-
-	buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
-	if (!buffer.pointer)
-		return_VALUE(-ENOMEM);
-	memset(buffer.pointer, 0, buffer.length);
+	link->irq.active = 0;
 
-	status = acpi_get_possible_resources(link->handle, &buffer);
+	status = acpi_get_current_resources(link->handle, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -205,20 +208,14 @@
 	{
 		acpi_resource_irq *p = &resource->data.irq;
 
-		for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
-			link->irq.possible[i] = p->interrupts[i];
-			link->irq.possible_count++;
-		}
-
-		if (!p->number_of_interrupts) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Blank IRQ resource\n"));
+		if (!p || !p->number_of_interrupts) {
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN, 
+				"Blank IRQ resource\n"));
 			result = -ENODEV;
 			goto end;
 		}
 
-		link->irq.flags.trigger = p->edge_level;
-		link->irq.flags.polarity = p->active_high_low;
-		link->irq.flags.shareable = p->shared_exclusive;
+		link->irq.active = p->interrupts[0];
 
 		break;
 	}
@@ -226,32 +223,36 @@
 	{
 		acpi_resource_ext_irq *p = &resource->data.extended_irq;
 
-		for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
-			link->irq.possible[i] = p->interrupts[i];
-			link->irq.possible_count++;
-		}
-
-		if (!p->number_of_interrupts) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Blank IRQ resource\n"));
+		if (!p || !p->number_of_interrupts) {
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+				"Blank IRQ resource\n"));
 			result = -ENODEV;
 			goto end;
 		}
 
-		link->irq.flags.trigger = p->edge_level;
-		link->irq.flags.polarity = p->active_high_low;
-		link->irq.flags.shareable = p->shared_exclusive;
+		link->irq.active = p->interrupts[0];
 
 		break;
 	}
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
-			"First resource is not an IRQ entry\n"));
+			"Resource is not an IRQ entry\n"));
 		break;
 	}
 
+	if (!link->irq.active) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Invalid IRQ %d\n", link->irq.active));
+		result = -ENODEV;
+	}
+
 end:
 	kfree(buffer.pointer);
 
+	if (0 == result)
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n",
+			link->irq.active));
+	
 	return_VALUE(result);
 }
 
@@ -259,7 +260,7 @@
 static int
 acpi_pci_link_set (
 	struct acpi_pci_link	*link,
-	u32			irq)
+	int			irq)
 {
 	acpi_status		status = AE_OK;
 	struct {
@@ -290,6 +291,8 @@
 		return_VALUE(-ENODEV);
 	}
 
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", irq));
+	
 	return_VALUE(0);
 }
 
@@ -328,8 +331,10 @@
 		return_VALUE(-ENODEV);
 	}
 
-	if (!link->irq.flags.valid) 
+	if (!link->irq.flags.valid) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link IRQ invalid\n"));
 		return_VALUE(-ENODEV);
+	}
 
 	/* TBD: Support multiple index (IRQ) entries per Link Device */
 	if (0 != entry->source.index) {
@@ -361,7 +366,7 @@
 	if (!entry || !entry->source.handle || !irq)
 		return_VALUE(-EINVAL);
 
-	/* TBD: Support multiple index values (not just first). */
+	/* TBD: Support multiple index (IRQ) entries per Link Device */
 	if (0 != entry->source.index) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
 			"Unsupported resource index [%d]\n", 
@@ -386,7 +391,8 @@
 
 	/* Is the target IRQ the same as the currently enabled IRQ? */
 	if (link->irq.flags.enabled && (irq == link->irq.active)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link IRQ already at target\n"));
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link already at IRQ %d\n",
+			irq));
 		return_VALUE(0);
 	}
 
@@ -413,6 +419,85 @@
 }
 
 
+static int
+acpi_pci_link_enable (
+	struct acpi_device	*device,
+	struct acpi_pci_link	*link)
+{
+	int			result = -ENODEV;
+
+	ACPI_FUNCTION_TRACE("acpi_pci_link_enable");
+
+	if (!device || !link)
+		return_VALUE(-EINVAL);
+
+	result = acpi_pci_link_get_possible(link);
+	if (0 != result)
+		return_VALUE(result);
+
+	result = acpi_bus_get_status(device);
+	if (0 != result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	/*
+	 * If this link device isn't enabled (_STA bit 1) then we enable it
+	 * by setting an IRQ.
+	 */
+	if (!device->status.enabled) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"Attempting to enable at IRQ [%d]\n", 
+			link->irq.possible[0]));
+
+		result = acpi_pci_link_set(link, link->irq.possible[0]);
+		if (0 != result)
+			return_VALUE(result);
+
+		result = acpi_bus_get_status(device);
+		if (0 != result) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+				"Unable to read status\n"));
+			return_VALUE(-ENODEV);
+		}
+
+		if (!device->status.enabled) {
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Enable failed\n"));
+			return_VALUE(-ENODEV);
+		}
+
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link enabled at IRQ %d\n", 
+			link->irq.possible[0]));
+	}
+
+	/*
+	 * Now we get the current IRQ just to make sure everything is kosher.
+	 */
+	result = acpi_pci_link_get_current(link);
+	if (0 != result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_WARN, 
+			"Current IRQ invalid, setting to default\n"));
+
+		result = acpi_pci_link_set(link, link->irq.possible[0]);
+		if (0 != result)
+			return_VALUE(result);
+
+		result = acpi_pci_link_get_current(link);
+		if (0 != result) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+				"Unable to read current IRQ\n"));
+			return_VALUE(result);
+		}
+	}
+
+  	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Using IRQ %d\n", link->irq.active));
+
+	link->irq.flags.valid = 1;
+
+	return_VALUE(0);
+}
+
+
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -440,34 +525,9 @@
 	sprintf(acpi_device_class(device), "%s", ACPI_PCI_LINK_CLASS);
 	acpi_driver_data(device) = link;
 
-	result = acpi_pci_link_get_possible(link);
-	if (0 != result)
-		return_VALUE(result);
-
-	if (!device->status.enabled) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Enabling at IRQ [%d]\n",
-			link->irq.possible[0]));
-
-		result = acpi_pci_link_set(link, link->irq.possible[0]);
-		if (0 != result)
-			return_VALUE(result);
-
-		result = acpi_bus_get_status(device);
-		if (0 != result)
-			return_VALUE(result);
-
-		if (!device->status.enabled) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
-				"Enable failed\n"));
-			return_VALUE(-EFAULT);
-		}
-	}
-
-	result = acpi_pci_link_get_current(link);
+	result = acpi_pci_link_enable(device, link);
 	if (0 != result)
-		return_VALUE(result);
-
-	link->irq.flags.valid = 1;
+		goto end;
 
 	printk(PREFIX "%s [%s] (IRQs", 
 		acpi_device_name(device), acpi_device_bid(device));
@@ -477,7 +537,11 @@
 			link->irq.possible[i]);
 	printk(")\n");
 
-	return_VALUE(0);
+end:
+	if (0 != result)
+		kfree(link);
+
+	return_VALUE(result);
 }
 
 
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_pci_root.c linux-2.5.8-pre3/drivers/acpi/acpi_pci_root.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_pci_root.c	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_pci_root.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 22 $)
+ *  acpi_pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 30 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -48,6 +48,7 @@
 
 static int acpi_pci_root_add (struct acpi_device *device);
 static int acpi_pci_root_remove (struct acpi_device *device, int type);
+static int acpi_pci_root_bind (struct acpi_device *device);
 
 static struct acpi_driver acpi_pci_root_driver = {
         name:                   ACPI_PCI_ROOT_DRIVER_NAME,
@@ -56,20 +57,20 @@
         ops:                    {
                                         add:    acpi_pci_root_add,
                                         remove: acpi_pci_root_remove,
+					bind:	acpi_pci_root_bind,
                                 },
 };
 
-struct acpi_pci_root_context {
-	acpi_handle		handle;
-	struct {
-		u8			seg;	/* Root's segment number */
-		u8			bus;	/* Root's bus number */
-		u8			sub;	/* Max subordinate bus */
-	}			id;
-	struct pci_bus		*bus;
+struct acpi_pci_data {
+	acpi_pci_id		id;
 	struct pci_dev		*dev;
 };
 
+struct acpi_pci_root {
+	acpi_handle		handle;
+	struct acpi_pci_data	data;
+};
+
 struct acpi_prt_list		acpi_prts;
 
 
@@ -77,25 +78,33 @@
                         PCI Routing Table (PRT) Support
    -------------------------------------------------------------------------- */
 
-static struct acpi_prt_entry *
+static int
 acpi_prt_find_entry (
-	struct pci_dev		*dev,
-	u8			pin)
+	acpi_pci_id		*id,
+	u8			pin,
+	struct acpi_prt_entry	**entry)
 {
-	struct acpi_prt_entry	*entry = NULL;
 	struct list_head	*node = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_prt_find_entry");
 
+	if (!id || !entry)
+		return_VALUE(-ENODEV);
+
 	/* TBD: Locking */
 	list_for_each(node, &acpi_prts.entries) {
-		entry = list_entry(node, struct acpi_prt_entry, node);
-		if ((entry->id.dev == PCI_SLOT(dev->devfn)) 
-			&& (entry->id.pin == pin))
-			return_PTR(entry);
+		(*entry) = list_entry(node, struct acpi_prt_entry, node);
+		/* TBD: Include check for segment when supported by pci_dev */
+		if ((id->bus == (*entry)->id.bus) 
+			&& (id->device == (*entry)->id.dev)
+			&& (pin == (*entry)->id.pin)) {
+			return_VALUE(0);
+		}
 	}
 
-	return_PTR(NULL);
+	(*entry) = NULL;
+
+	return_VALUE(-ENODEV);
 }
 
 
@@ -107,23 +116,49 @@
 {
 	int			result = 0;
 	struct acpi_prt_entry	*entry = NULL;
+	acpi_pci_id		id = {0, 0, 0, 0};
 
-	ACPI_FUNCTION_TRACE("acpi_pci_get_current_irq");
+	ACPI_FUNCTION_TRACE("acpi_prt_get_irq");
 
 	if (!dev || !irq)
 		return_VALUE(-ENODEV);
 
-	entry = acpi_prt_find_entry(dev, pin);
-	if (!entry)
-		return_VALUE(-ENODEV);
+	if (!dev->bus) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Device has invalid 'bus' field\n"));
+		return_VALUE(-EFAULT);
+	}
+
+	id.segment = 0;
+	id.bus = dev->bus->number;
+	id.device = PCI_SLOT(dev->devfn);
+	id.function = PCI_FUNC(dev->devfn);
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Resolving IRQ for %02x:%02x:%02x.%02x[%c]\n",
+		id.segment, id.bus, id.device, id.function, ('A'+pin)));
+
+	result = acpi_prt_find_entry(&id, pin, &entry);
+	if (0 != result)
+		return_VALUE(result);
 
 	/* Type 1: Dynamic (e.g. PCI Link Device) */
 	if (entry->source.handle)
 		result = acpi_pci_link_get_irq(entry, irq);
+
 	/* Type 2: Static (e.g. I/O [S]APIC Direct) */
-	else
-		*irq = entry->source.index;
+	else {
+		if (entry->source.index)
+			*irq = entry->source.index;
+		else
+			result = -ENODEV;
+	}
 	
+	if (0 == result)
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", *irq));
+	else
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to reslove IRQ\n"));
+
 	return_VALUE(0);
 }
 
@@ -135,18 +170,32 @@
 	int			irq)
 {
 	int			result = 0;
-	int			i = 0;
-	int			valid = 0;
 	struct acpi_prt_entry	*entry = NULL;
+	acpi_pci_id		id = {0, 0, 0, 0};
 
-	ACPI_FUNCTION_TRACE("acpi_pci_set_current_irq");
+	ACPI_FUNCTION_TRACE("acpi_pci_set_irq");
 
 	if (!dev || !irq)
 		return_VALUE(-EINVAL);
 
-	entry = acpi_prt_find_entry(dev, pin);
-	if (!entry)
-		return_VALUE(-ENODEV);
+	if (!dev->bus) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Device has invalid 'bus' field\n"));
+		return_VALUE(-EFAULT);
+	}
+
+	id.segment = 0;
+	id.bus = dev->bus->number;
+	id.device = PCI_SLOT(dev->devfn);
+	id.function = PCI_FUNC(dev->devfn);
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Setting %02x:%02x:%02x.%02x[%c] to IRQ%d\n",
+		id.segment, id.bus, id.device, id.function, ('A'+pin), irq));
+
+	result = acpi_prt_find_entry(&id, pin, &entry);
+	if (0 != result)
+		return_VALUE(result);
 
 	/* Type 1: Dynamic (e.g. PCI Link Device) */
 	if (entry->source.handle)
@@ -155,6 +204,11 @@
 	else
 		result = -EFAULT;
 	
+	if (0 == result)
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "IRQ set\n"));
+	else
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set IRQ\n"));
+
 	return_VALUE(result);
 }
 
@@ -212,9 +266,9 @@
 	 *       namespace).
 	 */
 
-	printk(KERN_INFO "      %02X:%02X:%02X[%c] -> %s[%d]\n", 
+	ACPI_DEBUG_PRINT_RAW((ACPI_DB_OK, "      %02X:%02X:%02X[%c] -> %s[%d]\n", 
 		entry->id.seg, entry->id.bus, entry->id.dev, 
-		('A' + entry->id.pin), prt->source, entry->source.index);
+		('A' + entry->id.pin), prt->source, entry->source.index));
 
 	/* TBD: Acquire/release lock */
 	list_add_tail(&entry->node, &acpi_prts.entries);
@@ -225,57 +279,23 @@
 }
 
 
-static acpi_status
-acpi_prt_callback (
-	acpi_handle             handle,
-	u32                     nesting_level,
-	void                    *context,
-	void                    **return_value)
+static int
+acpi_prt_parse (
+	acpi_handle		handle,
+	u8			seg,
+	u8			bus)
 {
 	acpi_status		status = AE_OK;
-	acpi_handle		prt_handle = NULL;
 	char			pathname[PATHNAME_MAX] = {0};
 	acpi_buffer		buffer = {0, NULL};
 	acpi_pci_routing_table	*prt = NULL;
-	unsigned long		sta = 0;
-	struct acpi_pci_root_context *root = (struct acpi_pci_root_context *) context;
-	u8			bus_number = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_prt_callback");
 
-	if (!root)
-		return_VALUE(AE_BAD_PARAMETER);
-
-	status = acpi_get_handle(handle, METHOD_NAME__PRT, &prt_handle);
-	if (ACPI_FAILURE(status))
-		return_VALUE(AE_OK);
+	ACPI_FUNCTION_TRACE("acpi_prt_parse");
 
 	buffer.length = sizeof(pathname);
 	buffer.pointer = pathname;
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
-	/* 
-	 * Evalute _STA to see if the device containing this _PRT is present.
-	 */
-	status = acpi_evaluate_integer(handle, METHOD_NAME__STA, NULL, &sta);
-	switch (status) {
-	case AE_OK:
-		if (!(sta & 0x01)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				"Found _PRT but device [%s] not present\n", 
-				pathname));
-			return_VALUE(AE_OK);
-		}
-		break;
-	case AE_NOT_FOUND:
-		/* assume present */
-		break;
-	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating %s._STA [%s]\n", 
-			pathname, acpi_format_exception(status)));
-		return_VALUE(status);
-	}
-
 	printk(KERN_INFO PREFIX "%s [%s._PRT]\n", ACPI_PCI_PRT_DEVICE_NAME, 
 		pathname);
 
@@ -287,9 +307,10 @@
 	buffer.pointer = NULL;
 	status = acpi_get_irq_routing_table(handle, &buffer);
 	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PRT [%s]\n", 
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Error evaluating _PRT [%s]\n",
 			acpi_format_exception(status)));
-		return_VALUE(status);
+		return_VALUE(-ENODEV);
 	}
 
 	prt = kmalloc(buffer.length, GFP_KERNEL);
@@ -300,144 +321,401 @@
 
 	status = acpi_get_irq_routing_table(handle, &buffer);
 	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PRT [%s]\n", 
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Error evaluating _PRT [%s]\n",
 			acpi_format_exception(status)));
 		kfree(buffer.pointer);
-		return_VALUE(status);
-	}
-
-	if (root->handle == handle)
-		bus_number = root->id.bus;
-	else {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Need to get subordinate bus number!\n"));
-		/* get the bus number for this device */
+		return_VALUE(-ENODEV);
 	}
 
 	while (prt && (prt->length > 0)) {
-		acpi_prt_add_entry(handle, root->id.seg, bus_number, prt);
+		acpi_prt_add_entry(handle, seg, bus, prt);
 		prt = (acpi_pci_routing_table*)((unsigned long)prt + prt->length);
 	}
 
-	return_VALUE(AE_OK);
+	return_VALUE(0);
 }
 
 
 /* --------------------------------------------------------------------------
-                                Driver Interface
+                             PCI Device Binding
    -------------------------------------------------------------------------- */
 
-int
-acpi_pci_root_add (
+static void
+acpi_pci_data_handler (
+	acpi_handle		handle,
+	u32			function,
+	void			*context)
+{
+	ACPI_FUNCTION_TRACE("acpi_pci_data_handler");
+
+	/* TBD: Anything we need to do here? */
+
+	return_VOID;
+}
+
+
+/**
+ * acpi_os_get_pci_id
+ * ------------------
+ * This function gets used by the ACPI Interpreter (a.k.a. Core Subsystem)
+ * to resolve PCI information for ACPI-PCI devices defined in the namespace.
+ */
+acpi_status
+acpi_os_get_pci_id (
+	acpi_handle		handle,
+	acpi_pci_id		*id)
+{
+	int			result = 0;
+	acpi_status		status = AE_OK;
+	struct acpi_device	*device = NULL;
+	struct acpi_pci_data	*data = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_os_get_pci_id");
+
+	if (!id)
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+	result = acpi_bus_get_device(handle, &device);
+	if (0 != result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Invalid ACPI Bus context for device %s\n",
+			acpi_device_bid(device)));
+		return_ACPI_STATUS(AE_NOT_EXIST);
+	}
+
+	status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data);
+	if (ACPI_FAILURE(status) || !data || !data->dev) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Invalid ACPI-PCI context for device %s\n",
+			acpi_device_bid(device)));
+		return_ACPI_STATUS(status);
+	}
+	
+	id->segment = data->id.segment;
+	id->bus = data->id.bus;
+	id->device = data->id.device;
+	id->function = data->id.function;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Device %s has PCI address %02x:%02x:%02x.%02x\n", 
+		acpi_device_bid(device), id->segment, id->bus, 
+		id->device, id->function));
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+	
+static int
+acpi_pci_root_bind (
 	struct acpi_device	*device)
 {
+	int			result = 0;
 	acpi_status		status = AE_OK;
-	struct acpi_pci_root_context *context = NULL;
-	unsigned long		temp = 0;
+	struct acpi_pci_data	*data = NULL;
+	struct acpi_pci_data	*parent_data = NULL;
+	acpi_handle		handle = NULL;
 
-	ACPI_FUNCTION_TRACE("acpi_pci_root_add");
+	ACPI_FUNCTION_TRACE("acpi_pci_root_bind");
 
-	if (!device)
+	if (!device || !device->parent)
 		return_VALUE(-EINVAL);
 
-	context = kmalloc(sizeof(struct acpi_pci_root_context), GFP_KERNEL);
-	if (!context)
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Attempting to bind PCI device %s.%s\n", 
+		acpi_device_bid(device->parent), acpi_device_bid(device)));
+
+	data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
+	if (!data)
 		return_VALUE(-ENOMEM);
-	memset(context, 0, sizeof(struct acpi_pci_root_context));
+	memset(data, 0, sizeof(struct acpi_pci_data));
 
-	context->handle = device->handle;
-	sprintf(acpi_device_name(device), "%s", ACPI_PCI_ROOT_DEVICE_NAME);
-	sprintf(acpi_device_class(device), "%s", ACPI_PCI_ROOT_CLASS);
-	acpi_driver_data(device) = context;
+	/* 
+	 * Segment & Bus
+	 * -------------
+	 * These are obtained via the parent device's ACPI-PCI context..
+	 * Note that PCI root bridge devices don't have a 'dev->subordinate'.
+	 */
+	status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, 
+		(void**) &parent_data);
+	if (ACPI_FAILURE(status) || !parent_data || !parent_data->dev) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Invalid ACPI-PCI context for parent device %s\n",
+			acpi_device_bid(device->parent)));
+		result = -ENODEV;
+		goto end;
+	}
 
-	status = acpi_evaluate_integer(context->handle, METHOD_NAME__SEG, 
-		NULL, &temp);
-	if (ACPI_SUCCESS(status))
-		context->id.seg = temp;
-	else
-		context->id.seg = 0;
+	data->id.segment = parent_data->id.segment;
 
-	status = acpi_evaluate_integer(context->handle, METHOD_NAME__BBN, 
-		NULL, &temp);
-	if (ACPI_SUCCESS(status))
-		context->id.bus = temp;
-	else
-		context->id.bus = 0;
+	if (parent_data->dev->subordinate)	       /* e.g. PCI-PCI bridge */
+		data->id.bus = parent_data->dev->subordinate->number;
+	else if (parent_data->dev->bus)			   /* PCI root bridge */
+		data->id.bus = parent_data->dev->bus->number;
+	else {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Parent device %s is not a PCI bridge\n",
+			acpi_device_bid(device->parent)));
+		result = -ENODEV;
+		goto end;
+	}
 
-	/* TBD: Evaluate _CRS for bus range of child P2P (bus min/max/len) */
+	/*
+	 * Device & Function
+	 * -----------------
+	 * These are simply obtained from the device's _ADR method.  Note
+	 * that a value of zero is valid.
+	 */
+	data->id.device = device->pnp.bus_address >> 16;
+	data->id.function = device->pnp.bus_address & 0xFFFF;
 
-	printk(KERN_INFO PREFIX "%s [%s] (%02x:%02x)\n", 
-		acpi_device_name(device), acpi_device_bid(device),
-		context->id.seg, context->id.bus);
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Binding device %s.%s to %02x:%02x:%02x.%02x\n", 
+		acpi_device_bid(device->parent), acpi_device_bid(device), 
+		data->id.segment, data->id.bus, data->id.device, 
+		data->id.function));
+
+	/* 
+	 * Locate PCI Device
+	 * -----------------
+	 * Locate matching device in PCI namespace.  If it doesn't exist
+	 * this typically means that the device isn't currently inserted
+	 * (e.g. docking station, port replicator, etc.).
+	 */
+	data->dev = pci_find_slot(data->id.bus, 
+		PCI_DEVFN(data->id.device, data->id.function));
+	if (!data->dev) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
+			data->id.segment, data->id.bus, 
+			data->id.device, data->id.function));
+		result = -ENODEV;
+		goto end;
+	}
+	if (!data->dev->bus) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Device %02x:%02x:%02x.%02x has invalid 'bus' field\n",
+			data->id.segment, data->id.bus, 
+			data->id.device, data->id.function));
+		result = -ENODEV;
+		goto end;
+	}
 
 	/*
-	 * Scan all devices on this root bridge.  Note that this must occur
-	 * now to get the correct bus number assignments for subordinate
-	 * PCI-PCI bridges.
+	 * Attach ACPI-PCI Context
+	 * -----------------------
+	 * Thus binding the ACPI and PCI devices.
 	 */
-	pci_scan_bus(context->id.bus, pci_root_ops, NULL);
+	status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Unable to attach ACPI-PCI context to device %s\n",
+			acpi_device_bid(device)));
+		result = -ENODEV;
+		goto end;
+	}
 
-	/* Evaluate _PRT for this root bridge. */
-	acpi_prt_callback(context->handle, 0, context, NULL);
+	/*
+	 * PCI Bridge?
+	 * -----------
+	 * If so, install the 'bind' function to facilitate callbacks for
+	 * all of its children.
+	 */
+	if (data->dev->subordinate)
+		device->ops.bind = acpi_pci_root_bind;
 
-	/* Evaluate all subordinate _PRTs. */
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, context->handle, ACPI_UINT32_MAX, 
-		acpi_prt_callback, context, NULL);
+	/*
+	 * PCI Routing Table
+	 * -----------------
+	 * Evaluate and parse _PRT, if exists.  This code is independent of 
+	 * PCI bridges (above) to allow parsing of _PRT objects within the
+	 * scope of non-bridge devices.  Note that _PRTs within the scope of
+	 * a PCI bridge assume the bridge's subordinate bus number.
+	 *
+	 * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
+	 */
+	status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
+	if (ACPI_SUCCESS(status)) {
+		if (data->dev->subordinate)		    /* PCI-PCI bridge */
+			acpi_prt_parse(device->handle, data->id.segment, 
+				data->dev->subordinate->number);
+		else				     /* non-bridge PCI device */
+			acpi_prt_parse(device->handle, data->id.segment,
+				data->id.bus);
+	}
 
-	return_VALUE(0);
+end:
+	if (0 != result)
+		kfree(data);
+
+	return_VALUE(result);
 }
 
 
-int
-acpi_pci_root_remove (
-	struct acpi_device	*device,
-	int			type)
+/* --------------------------------------------------------------------------
+                                Driver Interface
+   -------------------------------------------------------------------------- */
+
+static int
+acpi_pci_root_add (
+	struct acpi_device	*device)
 {
-	struct acpi_pci_dev_context *context = NULL;
+	int			result = 0;
+	struct acpi_pci_root	*root = NULL;
+	acpi_status		status = AE_OK;
+	unsigned long		value = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_pci_root_add");
 
 	if (!device)
-		return -EINVAL;
+		return_VALUE(-EINVAL);
 
-	if (device->driver_data)
-		/* Root bridge */
-		kfree(device->driver_data);
-	else {
-		/* Standard PCI device */
-		context = acpi_driver_data(device);
-		if (context)
-			kfree(context);
+	root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
+	if (!root)
+		return_VALUE(-ENOMEM);
+	memset(root, 0, sizeof(struct acpi_pci_root));
+
+	root->handle = device->handle;
+	sprintf(acpi_device_name(device), "%s", ACPI_PCI_ROOT_DEVICE_NAME);
+	sprintf(acpi_device_class(device), "%s", ACPI_PCI_ROOT_CLASS);
+	acpi_driver_data(device) = root;
+
+	/*
+	 * TBD: Doesn't the bus driver automatically set this?
+	 */
+	device->ops.bind = acpi_pci_root_bind;
+
+	/* 
+	 * Segment
+	 * -------
+	 * Obtained via _SEG, if exists, otherwise assumed to be zero (0).
+	 */
+	status = acpi_evaluate_integer(root->handle, METHOD_NAME__SEG, NULL, 
+		&value);
+	switch (status) {
+	case AE_OK:
+		root->data.id.segment = (u16) value;
+		break;
+	case AE_NOT_FOUND:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming segment 0 (no _SEG)\n"));
+		root->data.id.segment = 0;
+		break;
+	default:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SEG\n"));
+		result = -ENODEV;
+		goto end;
 	}
 
-	return 0;
-}
+	/* 
+	 * Bus
+	 * ---
+	 * Obtained via _BBN, if exists, otherwise assumed to be zero (0).
+	 */
+	status = acpi_evaluate_integer(root->handle, METHOD_NAME__BBN, NULL, 
+		&value);
+	switch (status) {
+	case AE_OK:
+		root->data.id.bus = (u16) value;
+		break;
+	case AE_NOT_FOUND:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n"));
+		root->data.id.bus = 0;
+		break;
+	default:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BBN\n"));
+		result = -ENODEV;
+		goto end;
+	}
 
+	/*
+	 * Device & Function
+	 * -----------------
+	 * Obtained from _ADR (which has already been evaluated for us).
+	 */
+	root->data.id.device = device->pnp.bus_address >> 16;
+	root->data.id.function = device->pnp.bus_address & 0xFFFF;
 
-int __init 
-acpi_pci_irq_init (void)
-{
-	int			result = 0;
-	acpi_status		status = AE_OK;
-	acpi_object		arg = {ACPI_TYPE_INTEGER};
-	acpi_object_list        arg_list = {1, &arg};
-	int			irq_model = 0;
+	/*
+	 * TBD: Evaluate _CRS to get root bridge resources
+	 * TBD: Need PCI interface for enumeration/configuration of roots.
+	 */
+
+	printk(KERN_INFO PREFIX "%s [%s] (%02x:%02x:%02x.%02x)\n", 
+		acpi_device_name(device), acpi_device_bid(device),
+		root->data.id.segment, root->data.id.bus, 
+		root->data.id.device, root->data.id.function);
 
-	ACPI_FUNCTION_TRACE("acpi_pci_irq_init");
+	/*
+	 * Scan the Root Bridge
+	 * --------------------
+	 * Must do this prior to any attempt to bind the root device, as the
+	 * PCI namespace does not get created until this call is made (and 
+	 * thus the root bridge's pci_dev does not exist).
+	 */
+	pci_scan_bus(root->data.id.bus, pci_root_ops, NULL);
 
 	/* 
-	 * Let the system know what interrupt model we are using by
-	 * evaluating the \_PIC object, if exists.
+	 * Locate PCI Device
+	 * -----------------
+	 * Locate the matching PCI root bridge device in the PCI namespace.
+	 */
+	root->data.dev = pci_find_slot(root->data.id.bus, 
+		PCI_DEVFN(root->data.id.device, root->data.id.function));
+	if (!root->data.dev) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Device %02x:%02x:%02x.%02x not present\n", 
+			root->data.id.segment, root->data.id.bus, 
+			root->data.id.device, root->data.id.function));
+		result = -ENODEV;
+		goto end;
+	}
+
+	/*
+	 * Attach ACPI-PCI Context
+	 * -----------------------
+	 * Thus binding the ACPI and PCI devices.
+	 */
+	status = acpi_attach_data(root->handle, acpi_pci_data_handler, 
+		&root->data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Unable to attach ACPI-PCI context to device %s\n",
+			acpi_device_bid(device)));
+		result = -ENODEV;
+		goto end;
+	}
+
+	/*
+	 * PCI Routing Table
+	 * -----------------
+	 * Evaluate and parse _PRT, if exists.  Note that root bridges
+	 * must have a _PRT (optional for subordinate bridges).
 	 */
+	result = acpi_prt_parse(device->handle, root->data.id.segment, 
+		root->data.id.bus);
 
-	result = acpi_get_interrupt_model(&irq_model);
+end:
 	if (0 != result)
-		return_VALUE(result);
+		kfree(root);
 
-	arg.integer.value = irq_model;
+	return_VALUE(result);
+}
 
-	status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
-	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
-		return_VALUE(-ENODEV);
-	}
+
+static int
+acpi_pci_root_remove (
+	struct acpi_device	*device,
+	int			type)
+{
+	struct acpi_pci_root	*root = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_pci_root_remove");
+
+	if (!device || !acpi_driver_data(device))
+		return_VALUE(-EINVAL);
+
+	root = (struct acpi_pci_root *) acpi_driver_data(device);
+
+	kfree(root);
 
 	return_VALUE(0);
 }
@@ -446,17 +724,11 @@
 int __init
 acpi_pci_root_init (void)
 {
-	int			result = 0;
-
 	ACPI_FUNCTION_TRACE("acpi_pci_root_init");
 
 	acpi_prts.count = 0;
 	INIT_LIST_HEAD(&acpi_prts.entries);
 
-	result = acpi_pci_irq_init();
-	if (0 != result)
-		return_VALUE(result);
-
 	if (0 > acpi_bus_register_driver(&acpi_pci_root_driver))
 		return_VALUE(-ENODEV);
 
@@ -470,5 +742,6 @@
 	ACPI_FUNCTION_TRACE("acpi_pci_root_exit");
 
 	acpi_bus_unregister_driver(&acpi_pci_root_driver);
-}
 
+	return_VOID;
+}
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_processor.c linux-2.5.8-pre3/drivers/acpi/acpi_processor.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_processor.c	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_processor.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- * acpi_processor.c - ACPI Processor Driver ($Revision: 50 $)
+ * acpi_processor.c - ACPI Processor Driver ($Revision: 57 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -23,16 +23,12 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *  TBD:
  *	1. Make # power/performance states dynamic.
- *	2. Includes support for _real_ performance states (not just throttle).
- *	3. Support duty_cycle values that span bit 4.
- *	4. Optimize by having scheduler determine business instead of
- *         having us try to calculate it here.
- *      5. Need C1 timing -- must modify kernel (IRQ handler) to get this.
- *	6. Convert time values to ticks (initially) to avoid having to do
- *         the math (acpi_get_timer_duration).
- *      7. What is a good default value for the OS busy_metric?
- *      8. Support both thermal and power limits.
- *      9. Resolve PIIX4 BMISX errata issue (getting an I/O port value of 0).
+ *	2. Support duty_cycle values that span bit 4.
+ *	3. Optimize by having scheduler determine business instead of
+ *	   having us try to calculate it here.
+ *	4. Need C1 timing -- must modify kernel (IRQ handler) to get this.
+ *	5. Convert time values to ticks (initially) to avoid having to do
+ *	   the math (acpi_get_timer_duration).
  */
 
 #include <linux/kernel.h>
@@ -43,6 +39,7 @@
 #include <linux/pm.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/delay.h>
 #include "acpi_bus.h"
 #include "acpi_drivers.h"
 
@@ -56,20 +53,22 @@
 
 #define PREFIX				"ACPI: "
 
+#define ACPI_PROCESSOR_BUSY_METRIC	10
 
 #define ACPI_PROCESSOR_MAX_POWER	ACPI_C_STATE_COUNT
 #define ACPI_PROCESSOR_MAX_C2_LATENCY	100
 #define ACPI_PROCESSOR_MAX_C3_LATENCY	1000
 
-#define ACPI_PROCESSOR_MAX_PERFORMANCE	4
+#define ACPI_PROCESSOR_MAX_PERFORMANCE	8
 
 #define ACPI_PROCESSOR_MAX_THROTTLING	16
-#define ACPI_PROCESSOR_MAX_THROTTLE	500	/* 50% */
+#define ACPI_PROCESSOR_MAX_THROTTLE	250	/* 25% */
 #define ACPI_PROCESSOR_MAX_DUTY_WIDTH	4
 
 const u32 POWER_OF_2[] = {1,2,4,8,16,32,64};
 
-#define ACPI_PROCESSOR_MAX_LIMIT	20
+#define ACPI_PROCESSOR_LIMIT_USER	0
+#define ACPI_PROCESSOR_LIMIT_THERMAL	1
 
 static int acpi_processor_add (struct acpi_device *device);
 static int acpi_processor_remove (struct acpi_device *device, int type);
@@ -110,24 +109,35 @@
 	int			state;
 	int			default_state;
 	u32			bm_activity;
-	u32			busy_metric;
 	struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
 };
 
 /* Performance Management */
 
+struct acpi_pct_register {
+	u8			descriptor;
+	u16			length;
+	u8			space_id;
+	u8			bit_width;
+	u8			bit_offset;
+	u8			reserved;
+	u64			address;
+} __attribute__ ((packed));
+
 struct acpi_processor_px {
-	u8			valid;
-	u32			core_frequency;
-	u32			power;
-	u32			transition_latency;
-	u32			bus_master_latency;
-	u32			control;
-	u32			status;
+	acpi_integer		core_frequency;		/* megahertz */
+	acpi_integer		power;			/* milliWatts */
+	acpi_integer		transition_latency;	/* microseconds */
+	acpi_integer		bus_master_latency;	/* microseconds */
+	acpi_integer		control;		/* control value */
+	acpi_integer		status;			/* success indicator */
 };
 
 struct acpi_processor_performance {
 	int			state;
+	int			platform_limit;
+	u16			control_register;
+	u16			status_register;
 	int			state_count;
 	struct acpi_processor_px states[ACPI_PROCESSOR_MAX_PERFORMANCE];
 };
@@ -136,7 +146,6 @@
 /* Throttling Control */
 
 struct acpi_processor_tx {
-	u8			valid;
 	u16			power;
 	u16			performance;
 };
@@ -153,37 +162,25 @@
 /* Limit Interface */
 
 struct acpi_processor_lx {
-	u8			valid;
-	u16			performance;
-	int			px;
-	int			tx;
+	int			px;		/* performace state */	
+	int			tx;		/* throttle level */
 };
 
 struct acpi_processor_limit {
-	int			state;
-	int			state_count;
-	struct {
-		u8			valid;
-		u16			performance;
-		int			px;
-		int			tx;
-	}			states[ACPI_PROCESSOR_MAX_LIMIT];
+	struct acpi_processor_lx state;		/* current limit */
+	struct acpi_processor_lx thermal;	/* thermal limit */
+	struct acpi_processor_lx user;		/* user limit */
 };
 
+
 struct acpi_processor_flags {
-	u8			bm_control:1;
 	u8			power:1;
 	u8			performance:1;
 	u8			throttling:1;
 	u8			limit:1;
-	u8			reserved:3;
-};
-
-struct acpi_processor_errata {
-	struct {
-		u8			reverse_throttle;
-		u32			bmisx;
-	}			piix4;
+	u8			bm_control:1;
+	u8			bm_check:1;
+	u8			reserved:2;
 };
 
 struct acpi_processor {
@@ -191,15 +188,25 @@
 	u32			acpi_id;
 	u32			id;
 	struct acpi_processor_flags flags;
-	struct acpi_processor_errata errata;
 	struct acpi_processor_power power;
 	struct acpi_processor_performance performance;
 	struct acpi_processor_throttling throttling;
 	struct acpi_processor_limit limit;
 };
 
+struct acpi_processor_errata {
+	u8			smp;
+	struct {
+		u8			throttle:1;
+		u8			fdma:1;
+		u8			reserved:6;
+		u32			bmisx;
+	}			piix4;
+};
 
-static u8			acpi_processor_smp = 0;
+static struct acpi_processor	*processors[NR_CPUS];
+static struct acpi_processor_errata errata;
+static void (*pm_idle_save)(void) = NULL;
 
 
 /* --------------------------------------------------------------------------
@@ -207,68 +214,138 @@
    -------------------------------------------------------------------------- */
 
 int
-acpi_processor_get_errata (
-	struct acpi_processor	*pr)
+acpi_processor_errata_piix4 (
+	struct pci_dev		*dev)
 {
-	struct pci_dev		*dev = NULL;
+	u8			rev = 0;
+	u8			value1 = 0;
+	u8			value2 = 0;
 
-	ACPI_FUNCTION_TRACE("acpi_processor_get_errata");
+	ACPI_FUNCTION_TRACE("acpi_processor_errata_piix4");
 
-	if (!pr)
+	if (!dev)
 		return_VALUE(-EINVAL);
 
 	/*
-	 * PIIX4
-	 * -----
+	 * Note that 'dev' references the PIIX4 ACPI Controller.
 	 */
-	dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
-		PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, PCI_ANY_ID, dev);
-	if (dev) {
-		u8		rev = 0;
-
-		pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PIIX4 ACPI rev %d\n", rev));
-
-		switch (rev) {
-
-		case 0:		/* PIIX4 A-step */
-		case 1:		/* PIIX4 B-step */
-			/*
-			 * Workaround for reverse-notation on throttling states
-			 * used by early PIIX4 models.
-			 */
-			pr->errata.piix4.reverse_throttle = 1;
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				"Reverse-throttle errata enabled\n"));
 
-		case 2:		/* PIIX4E */
-		case 3:		/* PIIX4M */
-			/*
-			 * Workaround for errata #18 "C3 Power State/BMIDE and
-			 * Type-F DMA Livelock" from the July 2001 PIIX4
-			 * specification update.  Applies to all PIIX4 models.
-			 */
-			/* TBD: Why is the bmisx value always ZERO? */
-			pr->errata.piix4.bmisx = pci_resource_start(dev, 4);
-			if (pr->errata.piix4.bmisx)
-				ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
-					"BM-IDE errata enabled\n"));
-			break;
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	switch (rev) {
+	case 0:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
+		break;
+	case 1:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
+		break;
+	case 2:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
+		break;
+	case 3:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
+		break;
+	default:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
+		break;
+	}
+
+	switch (rev) {
+
+	case 0:		/* PIIX4 A-step */
+	case 1:		/* PIIX4 B-step */
+		/*
+		 * See specification changes #13 ("Manual Throttle Duty Cycle")
+		 * and #14 ("Enabling and Disabling Manual Throttle"), plus
+		 * erratum #5 ("STPCLK# Deassertion Time") from the January 
+		 * 2002 PIIX4 specification update.  Applies to only older 
+		 * PIIX4 models.
+		 */
+		errata.piix4.throttle = 1;
+
+	case 2:		/* PIIX4E */
+	case 3:		/* PIIX4M */
+		/*
+		 * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA 
+		 * Livelock") from the January 2002 PIIX4 specification update.
+		 * Applies to all PIIX4 models.
+		 */
+
+		/* 
+		 * BM-IDE
+		 * ------
+		 * Find the PIIX4 IDE Controller and get the Bus Master IDE 
+		 * Status register address.  We'll use this later to read 
+		 * each IDE controller's DMA status to make sure we catch all
+		 * DMA activity.
+		 */
+		dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+		           PCI_DEVICE_ID_INTEL_82371AB, 
+                           PCI_ANY_ID, PCI_ANY_ID, NULL);
+		if (dev)
+			errata.piix4.bmisx = pci_resource_start(dev, 4);
+
+		/* 
+		 * Type-F DMA
+		 * ----------
+		 * Find the PIIX4 ISA Controller and read the Motherboard
+		 * DMA controller's status to see if Type-F (Fast) DMA mode
+		 * is enabled (bit 7) on either channel.  Note that we'll 
+		 * disable C3 support if this is enabled, as some legacy 
+		 * devices won't operate well if fast DMA is disabled.
+		 */
+		dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, 
+			PCI_DEVICE_ID_INTEL_82371AB_0, 
+			PCI_ANY_ID, PCI_ANY_ID, NULL);
+		if (dev) {
+			pci_read_config_byte(dev, 0x76, &value1);
+			pci_read_config_byte(dev, 0x77, &value2);
+			if ((value1 & 0x80) || (value2 & 0x80))
+				errata.piix4.fdma = 1;
 		}
+
+		break;
 	}
 
+	if (errata.piix4.bmisx)
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"Bus master activity detection (BM-IDE) erratum enabled\n"));
+	if (errata.piix4.fdma)
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"Type-F DMA livelock erratum (C3 disabled)\n"));
+
 	return_VALUE(0);
 }
 
 
+int
+acpi_processor_errata (
+	struct acpi_processor	*pr)
+{
+	int			result = 0;
+	struct pci_dev		*dev = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_errata");
+
+	if (!pr)
+		return_VALUE(-EINVAL);
+
+	/*
+	 * PIIX4
+	 */
+	dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, 
+		PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, PCI_ANY_ID, NULL);
+	if (dev)
+		result = acpi_processor_errata_piix4(dev);
+
+	return_VALUE(result);
+}
+
+
 /* --------------------------------------------------------------------------
                                 Power Management
    -------------------------------------------------------------------------- */
 
-static struct acpi_processor *acpi_processor_list[NR_CPUS];
-static void (*pm_idle_save)(void) = NULL;
-
 static void
 acpi_processor_power_activate (
 	struct acpi_processor	*pr,
@@ -311,9 +388,8 @@
 	u32			start_ticks = 0;
 	u32			end_ticks = 0;
 	u32			time_elapsed = 0;
-	static unsigned long	last_idle_jiffies = 0;
 
-	pr = acpi_processor_list[smp_processor_id()];
+	pr = processors[smp_processor_id()];
 	if (!pr)
 		return;
 
@@ -323,55 +399,47 @@
 	 */
 	__cli();
 
-	next_state = pr->power.state;
+	cx = &(pr->power.states[pr->power.state]);
 
 	/*
-	 * Check OS Idleness:
-	 * ------------------
-	 * If the OS has been busy (hasn't called the idle handler in a while)
-	 * then automatically demote to the default power state (e.g. C1).
-	 *
-	 * TBD: Optimize by having scheduler determine business instead
-	 *      of having us try to calculate it here.
+	 * Check BM Activity
+	 * -----------------
+	 * Check for bus mastering activity (if required), record, and check
+	 * for demotion.
 	 */
-	if (pr->power.state != pr->power.default_state) {
-		if ((jiffies - last_idle_jiffies) >= pr->power.busy_metric) {
-			next_state = pr->power.default_state;
-			if (next_state != pr->power.state)
-				acpi_processor_power_activate(pr, next_state);
-		}
-	}
+	if (pr->flags.bm_check) {
 
-	/*
-	 * Log BM Activity:
-	 * ----------------
-	 * Read BM_STS and record its value for later use by C3 policy.
-	 * (Note that we save the BM_STS values for the last 32 cycles).
-	 */
-	if (pr->flags.bm_control) {
 		pr->power.bm_activity <<= 1;
+		pr->power.bm_activity &= 0xFFFFFFFE;
+
 		if (acpi_hw_bit_register_read(ACPI_BITREG_BUS_MASTER_STATUS, ACPI_MTX_DO_NOT_LOCK)) {
-			pr->power.bm_activity |= 1;
-			acpi_hw_bit_register_write(ACPI_BITREG_BUS_MASTER_STATUS,
-				1, ACPI_MTX_DO_NOT_LOCK);
+			pr->power.bm_activity++;
+			acpi_hw_bit_register_write(ACPI_BITREG_BUS_MASTER_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
 		}
 		/*
-		 * PIIX4 Errata:
-		 * -------------
-		 * This code is a workaround for errata #18 "C3 Power State/
-		 * BMIDE and Type-F DMA Livelock" from the July '01 PIIX4
-		 * specification update.  Note that BM_STS doesn't always
-		 * reflect the true state of bus mastering activity; forcing
-		 * us to manually check the BMIDEA bit of each IDE channel.
+		 * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
+		 * the true state of bus mastering activity; forcing us to 
+		 * manually check the BMIDEA bit of each IDE channel.
 		 */
-		else if (pr->errata.piix4.bmisx) {
-			if ((inb_p(pr->errata.piix4.bmisx + 0x02) & 0x01) ||
-				(inb_p(pr->errata.piix4.bmisx + 0x0A) & 0x01))
-				pr->power.bm_activity |= 1;
+		else if (errata.piix4.bmisx) {
+			if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01) 
+				|| (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
+				pr->power.bm_activity++;
+		}
+
+		/*
+		 * Apply bus mastering demotion policy.  Automatically demote
+		 * to avoid a faulty transition.  Note that the processor 
+		 * won't enter a low-power state during this call (to this 
+		 * funciton) but should upon the next.
+		 */
+		if (pr->power.bm_activity & cx->demotion.threshold.bm) {
+			__sti();
+			next_state = cx->demotion.state;
+			goto end;
 		}
 	}
 
-	cx = &(pr->power.states[pr->power.state]);
 	cx->usage++;
 
 	/*
@@ -416,7 +484,7 @@
 		acpi_hw_bit_register_write(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
 		/* See how long we're asleep for */
 		start_ticks = inl(acpi_fadt.Xpm_tmr_blk.address);
-		/* Invoke C2 */
+		/* Invoke C3 */
 		inb(pr->power.states[ACPI_STATE_C3].address);
 		/* Dummy op - must do something useless after P_LVL3 read */
 		end_ticks = inl(acpi_fadt.Xpm_tmr_blk.address);
@@ -439,6 +507,8 @@
 		return;
 	}
 
+	next_state = pr->power.state;
+
 	/*
 	 * Promotion?
 	 * ----------
@@ -451,12 +521,16 @@
 			cx->promotion.count++;
  			cx->demotion.count = 0;
 			if (cx->promotion.count >= cx->promotion.threshold.count) {
-				if (pr->flags.bm_control) {
-					if (!(pr->power.bm_activity & cx->promotion.threshold.bm))
+				if (pr->flags.bm_check) {
+					if (!(pr->power.bm_activity & cx->promotion.threshold.bm)) {
 						next_state = cx->promotion.state;
+						goto end;
+					}
 				}
-				else
+				else {
 					next_state = cx->promotion.state;
+					goto end;
+				}
 			}
 		}
 	}
@@ -466,21 +540,20 @@
 	 * ---------
 	 * Track the number of shorts (time asleep is less than time threshold)
 	 * and demote when the usage threshold is reached.  Note that bus
-	 * mastering activity may cause immediate demotions.
+	 * mastering demotions are checked prior to state transitions (above).
 	 */
 	if (cx->demotion.state) {
 		if (time_elapsed < cx->demotion.threshold.time) {
 			cx->demotion.count++;
 			cx->promotion.count = 0;
-			if (cx->demotion.count >= cx->demotion.threshold.count)
-				next_state = cx->demotion.state;
-		}
-		if (pr->flags.bm_control) {
-			if (pr->power.bm_activity & cx->demotion.threshold.bm)
+			if (cx->demotion.count >= cx->demotion.threshold.count) {
 				next_state = cx->demotion.state;
+				goto end;
+			}
 		}
 	}
 
+end:
 	/*
 	 * New Cx State?
 	 * -------------
@@ -490,14 +563,6 @@
 	if (next_state != pr->power.state)
 		acpi_processor_power_activate(pr, next_state);
 
-	/*
-	 * Track OS Idleness:
-	 * ------------------
-	 * Record a jiffies timestamp to compute time elapsed between calls
-	 * to the idle handler.
-	 */
-	last_idle_jiffies = jiffies;
-
 	return;
 }
 
@@ -521,46 +586,30 @@
 		return_VALUE(-EINVAL);
 
 	/*
-	 * The Busy Metric is used to determine when the OS has been busy
-	 * and thus when policy should return to using the default Cx state
-	 * (e.g. C1).  On Linux we use the number of jiffies (scheduler
-	 * quantums) that transpire between calls to the idle handler.
-	 *
-	 * TBD: What is a good value for the OS busy_metric?
-	 */
-	pr->power.busy_metric = 2;
-
-	/*
 	 * C0/C1
 	 * -----
 	 */
-	if (pr->power.states[ACPI_STATE_C1].valid) {
-		pr->power.state = ACPI_STATE_C1;
-		pr->power.default_state = ACPI_STATE_C1;
-	}
-	else {
-		pr->power.state = ACPI_STATE_C0;
-		pr->power.default_state = ACPI_STATE_C0;
-		return_VALUE(0);
-	}
+	pr->power.state = ACPI_STATE_C1;
+	pr->power.default_state = ACPI_STATE_C1;
 
 	/*
 	 * C1/C2
 	 * -----
 	 * Set the default C1 promotion and C2 demotion policies, where we
-	 * promote from C1 to C2 anytime we're asleep in C1 for longer than
-	 * two times the C2 latency (to amortize cost of transitions). Demote
-	 * from C2 to C1 anytime we're asleep in C2 for less than this time.
+	 * promote from C1 to C2 after several (10) successive C1 transitions,
+	 * as we cannot (currently) measure the time spent in C1. Demote from
+	 * C2 to C1 after experiencing several (3) 'shorts' (time spent in C2
+	 * is less than the C2 transtional latency).
 	 */
 	if (pr->power.states[ACPI_STATE_C2].valid) {
 		pr->power.states[ACPI_STATE_C1].promotion.threshold.count = 10;
 		pr->power.states[ACPI_STATE_C1].promotion.threshold.time =
-			(2 * pr->power.states[ACPI_STATE_C2].latency);
+			pr->power.states[ACPI_STATE_C2].latency;
 		pr->power.states[ACPI_STATE_C1].promotion.state = ACPI_STATE_C2;
 
-		pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 1;
+		pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 3;
 		pr->power.states[ACPI_STATE_C2].demotion.threshold.time =
-			(2 * pr->power.states[ACPI_STATE_C2].latency);
+			pr->power.states[ACPI_STATE_C2].latency;
 		pr->power.states[ACPI_STATE_C2].demotion.state = ACPI_STATE_C1;
 	}
 
@@ -576,13 +625,13 @@
 		(pr->power.states[ACPI_STATE_C3].valid)) {
 		pr->power.states[ACPI_STATE_C2].promotion.threshold.count = 1;
 		pr->power.states[ACPI_STATE_C2].promotion.threshold.time =
-			(2 * pr->power.states[ACPI_STATE_C3].latency);
+			pr->power.states[ACPI_STATE_C3].latency;
 		pr->power.states[ACPI_STATE_C2].promotion.threshold.bm = 0x0F;
 		pr->power.states[ACPI_STATE_C2].promotion.state = ACPI_STATE_C3;
 
 		pr->power.states[ACPI_STATE_C3].demotion.threshold.count = 1;
 		pr->power.states[ACPI_STATE_C3].demotion.threshold.time =
-			(2 * pr->power.states[ACPI_STATE_C3].latency);
+			pr->power.states[ACPI_STATE_C3].latency;
 		pr->power.states[ACPI_STATE_C3].demotion.threshold.bm = 0x0F;
 		pr->power.states[ACPI_STATE_C3].demotion.state = ACPI_STATE_C2;
 	}
@@ -614,7 +663,7 @@
 	 * --
 	 * This state exists only as filler in our array.
 	 */
-	pr->power.states[ACPI_STATE_C0].valid = TRUE;
+	pr->power.states[ACPI_STATE_C0].valid = 1;
 
 	/*
 	 * C1
@@ -623,7 +672,7 @@
 	 *
 	 * TBD: What about PROC_C1?
 	 */
-	pr->power.states[ACPI_STATE_C1].valid = TRUE;
+	pr->power.states[ACPI_STATE_C1].valid = 1;
 
 	/*
 	 * C2
@@ -633,32 +682,82 @@
 	 * TBD: Support for C2 on MP (P_LVL2_UP).
 	 */
 	if (pr->power.states[ACPI_STATE_C2].address) {
+
 		pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
-		if (acpi_fadt.plvl2_lat > ACPI_PROCESSOR_MAX_C2_LATENCY)
+
+		/*
+		 * C2 latency must be less than or equal to 100 microseconds.
+		 */
+		if (acpi_fadt.plvl2_lat >= ACPI_PROCESSOR_MAX_C2_LATENCY)
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				"C2 latency too large [%d]\n",
 				acpi_fadt.plvl2_lat));
-		else if (!acpi_processor_smp)
-			pr->power.states[ACPI_STATE_C2].valid = TRUE;
+		/*
+		 * Only support C2 on UP systems (see TBD above).
+		 */
+		else if (errata.smp)
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				"C2 not supported in SMP mode\n"));
+		/*
+		 * Otherwise we've met all of our C2 requirements.
+		 */
+		else
+			pr->power.states[ACPI_STATE_C2].valid = 1;
 	}
 
 	/*
 	 * C3
 	 * --
-	 * We're (currently) only supporting C3 on UP systems that include
-	 * bus mastering arbitration control.  Note that this method of
-	 * maintaining cache coherency (disabling of bus mastering) cannot be
-	 * used on SMP systems, and flushing caches (e.g. WBINVD) is simply
-	 * too costly (at this time).
+	 * TBD: Investigate use of WBINVD on UP/SMP system in absence of
+	 *	bm_control.
 	 */
 	if (pr->power.states[ACPI_STATE_C3].address) {
+
 		pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
-		if (acpi_fadt.plvl3_lat > ACPI_PROCESSOR_MAX_C3_LATENCY)
+
+		/*
+		 * C3 latency must be less than or equal to 1000 microseconds.
+		 */
+		if (acpi_fadt.plvl3_lat >= ACPI_PROCESSOR_MAX_C3_LATENCY)
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				"C3 latency too large [%d]\n", 
 				acpi_fadt.plvl3_lat));
-		else if (!acpi_processor_smp && pr->flags.bm_control)
+		/*
+		 * Only support C3 when bus mastering arbitration control
+		 * is present (able to disable bus mastering to maintain
+		 * cache coherency while in C3).
+		 */
+		else if (!pr->flags.bm_control)
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				"C3 support requires bus mastering control\n"));
+		/*
+		 * Only support C3 on UP systems, as bm_control is only viable
+		 * on a UP system and flushing caches (e.g. WBINVD) is simply 
+		 * too costly (at this time).
+		 */
+		else if (errata.smp)
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				"C3 not supported in SMP mode\n"));
+		/*
+		 * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) 
+		 * DMA transfers are used by any ISA device to avoid livelock.
+		 * Note that we could disable Type-F DMA (as recommended by
+		 * the erratum), but this is known to disrupt certain ISA 
+		 * devices thus we take the conservative approach.
+		 */
+		else if (errata.piix4.fdma) {
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				"C3 not supported on PIIX4 with Type-F DMA\n"));
+		}
+		/*
+		 * Otherwise we've met all of our C3 requirements.  Enable
+		 * checking of bus mastering status (bm_check) so we can 
+		 * use this in our C3 policy.
+		 */
+		else {
 			pr->power.states[ACPI_STATE_C3].valid = 1;
+			pr->flags.bm_check = 1;
+		}
 	}
 
 	/*
@@ -678,7 +777,7 @@
 	 * manageable'.  Note that there's really no policy involved for
 	 * when only C1 is supported.
 	 */
-	if (pr->power.states[ACPI_STATE_C2].valid
+	if (pr->power.states[ACPI_STATE_C2].valid 
 		|| pr->power.states[ACPI_STATE_C3].valid)
 		pr->flags.power = 1;
 
@@ -690,30 +789,214 @@
                               Performance Management
    -------------------------------------------------------------------------- */
 
-static int
-acpi_processor_get_performance (
-	struct acpi_processor	*pr)
+static int 
+acpi_processor_get_platform_limit (
+	struct acpi_processor*	pr)
 {
-	ACPI_FUNCTION_TRACE("acpi_processor_get_performance_state");
+	acpi_status		status = 0;
+	unsigned long		ppc = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_get_platform_limit");
 
 	if (!pr)
 		return_VALUE(-EINVAL);
 
-	if (!pr->flags.performance)
-		return_VALUE(0);
+	/*
+	 * _PPC indicates the maximum state currently supported by the platform
+	 * (e.g. 0 = states 0..n; 1 = states 1..n; etc.
+	 */
+	status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
+	if(ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PPC\n"));
+		return_VALUE(-ENODEV);
+	}
 
-	/* TBD */
+	pr->performance.platform_limit = (int) ppc;
 
 	return_VALUE(0);
 }
 
 
+static int 
+acpi_processor_get_performance_control (
+	struct acpi_processor	*pr)
+{
+	int			result = 0;
+	acpi_status		status = 0;
+	acpi_buffer		buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_object		*pct = NULL;
+	acpi_object		obj = {0};
+	struct acpi_pct_register *reg = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control");
+
+	status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
+	if(ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	pct = (acpi_object *) buffer.pointer;
+	if (!pct || (pct->type != ACPI_TYPE_PACKAGE) 
+		|| (pct->package.count != 2)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	/*
+	 * control_register
+	 */
+
+	obj = pct->package.elements[0];
+
+	if ((obj.type != ACPI_TYPE_BUFFER) 
+		|| (obj.buffer.length < sizeof(struct acpi_pct_register)) 
+		|| (obj.buffer.pointer == NULL)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Invalid _PCT data (control_register)\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	reg = (struct acpi_pct_register *) (obj.buffer.pointer);
+
+	if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Unsupported address space [%d] (control_register)\n",
+			(u32) reg->space_id));
+		result = -EFAULT;
+		goto end;
+	}
+
+	pr->performance.control_register = (u16) reg->address;
+
+	/*
+	 * status_register
+	 */
+
+	obj = pct->package.elements[1];
+
+	if ((obj.type != ACPI_TYPE_BUFFER) 
+		|| (obj.buffer.length < sizeof(struct acpi_pct_register)) 
+		|| (obj.buffer.pointer == NULL)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Invalid _PCT data (status_register)\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	reg = (struct acpi_pct_register *) (obj.buffer.pointer);
+
+	if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Unsupported address space [%d] (status_register)\n",
+			(u32) reg->space_id));
+		result = -EFAULT;
+		goto end;
+	}
+
+	pr->performance.status_register = (u16) reg->address;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"control_register[0x%04x] status_register[0x%04x]\n",
+		pr->performance.control_register,
+		pr->performance.status_register));
+
+end:
+	kfree(buffer.pointer);
+
+	return_VALUE(result);
+}
+
+
+static int 
+acpi_processor_get_performance_states (
+	struct acpi_processor*	pr)
+{
+	int			result = 0;
+	acpi_status		status = AE_OK;
+	acpi_buffer		buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_buffer		format = {sizeof("NNNNNN"), "NNNNNN"};
+	acpi_buffer		state = {0, NULL};
+	acpi_object 		*pss = NULL;
+	int			i = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states");
+
+	status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
+	if(ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	pss = (acpi_object *) buffer.pointer;
+	if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", 
+		pss->package.count));
+
+	if (pss->package.count > ACPI_PROCESSOR_MAX_PERFORMANCE) {
+		pr->performance.state_count = ACPI_PROCESSOR_MAX_PERFORMANCE;
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"Limiting number of states to max (%d)\n", 
+			ACPI_PROCESSOR_MAX_PERFORMANCE));
+	}
+	else
+		pr->performance.state_count = pss->package.count;
+
+	if (pr->performance.state_count > 1)
+		pr->flags.performance = 1;
+
+	for (i = 0; i < pr->performance.state_count; i++) {
+
+		struct acpi_processor_px *px = &(pr->performance.states[i]);
+
+		state.length = sizeof(struct acpi_processor_px);
+		state.pointer = px;
+
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
+
+		status = acpi_extract_package(&(pss->package.elements[i]), 
+			&format, &state);
+		if (ACPI_FAILURE(status)) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
+			result = -EFAULT;
+			goto end;
+		}
+
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n",
+			i, 
+			(u32) px->core_frequency, 
+			(u32) px->power, 
+			(u32) px->transition_latency, 
+			(u32) px->bus_master_latency,
+			(u32) px->control, 
+			(u32) px->status));
+	}
+
+end:
+	kfree(buffer.pointer);
+
+	return_VALUE(result);
+}
+
+
 static int
 acpi_processor_set_performance (
 	struct acpi_processor	*pr,
 	int			state)
 {
-	ACPI_FUNCTION_TRACE("acpi_processor_set_performance_state");
+	u16			port = 0;
+	u8			value = 0;
+	int			i = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_set_performance");
 
 	if (!pr)
 		return_VALUE(-EINVAL);
@@ -721,13 +1004,71 @@
 	if (!pr->flags.performance)
 		return_VALUE(-ENODEV);
 
-	if (state >= pr->performance.state_count)
+	if (state >= pr->performance.state_count) {
+		ACPI_DEBUG_PRINT((ACPI_DB_WARN, 
+			"Invalid target state (P%d)\n", state));
 		return_VALUE(-ENODEV);
+	}
 
-	if (state == pr->performance.state)
+	if (state < pr->performance.platform_limit) {
+		ACPI_DEBUG_PRINT((ACPI_DB_WARN, 
+			"Platform limit (P%d) overrides target state (P%d)\n",
+			pr->performance.platform_limit, state));
+		return_VALUE(-ENODEV);
+	}
+
+	if (state == pr->performance.state) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"Already at target state (P%d)\n", state));
 		return_VALUE(0);
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n",
+		pr->performance.state, state));
+
+	/*
+	 * First we write the target state's 'control' value to the
+	 * control_register.
+	 */
 
-	/* TBD */
+	port = pr->performance.control_register;
+	value = (u16) pr->performance.states[state].control;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Writing 0x%02x to port 0x%04x\n", value, port));
+
+	outb(value, port); 
+
+	/*
+	 * Then we read the 'status_register' and compare the value with the
+	 * target state's 'status' to make sure the transition was successful.
+	 * Note that we'll poll for up to 1ms (100 cycles of 10us) before
+	 * giving up.
+	 */
+
+	port = pr->performance.status_register;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Looking for 0x%02x from port 0x%04x\n",
+		(u8) pr->performance.states[state].status, port));
+
+	for (i=0; i<100; i++) {
+		value = inb(port);
+		if (value == (u8) pr->performance.states[state].status)
+			break;
+		udelay(10);
+	}
+
+	if (value != pr->performance.states[state].status) {
+		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Transition failed\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Transition successful after %d microseconds\n",
+		i * 10));
+
+	pr->performance.state = state;
 
 	return_VALUE(0);
 }
@@ -738,13 +1079,37 @@
 	struct acpi_processor	*pr)
 {
 	int			result = 0;
+	acpi_status		status = AE_OK;
+	acpi_handle		handle = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info");
 
 	if (!pr)
 		return_VALUE(-EINVAL);
 
-	/* TBD: Support ACPI 2.0 objects */
+	status = acpi_get_handle(pr->handle, "_PCT", &handle);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"ACPI-based processor performance control unavailable\n"));
+		return_VALUE(0);
+	}
+
+	result = acpi_processor_get_performance_control(pr);
+	if (0 != result)
+		return_VALUE(result);
+
+	result = acpi_processor_get_performance_states(pr);
+	if (0 != result)
+		return_VALUE(result);
+
+	result = acpi_processor_get_platform_limit(pr);
+	if (0 != result)
+		return_VALUE(result);
+
+	/* 
+	 * TBD: Don't trust the latency values we get from BIOS, but rather
+	 *      measure the latencies during run-time (e.g. get_latencies).
+	 */
 
 	return_VALUE(0);
 }
@@ -776,32 +1141,29 @@
 	__cli();
 
 	duty_mask = pr->throttling.state_count - 1;
+
 	duty_mask <<= pr->throttling.duty_offset;
 
-	value = inb(pr->throttling.address);
+	value = inl(pr->throttling.address);
 
 	/*
 	 * Compute the current throttling state when throttling is enabled
-	 * (bit 4 is on).  Note that the reverse_throttling flag indicates
-	 * that the duty_value is opposite of that specified by ACPI.
+	 * (bit 4 is on).
 	 */
 	if (value & 0x10) {
 		duty_value = value & duty_mask;
 		duty_value >>= pr->throttling.duty_offset;
 
-		if (duty_value) {
-			if (pr->errata.piix4.reverse_throttle)
-				state = duty_value;
-			else
-				state = pr->throttling.state_count-duty_value;
-		}
+		if (duty_value)
+			state = pr->throttling.state_count-duty_value;
 	}
 
 	pr->throttling.state = state;
 
 	__sti();
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling state is T%d (%d%% throttling applied)\n",
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Throttling state is T%d (%d%% throttling applied)\n",
 		state, pr->throttling.states[state].performance));
 
 	return_VALUE(0);
@@ -825,7 +1187,7 @@
 	if ((state < 0) || (state > (pr->throttling.state_count - 1)))
 		return_VALUE(-EINVAL);
 
-	if (!pr->flags.throttling || !pr->throttling.states[state].valid)
+	if (!pr->flags.throttling)
 		return_VALUE(-ENODEV);
 
 	if (state == pr->throttling.state)
@@ -834,20 +1196,16 @@
 	__cli();
 
 	/*
-	 * Calculate the duty_value and duty_mask.  Note that the
-	 * reverse_throttling flag indicates that the duty_value is
-	 * opposite of that specified by ACPI.
+	 * Calculate the duty_value and duty_mask.
 	 */
 	if (state) {
-		if (pr->errata.piix4.reverse_throttle)
-			duty_value = state;
-		else
-			duty_value = pr->throttling.state_count - state;
+		duty_value = pr->throttling.state_count - state;
 
 		duty_value <<= pr->throttling.duty_offset;
 
 		/* Used to clear all duty_value bits */
-		duty_mask = pr->performance.state_count - 1;
+		duty_mask = pr->throttling.state_count - 1;
+
 		duty_mask <<= acpi_fadt.duty_offset;
 		duty_mask = ~duty_mask;
 	}
@@ -856,7 +1214,7 @@
 	 * Disable throttling by writing a 0 to bit 4.  Note that we must
 	 * turn it off before you can change the duty_value.
 	 */
-	value = inb(pr->throttling.address);
+	value = inl(pr->throttling.address);
 	if (value & 0x10) {
 		value &= 0xFFFFFFEF;
 		outl(value, pr->throttling.address);
@@ -879,8 +1237,9 @@
 
 	__sti();
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling state set to T%d (%d%%)\n",
-		state, (pr->throttling.states[state].performance?pr->throttling.states[state].performance/10:0)));
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+		"Throttling state set to T%d (%d%%)\n", state, 
+		(pr->throttling.states[state].performance?pr->throttling.states[state].performance/10:0)));
 
 	return_VALUE(0);
 }
@@ -912,13 +1271,24 @@
 		return_VALUE(0);
 	}
 	else if (!pr->throttling.duty_width) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid duty_width\n"));
-		return_VALUE(-EFAULT);
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
+		return_VALUE(0);
 	}
 	/* TBD: Support duty_cycle values that span bit 4. */
 	else if ((pr->throttling.duty_offset
 		+ pr->throttling.duty_width) > 4) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "duty_cycle spans bit 4\n"));
+		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "duty_cycle spans bit 4\n"));
+		return_VALUE(0);
+	}
+
+	/*
+	 * PIIX4 Errata: We don't support throttling on the original PIIX4.
+	 * This shouldn't be an issue as few (if any) mobile systems ever
+	 * used this part.
+	 */
+	if (errata.piix4.throttle) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"Throttling not supported on PIIX4 A- or B-step\n"));
 		return_VALUE(0);
 	}
 
@@ -935,7 +1305,6 @@
 	for (i=0; i<pr->throttling.state_count; i++) {
 		pr->throttling.states[i].performance = step * i;
 		pr->throttling.states[i].power = step * i;
-		pr->throttling.states[i].valid = 1;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n", 
@@ -973,19 +1342,76 @@
                                  Limit Interface
    -------------------------------------------------------------------------- */
 
+static int
+acpi_processor_apply_limit (
+	struct acpi_processor* 	pr)
+{
+	int			result = 0;
+	u16			px = 0;
+	u16			tx = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_processor_apply_limit");
+
+	if (!pr)
+		return_VALUE(-EINVAL);
+
+	if (!pr->flags.limit)
+		return_VALUE(-ENODEV);
+
+	if (pr->flags.performance) {
+		px = pr->performance.platform_limit;
+		if (pr->limit.user.px > px)
+			px = pr->limit.user.px;
+		if (pr->limit.thermal.px > px)
+			px = pr->limit.thermal.px;
+
+		result = acpi_processor_set_performance(pr, px);
+		if (0 != result)
+			goto end;
+	}
+
+	if (pr->flags.throttling) {
+		if (pr->limit.user.tx > tx)
+			tx = pr->limit.user.tx;
+		if (pr->limit.thermal.tx > tx)
+			tx = pr->limit.thermal.tx;
+
+		result = acpi_processor_set_throttling(pr, tx);
+		if (0 != result)
+			goto end;
+	}
+
+	pr->limit.state.px = px;
+	pr->limit.state.tx = tx;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d] limit set to (P%d:T%d)\n",
+		pr->id,
+		pr->limit.state.px,
+		pr->limit.state.tx));
+
+end:
+	if (0 != result)
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n"));
+
+	return_VALUE(result);
+}
+
+
 int
-acpi_processor_set_limit (
+acpi_processor_set_thermal_limit (
 	acpi_handle		handle,
-	int			type,
-	int			*state)
+	int			type)
 {
 	int			result = 0;
 	struct acpi_processor	*pr = NULL;
 	struct acpi_device	*device = NULL;
+	int			px = 0;
+	int			tx = 0;
 
-	ACPI_FUNCTION_TRACE("acpi_processor_set_limit");
+	ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit");
 
-	if (!state)
+	if ((type < ACPI_PROCESSOR_LIMIT_NONE) 
+		|| (type > ACPI_PROCESSOR_LIMIT_DECREMENT))
 		return_VALUE(-EINVAL);
 
 	result = acpi_bus_get_device(handle, &device);
@@ -999,56 +1425,75 @@
 	if (!pr->flags.limit)
 		return_VALUE(-ENODEV);
 
+	/* Thermal limits are always relative to the current Px/Tx state. */
+	if (pr->flags.performance)
+		pr->limit.thermal.px = pr->performance.state;
+	if (pr->flags.throttling)
+		pr->limit.thermal.tx = pr->throttling.state;
+
+	/*
+	 * Our default policy is to only use throttling at the lowest
+	 * performance state.
+	 */
+
 	switch (type) {
+
 	case ACPI_PROCESSOR_LIMIT_NONE:
-		*state = 0;
-		pr->limit.state = 0;
+		px = 0;
+		tx = 0;
 		break;
+
 	case ACPI_PROCESSOR_LIMIT_INCREMENT:
-		if (*state == (pr->limit.state_count - 1)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at maximum limit state\n"));
-			return_VALUE(1);
+		if (pr->flags.performance) {
+			if (px == (pr->performance.state_count - 1))
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+					"At maximum performance state\n"));
+			else {
+				px++;
+				goto end;
+			}
+		}
+		if (pr->flags.throttling) {
+			if (tx == (pr->throttling.state_count - 1))
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+					"At maximum throttling state\n"));
+			else
+				tx++;
 		}
-		*state = ++pr->limit.state;
 		break;
+
 	case ACPI_PROCESSOR_LIMIT_DECREMENT:
-		if (*state == 0) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at minimum limit state\n"));
-			return_VALUE(1);
+		if (pr->flags.performance) {
+			if (px == pr->performance.platform_limit)
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+					"At minimum performance state\n"));
+			else  {
+				px--;
+				goto end;
+			}
+		}
+		if (pr->flags.throttling) {
+			if (tx == 0)
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+					"At minimum throttling state\n"));
+			else
+				tx--;
 		}
-		*state = --pr->limit.state;
-		break;
-	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid limit type [%d]\n",
-			type));
-		*state = pr->limit.state;
-		return_VALUE(-EINVAL);
 		break;
 	}
 
-	if (pr->flags.performance) {
-		result = acpi_processor_set_performance(pr, 
-			pr->limit.states[*state].px);
-		if (0 != result)
-			goto end;
-	}
-
-	if (pr->flags.throttling) {
-		result = acpi_processor_set_throttling(pr, 
-			pr->limit.states[*state].tx);
-		if (0 != result)
-			goto end;
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d] limit now %d%% (P%d:T%d)\n",
-		pr->id,
-		pr->limit.states[*state].performance / 10,
-		pr->limit.states[*state].px,
-		pr->limit.states[*state].tx));
-
 end:
+	pr->limit.thermal.px = px;
+	pr->limit.thermal.tx = tx;
+
+	result = acpi_processor_apply_limit(pr);
 	if (0 != result)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n"));
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			"Unable to set thermal limit\n"));
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
+		pr->limit.thermal.px,
+		pr->limit.thermal.tx));
 
 	return_VALUE(result);
 }
@@ -1058,58 +1503,12 @@
 acpi_processor_get_limit_info (
 	struct acpi_processor	*pr)
 {
-	int			i = 0;
-	int			px = 0;
-	int			tx = 0;
-	int			base_perf = 1000;
-	int			throttle = 0;
-
 	ACPI_FUNCTION_TRACE("acpi_processor_get_limit_info");
 
 	if (!pr)
 		return_VALUE(-EINVAL);
 
-	/*
-	 * Limit
-	 * -----
-	 * Our default policy is to only use throttling at the lowest
-	 * performance state.  This is enforced by adding throttling states 
-	 * after perormance states.  We also only expose throttling states 
-	 * less than the maximum throttle value (e.g. 50%).
-	 */
-
-	if (pr->flags.performance) {
-		for (px=0; px<pr->performance.state_count; px++) {
-			if (!pr->performance.states[px].valid)
-				continue;
-			i = pr->limit.state_count++;
-			pr->limit.states[i].px = px;
-			pr->limit.states[i].performance = (pr->performance.states[px].core_frequency / pr->performance.states[0].core_frequency) * 1000;
-			pr->limit.states[i].valid = 1;
-		}
-		px--;
-		base_perf = pr->limit.states[i].performance;
-	}
-
-	if (pr->flags.throttling) {
-		for (tx=0; tx<pr->throttling.state_count; tx++) {
-			if (!pr->throttling.states[tx].valid)
-				continue;
-			if (pr->throttling.states[tx].performance > ACPI_PROCESSOR_MAX_THROTTLE)
-				continue;
-			i = pr->limit.state_count++;
-			pr->limit.states[i].px = px;
-			pr->limit.states[i].tx = tx;
-			throttle = (base_perf * pr->throttling.states[tx].performance) / 1000;
-			pr->limit.states[i].performance = base_perf - throttle;
-			pr->limit.states[i].valid = 1;
-		}
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d limit states\n", 
-		pr->limit.state_count));
-
-	if (pr->limit.state_count)
+	if (pr->flags.performance || pr->flags.throttling)
 		pr->flags.limit = 1;
 
 	return_VALUE(0);
@@ -1278,11 +1677,11 @@
 	p += sprintf(p, "states:\n");
 
 	for (i=0; i<pr->performance.state_count; i++)
-		p += sprintf(p, "   %cP%d:                %d Mhz, %d mW %s\n",
+		p += sprintf(p, "   %cP%d:                  %d Mhz, %d mW, %d uS\n",
 			(i == pr->performance.state?'*':' '), i,
-			pr->performance.states[i].core_frequency,
-			pr->performance.states[i].power,
-			(pr->performance.states[i].valid?"":"(disabled)"));
+			(u32) pr->performance.states[i].core_frequency,
+			(u32) pr->performance.states[i].power,
+			(u32) pr->performance.states[i].transition_latency);
 
 end:
 	len = (p - page);
@@ -1316,8 +1715,8 @@
 		return_VALUE(-EFAULT);
 	
 	state_string[count] = '\0';
-	
-	result = acpi_processor_set_throttling(pr, 
+
+	result = acpi_processor_set_performance(pr, 
 		simple_strtoul(state_string, NULL, 0));
 	if (0 != result)
 		return_VALUE(result);
@@ -1339,6 +1738,7 @@
 	char			*p = page;
 	int			len = 0;
 	int			i = 0;
+	int                     result = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_processor_read_throttling");
 
@@ -1350,6 +1750,13 @@
 		goto end;
 	}
 
+	result = acpi_processor_get_throttling(pr);
+
+	if (result) {
+		p += sprintf(p, "Could not determine current throttling state.\n");
+		goto end;
+	}
+
 	p += sprintf(p, "state count:             %d\n",
 		pr->throttling.state_count);
 
@@ -1359,10 +1766,9 @@
 	p += sprintf(p, "states:\n");
 
 	for (i=0; i<pr->throttling.state_count; i++)
-		p += sprintf(p, "   %cT%d:                  %02d%% %s\n",
+		p += sprintf(p, "   %cT%d:                  %02d%%\n",
 			(i == pr->throttling.state?'*':' '), i,
-			(pr->throttling.states[i].performance?pr->throttling.states[i].performance/10:0),
-			(pr->throttling.states[i].valid?"":"(disabled)"));
+			(pr->throttling.states[i].performance?pr->throttling.states[i].performance/10:0));
 
 end:
 	len = (p - page);
@@ -1418,7 +1824,6 @@
 	struct acpi_processor	*pr = (struct acpi_processor *) data;
 	char			*p = page;
 	int			len = 0;
-	int			i = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_processor_read_limit");
 
@@ -1430,22 +1835,17 @@
 		goto end;
 	}
 
-	p += sprintf(p, "state count:             %d\n",
-		pr->limit.state_count);
+	p += sprintf(p, "active limit:            P%d:T%d\n",
+		pr->limit.state.px, pr->limit.state.tx);
 
-	p += sprintf(p, "active state:            L%d\n",
-		pr->limit.state);
+	p += sprintf(p, "platform limit:          P%d:T0\n",
+		pr->flags.performance?pr->performance.platform_limit:0);
 
-	p += sprintf(p, "states:\n");
+	p += sprintf(p, "user limit:              P%d:T%d\n",
+		pr->limit.user.px, pr->limit.user.tx);
 
-	for (i=0; i<pr->limit.state_count; i++)
-		p += sprintf(p, "   %cL%d:                  %02d%% [P%d:T%d] %s\n",
-			(i == pr->limit.state?'*':' '),
-			i,
-			pr->limit.states[i].performance / 10,
-			pr->limit.states[i].px,
-			pr->limit.states[i].tx,
-			pr->limit.states[i].valid?"":"(disabled)");
+	p += sprintf(p, "thermal limit:           P%d:T%d\n",
+		pr->limit.thermal.px, pr->limit.thermal.tx);
 
 end:
 	len = (p - page);
@@ -1468,25 +1868,47 @@
 {
 	int			result = 0;
 	struct acpi_processor	*pr = (struct acpi_processor *) data;
-	char			limit_string[12] = {'\0'};
-	int			limit = 0;
-	int			state = 0;
+	char			limit_string[25] = {'\0'};
+	int			px = 0;
+	int			tx = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_processor_write_limit");
 
-	if (!pr || (count > sizeof(limit_string) - 1))
+	if (!pr || (count > sizeof(limit_string) - 1)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
 		return_VALUE(-EINVAL);
+	}
 	
-	if (copy_from_user(limit_string, buffer, count))
+	if (copy_from_user(limit_string, buffer, count)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
 		return_VALUE(-EFAULT);
+	}
 	
 	limit_string[count] = '\0';
 
-	limit = simple_strtoul(limit_string, NULL, 0);
-	
-	result = acpi_processor_set_limit(pr->handle, limit, &state);
-	if (0 != result)
-		return_VALUE(result);
+	if (sscanf(limit_string, "%d:%d", &px, &tx) != 2) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
+		return_VALUE(-EINVAL);
+	}
+
+	if (pr->flags.performance) {
+		if ((px < pr->performance.platform_limit) 
+			|| (px > (pr->performance.state_count - 1))) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid px\n"));
+			return_VALUE(-EINVAL);
+		}
+		pr->limit.user.px = px;
+	}
+
+	if (pr->flags.throttling) {
+		if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n"));
+			return_VALUE(-EINVAL);
+		}
+		pr->limit.user.tx = tx;
+	}
+
+	result = acpi_processor_apply_limit(pr);
 
 	return_VALUE(count);
 }
@@ -1564,7 +1986,7 @@
 		entry->data = acpi_driver_data(device);
 	}
 
-	/* 'thermal_limit' [R/W] */
+	/* 'limit' [R/W] */
 	entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
 		S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
 	if (!entry)
@@ -1617,10 +2039,10 @@
 
 #ifdef CONFIG_SMP
 	if (smp_num_cpus > 1)
-		acpi_processor_smp = smp_num_cpus;
+		errata.smp = smp_num_cpus;
 #endif
 
-	acpi_processor_get_errata(pr);
+	acpi_processor_errata(pr);
 
 	/*
 	 * Check to see if we have bus mastering arbitration control.  This
@@ -1687,6 +2109,7 @@
 	u32			event,
 	void			*data)
 {
+	int			result = 0;
 	struct acpi_processor	*pr = (struct acpi_processor *) data;
 	struct acpi_device	*device = NULL;
 
@@ -1700,7 +2123,15 @@
 
 	switch (event) {
 	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
+		result = acpi_processor_get_platform_limit(pr);
+		if (0 == result)
+			acpi_processor_apply_limit(pr);
+
+		acpi_bus_generate_event(device, event, 
+			pr->performance.platform_limit);
+		break;
 	case ACPI_PROCESSOR_NOTIFY_POWER:
+		/* TBD */
 		acpi_bus_generate_event(device, event, 0);
 		break;
 	default:
@@ -1745,9 +2176,6 @@
 	if (0 != result)
 		goto end;
 
-	/*
-	 * TBD: Fix notify handler installation for processors.
-	 *
 	status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, 
 		acpi_processor_notify, pr);
 	if (ACPI_FAILURE(status)) {
@@ -1756,16 +2184,13 @@
 		result = -ENODEV;
 		goto end;
 	}
-	*/
 
-	acpi_processor_list[pr->id] = pr;
+	processors[pr->id] = pr;
 
 	/*
-	 * Set Idle Handler
-	 * ----------------
-	 * Install the idle handler if power management (states other than C1)
-	 * is supported.  Note that the default idle handler (default_idle)
-	 * will be used on platforms that only support C1.
+	 * Install the idle handler if processor power management is supported.
+	 * Note that the default idle handler (default_idle) will be used on 
+	 * platforms that only support C1.
 	 */
 	if ((pr->id == 0) && (pr->flags.power)) {
 		pm_idle_save = pm_idle;
@@ -1781,8 +2206,6 @@
 		printk(", %d performance states", pr->performance.state_count);
 	if (pr->flags.throttling)
 		printk(", %d throttling states", pr->throttling.state_count);
-	if (pr->errata.piix4.bmisx)
-		printk(", PIIX4 errata");
 	printk(")\n");
 
 end:
@@ -1810,7 +2233,10 @@
 
 	pr = (struct acpi_processor *) acpi_driver_data(device);
 
-	/*
+	/* Unregister the idle handler when processor #0 is removed. */
+	if (pr->id == 0)
+		pm_idle = pm_idle_save;
+
 	status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, 
 		acpi_processor_notify);
 	if (ACPI_FAILURE(status)) {
@@ -1818,15 +2244,10 @@
 			"Error removing notify handler\n"));
 		return_VALUE(-ENODEV);
 	}
-	*/
-
-	/* Unregister the idle handler when processor #0 is removed. */
-	if (pr->id == 0)
-		pm_idle = pm_idle_save;
 
 	acpi_processor_remove_fs(device);
 
-	acpi_processor_list[pr->id] = NULL;
+	processors[pr->id] = NULL;
 
 	kfree(pr);
 
@@ -1841,7 +2262,8 @@
 
 	ACPI_FUNCTION_TRACE("acpi_processor_init");
 
-	memset(&acpi_processor_list, 0, sizeof(acpi_processor_list));
+	memset(&processors, 0, sizeof(processors));
+	memset(&errata, 0, sizeof(errata));
 
 	result = acpi_bus_register_driver(&acpi_processor_driver);
 	if (0 > result)
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_system.c linux-2.5.8-pre3/drivers/acpi/acpi_system.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_system.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_system.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_system.c - ACPI System Driver ($Revision: 40 $)
+ *  acpi_system.c - ACPI System Driver ($Revision: 45 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -31,6 +31,7 @@
 #include <linux/spinlock.h>
 #include <linux/poll.h>
 #include <linux/delay.h>
+#include <linux/sysrq.h>
 #include <linux/pm.h>
 #include <asm/uaccess.h>
 #include <asm/acpi.h>
@@ -86,9 +87,8 @@
 acpi_power_off (void)
 {
 	acpi_enter_sleep_state_prep(ACPI_STATE_S5);
-	acpi_disable_irqs();
+	ACPI_DISABLE_IRQS();
 	acpi_enter_sleep_state(ACPI_STATE_S5);
-	acpi_disable_irqs();
 }
 
 #endif /*CONFIG_PM*/
@@ -123,7 +123,7 @@
 	device_resume(RESUME_POWER_ON);
 
 	/* enable interrupts once again */
-	acpi_enable_irqs();
+	ACPI_ENABLE_IRQS();
 
 	/* restore device context */
 	device_resume(RESUME_RESTORE_STATE);
@@ -200,7 +200,7 @@
 	 * But, we want it done early, so we don't get any suprises during
 	 * the device suspend sequence.
 	 */
-	acpi_disable_irqs();
+	ACPI_DISABLE_IRQS();
 
 	/* Unconditionally turn off devices.
 	 * Obvious if we enter a sleep state.
@@ -304,7 +304,7 @@
 		return status;
 
 	/* disable interrupts and flush caches */
-	acpi_disable_irqs();
+	ACPI_DISABLE_IRQS();
 	wbinvd();
 
 	/* perform OS-specific sleep actions */
@@ -318,7 +318,7 @@
 	acpi_leave_sleep_state(state);
 
 	/* make sure interrupts are enabled */
-	acpi_enable_irqs();
+	ACPI_ENABLE_IRQS();
 
 	/* reset firmware waking vector */
 	acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0);
@@ -570,7 +570,6 @@
 {
 	char			*p = page;
 	int 			size = 0;
-	u32                     var;
 
 	if (off != 0)
 		goto end;
@@ -607,7 +606,6 @@
         void                    *data)
 {
 	char			debug_string[12] = {'\0'};
-	u32                     *pvar;
 
 	ACPI_FUNCTION_TRACE("acpi_system_write_debug");
 
@@ -1126,6 +1124,23 @@
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
+#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM)
+
+/* Simple wrapper calling power down function. */
+static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs,
+	struct kbd_struct *kbd, struct tty_struct *tty)
+{
+	acpi_power_off();
+}
+
+struct sysrq_key_op sysrq_acpi_poweroff_op = {
+	handler:	&acpi_sysrq_power_off,
+	help_msg:	"Off",
+	action_msg:	"Power Off\n"
+};
+
+#endif  /* CONFIG_MAGIC_SYSRQ */
+
 static int
 acpi_system_add (
 	struct acpi_device	*device)
@@ -1168,8 +1183,10 @@
 
 #ifdef CONFIG_PM
 	/* Install the soft-off (S5) handler. */
-	if (system->states[ACPI_STATE_S5])
+	if (system->states[ACPI_STATE_S5]) {
 		pm_power_off = acpi_power_off;
+		register_sysrq_key('o', &sysrq_acpi_poweroff_op);
+	}
 #endif
 
 end:
@@ -1196,8 +1213,10 @@
 
 #ifdef CONFIG_PM
 	/* Remove the soft-off (S5) handler. */
-	if (system->states[ACPI_STATE_S5])
+	if (system->states[ACPI_STATE_S5]) {
+		unregister_sysrq_key('o', &sysrq_acpi_poweroff_op);
 		pm_power_off = NULL;
+	}
 #endif
 
 	acpi_system_remove_fs(device);
diff -urN linux-2.5.8-pre2/drivers/acpi/acpi_thermal.c linux-2.5.8-pre3/drivers/acpi/acpi_thermal.c
--- linux-2.5.8-pre2/drivers/acpi/acpi_thermal.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/drivers/acpi/acpi_thermal.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- *  acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 33 $)
+ *  acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 36 $)
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -78,7 +78,6 @@
 	u8			passive:1;
 	u8			active:1;
 	u8			reserved:4;
-	int			passive_index;		/* a.k.a. limit state */
 	int			active_index;
 };
 
@@ -467,15 +466,23 @@
 	 */
 	if (tz->temperature >= passive->temperature) {
 		trend = (passive->tc1 * (tz->temperature - tz->last_temperature)) + (passive->tc2 * (tz->temperature - passive->temperature));
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n", trend, passive->tc1, tz->temperature, tz->last_temperature, passive->tc2, tz->temperature, passive->temperature));
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+			"trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n", 
+			trend, passive->tc1, tz->temperature, 
+			tz->last_temperature, passive->tc2, 
+			tz->temperature, passive->temperature));
 		/* Heating up? */
 		if (trend > 0)
 			for (i=0; i<passive->devices.count; i++)
-				acpi_processor_set_limit(passive->devices.handles[i], ACPI_PROCESSOR_LIMIT_INCREMENT, &tz->state.passive_index);
+				acpi_processor_set_thermal_limit(
+					passive->devices.handles[i], 
+					ACPI_PROCESSOR_LIMIT_INCREMENT);
 		/* Cooling off? */
 		else if (trend < 0)
 			for (i=0; i<passive->devices.count; i++)
-				acpi_processor_set_limit(passive->devices.handles[i], ACPI_PROCESSOR_LIMIT_DECREMENT, &tz->state.passive_index);
+				acpi_processor_set_thermal_limit(
+					passive->devices.handles[i], 
+					ACPI_PROCESSOR_LIMIT_DECREMENT);
 	}
 
 	/*
@@ -487,10 +494,13 @@
 	 */
 	else if (tz->trips.passive.flags.enabled) {
 		for (i=0; i<passive->devices.count; i++)
-			acpi_processor_set_limit(passive->devices.handles[i], ACPI_PROCESSOR_LIMIT_DECREMENT, &tz->state.passive_index);
-		if (0 == tz->state.passive_index) {
+			result = acpi_processor_set_thermal_limit(
+				passive->devices.handles[i], 
+				ACPI_PROCESSOR_LIMIT_DECREMENT);
+		if (1 == result) {
 			tz->trips.passive.flags.enabled = 0;
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabling passive cooling (zone is cool)\n"));
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+				"Disabling passive cooling (zone is cool)\n"));
 		}
 	}
 
@@ -671,7 +681,7 @@
 		if (timer_pending(&(tz->timer)))
 			mod_timer(&(tz->timer), (HZ * sleep_time) / 1000);
 		else {
-			tz->timer.data = (u32) tz;
+			tz->timer.data = (unsigned long) tz;
 			tz->timer.function = acpi_thermal_run;
 			tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
 			add_timer(&(tz->timer));
@@ -720,7 +730,7 @@
 		if (tz->state.hot)
 			p += sprintf(p, "hot ");
 		if (tz->state.passive)
-			p += sprintf(p, "passive[%d] ", tz->state.passive_index);
+			p += sprintf(p, "passive ");
 		if (tz->state.active)
 			p += sprintf(p, "active[%d]", tz->state.active_index);
 		p += sprintf(p, "\n");
@@ -810,9 +820,10 @@
 			tz->trips.passive.tc1,
 			tz->trips.passive.tc2, 
 			tz->trips.passive.tsp);
-		for (j=0; j<tz->trips.passive.devices.count; j++) 
-			p += sprintf(p, "0x%p ", 
-				tz->trips.passive.devices.handles[j]);
+		for (j=0; j<tz->trips.passive.devices.count; j++) {
+
+			p += sprintf(p, "0x%p ", tz->trips.passive.devices.handles[j]);
+		}
 		p += sprintf(p, "\n");
 	}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/debugger/dbdisply.c linux-2.5.8-pre3/drivers/acpi/debugger/dbdisply.c
--- linux-2.5.8-pre2/drivers/acpi/debugger/dbdisply.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/acpi/debugger/dbdisply.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbdisply - debug display commands
- *              $Revision: 66 $
+ *              $Revision: 67 $
  *
  ******************************************************************************/
 
@@ -298,6 +298,7 @@
 
 
 	if (!obj_desc) {
+		acpi_os_printf (" Uninitialized\n");
 		return;
 	}
 
@@ -420,10 +421,10 @@
 				break;
 
 			case AML_LOCAL_OP:
-				acpi_os_printf ("[Local%d]", obj_desc->reference.offset);
+				acpi_os_printf ("[Local%d] ", obj_desc->reference.offset);
 				if (walk_state) {
 					obj_desc = walk_state->local_variables[obj_desc->reference.offset].object;
-					acpi_os_printf (" %p", obj_desc);
+					acpi_os_printf ("%p", obj_desc);
 					acpi_db_decode_internal_object (obj_desc);
 				}
 				break;
@@ -432,7 +433,7 @@
 				acpi_os_printf ("[Arg%d] ", obj_desc->reference.offset);
 				if (walk_state) {
 					obj_desc = walk_state->arguments[obj_desc->reference.offset].object;
-					acpi_os_printf (" %p", obj_desc);
+					acpi_os_printf ("%p", obj_desc);
 					acpi_db_decode_internal_object (obj_desc);
 				}
 				break;
@@ -467,7 +468,6 @@
 		break;
 	}
 
-
 	acpi_os_printf ("\n");
 }
 
diff -urN linux-2.5.8-pre2/drivers/acpi/debugger/dbfileio.c linux-2.5.8-pre3/drivers/acpi/debugger/dbfileio.c
--- linux-2.5.8-pre2/drivers/acpi/debugger/dbfileio.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/acpi/debugger/dbfileio.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: dbfileio - Debugger file I/O commands.  These can't usually
  *              be used when running the debugger in Ring 0 (Kernel mode)
- *              $Revision: 59 $
+ *              $Revision: 60 $
  *
  ******************************************************************************/
 
@@ -308,27 +308,14 @@
 }
 
 
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_load_acpi_table
- *
- * PARAMETERS:  Filname         - File where table is located
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load an ACPI table from a file
- *
- ******************************************************************************/
-
+#ifdef ACPI_APPLICATION
 acpi_status
-acpi_db_load_acpi_table (
+acpi_db_get_acpi_table (
 	NATIVE_CHAR             *filename)
 {
-#ifdef ACPI_APPLICATION
 	FILE                    *fp;
-	acpi_status             status;
 	u32                     table_length;
-
+	acpi_status             status;
 
 	/* Open the file */
 
@@ -350,7 +337,35 @@
 		return (status);
 	}
 
-	/* Attempt to recognize and install the table */
+	return (AE_OK);
+ }
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_db_load_acpi_table
+ *
+ * PARAMETERS:  Filname         - File where table is located
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load an ACPI table from a file
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_db_load_acpi_table (
+	NATIVE_CHAR             *filename) {
+#ifdef ACPI_APPLICATION
+	acpi_status             status;
+
+
+	status = acpi_db_get_acpi_table (filename);
+	if (ACPI_FAILURE (status)) {
+		return (status);
+	}
+
+   /* Attempt to recognize and install the table */
 
 	status = ae_local_load_table (acpi_gbl_db_table_ptr);
 	if (ACPI_FAILURE (status)) {
diff -urN linux-2.5.8-pre2/drivers/acpi/debugger/dbutils.c linux-2.5.8-pre3/drivers/acpi/debugger/dbutils.c
--- linux-2.5.8-pre2/drivers/acpi/debugger/dbutils.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/acpi/debugger/dbutils.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dbutils - AML debugger utilities
- *              $Revision: 51 $
+ *              $Revision: 52 $
  *
  ******************************************************************************/
 
@@ -151,7 +151,7 @@
 
 	case ACPI_TYPE_BUFFER:
 
-		acpi_os_printf ("[Buffer] = ");
+		acpi_os_printf ("[Buffer] Length %.2X = ", obj_desc->buffer.length);
 		acpi_ut_dump_buffer ((u8 *) obj_desc->buffer.pointer, obj_desc->buffer.length, DB_DWORD_DISPLAY, _COMPONENT);
 		break;
 
diff -urN linux-2.5.8-pre2/drivers/acpi/dispatcher/dsmethod.c linux-2.5.8-pre3/drivers/acpi/dispatcher/dsmethod.c
--- linux-2.5.8-pre2/drivers/acpi/dispatcher/dsmethod.c	Mon Mar 18 12:37:15 2002
+++ linux-2.5.8-pre3/drivers/acpi/dispatcher/dsmethod.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
- *              $Revision: 79 $
+ *              $Revision: 81 $
  *
  *****************************************************************************/
 
@@ -77,7 +77,7 @@
 		return_ACPI_STATUS (AE_NULL_ENTRY);
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Parsing [%4.4s] **** Named_obj=%p\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** Named_obj=%p\n",
 		(char *) &((acpi_namespace_node *) obj_handle)->name, obj_handle));
 
 	/* Extract the method object from the method Node */
@@ -111,7 +111,7 @@
 
 	/* Init new op with the method name and pointer back to the Node */
 
-	acpi_ps_set_name (op, node->name);
+	acpi_ps_set_name (op, node->name.integer);
 	op->node = node;
 
 	/*
@@ -152,7 +152,7 @@
 		return_ACPI_STATUS (status);
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** [%4.4s] Parsed **** Named_obj=%p Op=%p\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** [%4.4s] Parsed **** Named_obj=%p Op=%p\n",
 		(char *) &((acpi_namespace_node *) obj_handle)->name, obj_handle, op));
 
 	acpi_ps_delete_parse_tree (op);
@@ -414,7 +414,6 @@
 		walk_state->method_call_op, return_desc, walk_state->return_used,
 		walk_state->results, walk_state));
 
-
 	return_ACPI_STATUS (AE_OK);
 }
 
diff -urN linux-2.5.8-pre2/drivers/acpi/dispatcher/dsmthdat.c linux-2.5.8-pre3/drivers/acpi/dispatcher/dsmthdat.c
--- linux-2.5.8-pre2/drivers/acpi/dispatcher/dsmthdat.c	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/drivers/acpi/dispatcher/dsmthdat.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dsmthdat - control method arguments and local variables
- *              $Revision: 58 $
+ *              $Revision: 59 $
  *
  ******************************************************************************/
 
@@ -72,10 +72,10 @@
 	for (i = 0; i < MTH_NUM_ARGS; i++) {
 		ACPI_MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name,
 				 NAMEOF_ARG_NTE);
-		walk_state->arguments[i].name     |= (i << 24);
-		walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED;
-		walk_state->arguments[i].type      = ACPI_TYPE_ANY;
-		walk_state->arguments[i].flags     = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
+		walk_state->arguments[i].name.integer |= (i << 24);
+		walk_state->arguments[i].descriptor   = ACPI_DESC_TYPE_NAMED;
+		walk_state->arguments[i].type         = ACPI_TYPE_ANY;
+		walk_state->arguments[i].flags        = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
 	}
 
 	/* Init the method locals */
@@ -84,10 +84,10 @@
 		ACPI_MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name,
 				 NAMEOF_LOCAL_NTE);
 
-		walk_state->local_variables[i].name    |= (i << 24);
-		walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED;
-		walk_state->local_variables[i].type     = ACPI_TYPE_ANY;
-		walk_state->local_variables[i].flags    = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
+		walk_state->local_variables[i].name.integer |= (i << 24);
+		walk_state->local_variables[i].descriptor  = ACPI_DESC_TYPE_NAMED;
+		walk_state->local_variables[i].type        = ACPI_TYPE_ANY;
+		walk_state->local_variables[i].flags       = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
 	}
 
 	return_ACPI_STATUS (AE_OK);
diff -urN linux-2.5.8-pre2/drivers/acpi/dispatcher/dsobject.c linux-2.5.8-pre3/drivers/acpi/dispatcher/dsobject.c
--- linux-2.5.8-pre2/drivers/acpi/dispatcher/dsobject.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/acpi/dispatcher/dsobject.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsobject - Dispatcher object management routines
- *              $Revision: 90 $
+ *              $Revision: 91 $
  *
  *****************************************************************************/
 
@@ -47,11 +47,11 @@
  * RETURN:      Status
  *
  * DESCRIPTION: Callback from Acpi_walk_namespace. Invoked for every object
- *              within the  namespace.
+ *              within the namespace.
  *
  *              Currently, the only objects that require initialization are:
  *              1) Methods
- *              2) Op Regions
+ *              2) Operation Regions
  *
  ******************************************************************************/
 
@@ -83,7 +83,6 @@
 		return (AE_OK);
 	}
 
-
 	/* And even then, we are only interested in a few object types */
 
 	type = acpi_ns_get_type (obj_handle);
@@ -152,12 +151,13 @@
  *
  * FUNCTION:    Acpi_ds_initialize_objects
  *
- * PARAMETERS:  None
+ * PARAMETERS:  Table_desc      - Descriptor for parent ACPI table
+ *              Start_node      - Root of subtree to be initialized.
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Walk the entire namespace and perform any necessary
- *              initialization on the objects found therein
+ * DESCRIPTION: Walk the namespace starting at "Start_node" and perform any
+ *              necessary initialization on the objects found therein
  *
  ******************************************************************************/
 
@@ -183,7 +183,6 @@
 	info.object_count   = 0;
 	info.table_desc     = table_desc;
 
-
 	/* Walk entire namespace from the supplied root */
 
 	status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
@@ -208,9 +207,10 @@
  *
  * FUNCTION:    Acpi_ds_init_object_from_op
  *
- * PARAMETERS:  Op              - Parser op used to init the internal object
+ * PARAMETERS:  Walk_state      - Current walk state
+ *              Op              - Parser op used to init the internal object
  *              Opcode          - AML opcode associated with the object
- *              Obj_desc        - Namespace object to be initialized
+ *              Ret_obj_desc    - Namespace object to be initialized
  *
  * RETURN:      Status
  *
@@ -227,10 +227,6 @@
 	u16                     opcode,
 	acpi_operand_object     **ret_obj_desc)
 {
-	acpi_status             status;
-	acpi_parse_object       *arg;
-	acpi_parse2_object      *byte_list;
-	acpi_operand_object     *arg_desc;
 	const acpi_opcode_info  *op_info;
 	acpi_operand_object     *obj_desc;
 
@@ -246,100 +242,39 @@
 		return (AE_TYPE);
 	}
 
-
-	/* Get and prepare the first argument */
+	/* Perform per-object initialization */
 
 	switch (obj_desc->common.type) {
 	case ACPI_TYPE_BUFFER:
 
-		obj_desc->buffer.node = (acpi_namespace_node *) walk_state->operands[0];
-
-		/* First arg is a number */
-
-		acpi_ds_create_operand (walk_state, op->value.arg, 0);
-		arg_desc = walk_state->operands [walk_state->num_operands - 1];
-		acpi_ds_obj_stack_pop (1, walk_state);
-
-		/* Resolve the object (could be an arg or local) */
-
-		status = acpi_ex_resolve_to_value (&arg_desc, walk_state);
-		if (ACPI_FAILURE (status)) {
-			acpi_ut_remove_reference (arg_desc);
-			return (status);
-		}
-
-		/* We are expecting a number */
-
-		if (arg_desc->common.type != ACPI_TYPE_INTEGER) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-				"Expecting number, got obj: %p type %X\n",
-				arg_desc, arg_desc->common.type));
-			acpi_ut_remove_reference (arg_desc);
-			return (AE_TYPE);
-		}
-
-		/* Get the value, delete the internal object */
-
-		obj_desc->buffer.length = (u32) arg_desc->integer.value;
-		acpi_ut_remove_reference (arg_desc);
-
-		/* Allocate the buffer */
-
-		if (obj_desc->buffer.length == 0) {
-			obj_desc->buffer.pointer = NULL;
-			ACPI_REPORT_WARNING (("Buffer created with zero length in AML\n"));
-			break;
-		}
-
-		else {
-			obj_desc->buffer.pointer = ACPI_MEM_CALLOCATE (
-					   obj_desc->buffer.length);
-
-			if (!obj_desc->buffer.pointer) {
-				return (AE_NO_MEMORY);
-			}
-		}
-
 		/*
-		 * Second arg is the buffer data (optional) Byte_list can be either
-		 * individual bytes or a string initializer.
+		 * Defer evaluation of Buffer Term_arg operand
 		 */
-		arg = op->value.arg;         /* skip first arg */
-
-		byte_list = (acpi_parse2_object *) arg->next;
-		if (byte_list) {
-			if (byte_list->opcode != AML_INT_BYTELIST_OP) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Expecting bytelist, got: %p\n",
-					byte_list));
-				return (AE_TYPE);
-			}
-
-			ACPI_MEMCPY (obj_desc->buffer.pointer, byte_list->data,
-					  obj_desc->buffer.length);
-		}
-
+		obj_desc->buffer.node     = (acpi_namespace_node *) walk_state->operands[0];
+		obj_desc->buffer.aml_start = ((acpi_parse2_object *) op)->data;
+		obj_desc->buffer.aml_length = ((acpi_parse2_object *) op)->length;
 		break;
 
 
 	case ACPI_TYPE_PACKAGE:
 
 		/*
-		 * When called, an internal package object has already been built and
-		 * is pointed to by Obj_desc. Acpi_ds_build_internal_object builds another
-		 * internal package object, so remove reference to the original so
-		 * that it is deleted.  Error checking is done within the remove
-		 * reference function.
+		 * Defer evaluation of Package Term_arg operand
 		 */
-		acpi_ut_remove_reference (obj_desc);
-		status = acpi_ds_build_internal_object (walk_state, op, ret_obj_desc);
+		obj_desc->package.node     = (acpi_namespace_node *) walk_state->operands[0];
+		obj_desc->package.aml_start = ((acpi_parse2_object *) op)->data;
+		obj_desc->package.aml_length = ((acpi_parse2_object *) op)->length;
 		break;
 
+
 	case ACPI_TYPE_INTEGER:
+
 		obj_desc->integer.value = op->value.integer;
 		break;
 
 
 	case ACPI_TYPE_STRING:
+
 		obj_desc->string.pointer = op->value.string;
 		obj_desc->string.length = ACPI_STRLEN (op->value.string);
 
@@ -387,7 +322,6 @@
 			obj_desc->reference.opcode = opcode;
 			break;
 		}
-
 		break;
 
 
@@ -405,9 +339,10 @@
 
 /*****************************************************************************
  *
- * FUNCTION:    Acpi_ds_build_internal_simple_obj
+ * FUNCTION:    Acpi_ds_build_internal_object
  *
- * PARAMETERS:  Op              - Parser object to be translated
+ * PARAMETERS:  Walk_state      - Current walk state
+ *              Op              - Parser object to be translated
  *              Obj_desc_ptr    - Where the ACPI internal object is returned
  *
  * RETURN:      Status
@@ -417,8 +352,8 @@
  *
  ****************************************************************************/
 
-static acpi_status
-acpi_ds_build_internal_simple_obj (
+acpi_status
+acpi_ds_build_internal_object (
 	acpi_walk_state         *walk_state,
 	acpi_parse_object       *op,
 	acpi_operand_object     **obj_desc_ptr)
@@ -428,7 +363,7 @@
 	char                    *name;
 
 
-	ACPI_FUNCTION_TRACE ("Ds_build_internal_simple_obj");
+	ACPI_FUNCTION_TRACE ("Ds_build_internal_object");
 
 
 	if (op->opcode == AML_INT_NAMEPATH_OP) {
@@ -453,7 +388,6 @@
 								 name, op->aml_offset));
 						ACPI_MEM_FREE (name);
 					}
-
 					else {
 						ACPI_REPORT_WARNING (("Reference %s at AML %X not found\n",
 								   op->value.string, op->aml_offset));
@@ -461,7 +395,6 @@
 
 					*obj_desc_ptr = NULL;
 				}
-
 				else {
 					return_ACPI_STATUS (status);
 				}
@@ -483,14 +416,13 @@
 	}
 
 	*obj_desc_ptr = obj_desc;
-
 	return_ACPI_STATUS (AE_OK);
 }
 
 
 /*****************************************************************************
  *
- * FUNCTION:    Acpi_ds_build_internal_package_obj
+ * FUNCTION:    Acpi_ds_build_internal_buffer_obj
  *
  * PARAMETERS:  Op              - Parser object to be translated
  *              Obj_desc_ptr    - Where the ACPI internal object is returned
@@ -503,114 +435,212 @@
  ****************************************************************************/
 
 acpi_status
-acpi_ds_build_internal_package_obj (
+acpi_ds_build_internal_buffer_obj (
 	acpi_walk_state         *walk_state,
 	acpi_parse_object       *op,
+	u32                     buffer_length,
 	acpi_operand_object     **obj_desc_ptr)
 {
 	acpi_parse_object       *arg;
 	acpi_operand_object     *obj_desc;
-	acpi_status             status = AE_OK;
+	acpi_parse2_object      *byte_list;
+	u32                     byte_list_length = 0;
 
 
-	ACPI_FUNCTION_TRACE ("Ds_build_internal_package_obj");
+	ACPI_FUNCTION_TRACE ("Ds_build_internal_buffer_obj");
 
 
-	obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE);
-	*obj_desc_ptr = obj_desc;
-	if (!obj_desc) {
-		return_ACPI_STATUS (AE_NO_MEMORY);
-	}
-
-	if (op->opcode == AML_VAR_PACKAGE_OP) {
+	obj_desc = *obj_desc_ptr;
+	if (obj_desc) {
 		/*
-		 * Variable length package parameters are evaluated JIT
+		 * We are evaluating a Named buffer object "Name (xxxx, Buffer)".
+		 * The buffer object already exists (from the NS node)
 		 */
-		return_ACPI_STATUS (AE_OK);
 	}
+	else {
+		/* Create a new buffer object */
 
-	/* The first argument must be the package length */
-
-	arg = op->value.arg;
-	obj_desc->package.count = arg->value.integer32;
+		obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
+		*obj_desc_ptr = obj_desc;
+		if (!obj_desc) {
+			return_ACPI_STATUS (AE_NO_MEMORY);
+		}
+	}
 
 	/*
-	 * Allocate the array of pointers (ptrs to the
-	 * individual objects) Add an extra pointer slot so
-	 * that the list is always null terminated.
+	 * Second arg is the buffer data (optional) Byte_list can be either
+	 * individual bytes or a string initializer.  In either case, a
+	 * Byte_list appears in the AML.
 	 */
-	obj_desc->package.elements = ACPI_MEM_CALLOCATE (
-			 (obj_desc->package.count + 1) * sizeof (void *));
+	arg = op->value.arg;         /* skip first arg */
 
-	if (!obj_desc->package.elements) {
-		acpi_ut_delete_object_desc (obj_desc);
-		return_ACPI_STATUS (AE_NO_MEMORY);
-	}
+	byte_list = (acpi_parse2_object *) arg->next;
+	if (byte_list) {
+		if (byte_list->opcode != AML_INT_BYTELIST_OP) {
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+				"Expecting bytelist, got AML opcode %X in op %p\n",
+				byte_list->opcode, byte_list));
 
-	obj_desc->package.next_element = obj_desc->package.elements;
+			acpi_ut_remove_reference (obj_desc);
+			return (AE_TYPE);
+		}
+
+		byte_list_length = byte_list->value.integer32;
+	}
 
 	/*
-	 * Now init the elements of the package
+	 * The buffer length (number of bytes) will be the larger of:
+	 * 1) The specified buffer length and
+	 * 2) The length of the initializer byte list
 	 */
-	arg = arg->next;
-	while (arg) {
-		if (arg->opcode == AML_PACKAGE_OP) {
-			status = acpi_ds_build_internal_package_obj (walk_state, arg,
-					  obj_desc->package.next_element);
-		}
+	obj_desc->buffer.length = buffer_length;
+	if (byte_list_length > buffer_length) {
+		obj_desc->buffer.length = byte_list_length;
+	}
 
-		else {
-			status = acpi_ds_build_internal_simple_obj (walk_state, arg,
-					  obj_desc->package.next_element);
-		}
+	/* Allocate the buffer */
 
-		obj_desc->package.next_element++;
-		arg = arg->next;
+	if (obj_desc->buffer.length == 0) {
+		obj_desc->buffer.pointer = NULL;
+		ACPI_REPORT_WARNING (("Buffer created with zero length in AML\n"));
+		return_ACPI_STATUS (AE_OK);
 	}
 
-	obj_desc->package.flags |= AOPOBJ_DATA_VALID;
-	return_ACPI_STATUS (status);
+	obj_desc->buffer.pointer = ACPI_MEM_CALLOCATE (
+			   obj_desc->buffer.length);
+	if (!obj_desc->buffer.pointer) {
+		acpi_ut_delete_object_desc (obj_desc);
+		return_ACPI_STATUS (AE_NO_MEMORY);
+	}
+
+	/* Initialize buffer from the Byte_list (if present) */
+
+	if (byte_list) {
+		ACPI_MEMCPY (obj_desc->buffer.pointer, byte_list->data,
+				  byte_list_length);
+	}
+
+	obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
+	op->node = (acpi_namespace_node *) obj_desc;
+	return_ACPI_STATUS (AE_OK);
 }
 
 
 /*****************************************************************************
  *
- * FUNCTION:    Acpi_ds_build_internal_object
+ * FUNCTION:    Acpi_ds_build_internal_package_obj
  *
  * PARAMETERS:  Op              - Parser object to be translated
  *              Obj_desc_ptr    - Where the ACPI internal object is returned
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Translate a parser Op object to the equivalent namespace
- *              object
+ * DESCRIPTION: Translate a parser Op package object to the equivalent
+ *              namespace object
  *
  ****************************************************************************/
 
 acpi_status
-acpi_ds_build_internal_object (
+acpi_ds_build_internal_package_obj (
 	acpi_walk_state         *walk_state,
 	acpi_parse_object       *op,
+	u32                     package_length,
 	acpi_operand_object     **obj_desc_ptr)
 {
-	acpi_status             status;
+	acpi_parse_object       *arg;
+	acpi_parse_object       *parent;
+	acpi_operand_object     *obj_desc = NULL;
+	u32                     package_list_length;
+	acpi_status             status = AE_OK;
+	u32                     i;
 
 
-	switch (op->opcode) {
-	case AML_PACKAGE_OP:
-	case AML_VAR_PACKAGE_OP:
+	ACPI_FUNCTION_TRACE ("Ds_build_internal_package_obj");
 
-		status = acpi_ds_build_internal_package_obj (walk_state, op, obj_desc_ptr);
-		break;
 
+	/* Find the parent of a possibly nested package */
 
-	default:
 
-		status = acpi_ds_build_internal_simple_obj (walk_state, op, obj_desc_ptr);
-		break;
+	parent = op->parent;
+	while ((parent->opcode == AML_PACKAGE_OP)     ||
+		   (parent->opcode == AML_VAR_PACKAGE_OP)) {
+		parent = parent->parent;
 	}
 
-	return (status);
+	obj_desc = *obj_desc_ptr;
+	if (obj_desc) {
+		/*
+		 * We are evaluating a Named package object "Name (xxxx, Package)".
+		 * Get the existing package object from the NS node
+		 */
+	}
+	else {
+		obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE);
+		*obj_desc_ptr = obj_desc;
+		if (!obj_desc) {
+			return_ACPI_STATUS (AE_NO_MEMORY);
+		}
+
+		obj_desc->package.node = parent->node;
+	}
+
+	obj_desc->package.count = package_length;
+
+	/* Count the number of items in the package list */
+
+	package_list_length = 0;
+	arg = op->value.arg;
+	arg = arg->next;
+	while (arg) {
+		package_list_length++;
+		arg = arg->next;
+	}
+
+	/*
+	 * The package length (number of elements) will be the greater
+	 * of the specified length and the length of the initializer list
+	 */
+	if (package_list_length > package_length) {
+		obj_desc->package.count = package_list_length;
+	}
+
+	/*
+	 * Allocate the pointer array (array of pointers to the
+	 * individual objects). Add an extra pointer slot so
+	 * that the list is always null terminated.
+	 */
+	obj_desc->package.elements = ACPI_MEM_CALLOCATE (
+			 (obj_desc->package.count + 1) * sizeof (void *));
+
+	if (!obj_desc->package.elements) {
+		acpi_ut_delete_object_desc (obj_desc);
+		return_ACPI_STATUS (AE_NO_MEMORY);
+	}
+
+	/*
+	 * Now init the elements of the package
+	 */
+	i = 0;
+	arg = op->value.arg;
+	arg = arg->next;
+	while (arg) {
+		if (arg->opcode == AML_INT_RETURN_VALUE_OP) {
+			/* Object (package or buffer) is already built */
+
+			obj_desc->package.elements[i] = (acpi_operand_object *) arg->node;
+		}
+		else {
+			status = acpi_ds_build_internal_object (walk_state, arg,
+					  &obj_desc->package.elements[i]);
+		}
+
+		i++;
+		arg = arg->next;
+	}
+
+	obj_desc->package.flags |= AOPOBJ_DATA_VALID;
+	op->node = (acpi_namespace_node *) obj_desc;
+	return_ACPI_STATUS (status);
 }
 
 
@@ -666,7 +696,7 @@
 
 	node->type = obj_desc->common.type;
 
-	/* Init obj */
+	/* Attach obj to node */
 
 	status = acpi_ns_attach_object (node, obj_desc, node->type);
 
diff -urN linux-2.5.8-pre2/drivers/acpi/dispatcher/dsopcode.c linux-2.5.8-pre3/drivers/acpi/dispatcher/dsopcode.c
--- linux-2.5.8-pre2/drivers/acpi/dispatcher/dsopcode.c	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/drivers/acpi/dispatcher/dsopcode.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: dsopcode - Dispatcher Op Region support and handling of
  *                         "control" opcodes
- *              $Revision: 73 $
+ *              $Revision: 74 $
  *
  *****************************************************************************/
 
@@ -54,7 +54,9 @@
 acpi_status
 acpi_ds_execute_arguments (
 	acpi_namespace_node     *node,
-	acpi_operand_object     *extra_desc)
+	acpi_namespace_node     *scope_node,
+	u32                     aml_length,
+	u8                      *aml_start)
 {
 	acpi_status             status;
 	acpi_parse_object       *op;
@@ -66,17 +68,16 @@
 
 
 	/*
-	 * Allocate a new parser op to be the root of the parsed
-	 * Buffer_field tree
+	 * Allocate a new parser op to be the root of the parsed tree
 	 */
-	op = acpi_ps_alloc_op (AML_SCOPE_OP);
+	op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP);
 	if (!op) {
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
 	/* Save the Node for use in Acpi_ps_parse_aml */
 
-	op->node = acpi_ns_get_parent_node (node);
+	op->node = scope_node;
 
 	/* Create and initialize a new parser state */
 
@@ -85,8 +86,8 @@
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
-	status = acpi_ds_init_aml_walk (walk_state, op, NULL, extra_desc->extra.aml_start,
-			  extra_desc->extra.aml_length, NULL, NULL, 1);
+	status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start,
+			  aml_length, NULL, NULL, 1);
 	if (ACPI_FAILURE (status)) {
 		acpi_ds_delete_walk_state (walk_state);
 		return_ACPI_STATUS (status);
@@ -94,7 +95,7 @@
 
 	walk_state->parse_flags = 0;
 
-	/* Pass1: Parse the entire Buffer_field declaration */
+	/* Pass1: Parse the entire declaration */
 
 	status = acpi_ps_parse_aml (walk_state);
 	if (ACPI_FAILURE (status)) {
@@ -102,7 +103,7 @@
 		return_ACPI_STATUS (status);
 	}
 
-	/* Get and init the actual Field_unit Op created above */
+	/* Get and init the Op created above */
 
 	arg = op->value.arg;
 	op->node = node;
@@ -111,12 +112,12 @@
 
 	/* Evaluate the address and length arguments for the Buffer Field */
 
-	op = acpi_ps_alloc_op (AML_SCOPE_OP);
+	op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP);
 	if (!op) {
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
-	op->node = acpi_ns_get_parent_node (node);
+	op->node = scope_node;
 
 	/* Create and initialize a new parser state */
 
@@ -125,8 +126,8 @@
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
-	status = acpi_ds_init_aml_walk (walk_state, op, NULL, extra_desc->extra.aml_start,
-			  extra_desc->extra.aml_length, NULL, NULL, 3);
+	status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start,
+			  aml_length, NULL, NULL, 3);
 	if (ACPI_FAILURE (status)) {
 		acpi_ds_delete_walk_state (walk_state);
 		return_ACPI_STATUS (status);
@@ -178,7 +179,102 @@
 
 	/* Execute the AML code for the Term_arg arguments */
 
-	status = acpi_ds_execute_arguments (node, extra_desc);
+	status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node),
+			 extra_desc->extra.aml_length, extra_desc->extra.aml_start);
+	return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION:    Acpi_ds_get_buffer_arguments
+ *
+ * PARAMETERS:  Obj_desc        - A valid Bufferobject
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Get Buffer length and initializer byte list.  This implements
+ *              the late evaluation of these attributes.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_buffer_arguments (
+	acpi_operand_object     *obj_desc)
+{
+	acpi_namespace_node     *node;
+	acpi_status             status;
+
+
+	ACPI_FUNCTION_TRACE_PTR ("Ds_get_buffer_arguments", obj_desc);
+
+
+	if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+		return_ACPI_STATUS (AE_OK);
+	}
+
+	/* Get the Buffer node */
+
+	node = obj_desc->buffer.node;
+	if (!node) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+				"No pointer back to NS node in buffer %p\n", obj_desc));
+		return_ACPI_STATUS (AE_AML_INTERNAL);
+	}
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer JIT Init\n"));
+
+	/* Execute the AML code for the Term_arg arguments */
+
+	status = acpi_ds_execute_arguments (node, node,
+			 obj_desc->buffer.aml_length, obj_desc->buffer.aml_start);
+	return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION:    Acpi_ds_get_package_arguments
+ *
+ * PARAMETERS:  Obj_desc        - A valid Packageobject
+ *
+ * RETURN:      Status.
+ *
+ * DESCRIPTION: Get Package length and initializer byte list.  This implements
+ *              the late evaluation of these attributes.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_package_arguments (
+	acpi_operand_object     *obj_desc)
+{
+	acpi_namespace_node     *node;
+	acpi_status             status;
+
+
+	ACPI_FUNCTION_TRACE_PTR ("Ds_get_package_arguments", obj_desc);
+
+
+	if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+		return_ACPI_STATUS (AE_OK);
+	}
+
+	/* Get the Package node */
+
+	node = obj_desc->package.node;
+	if (!node) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+				"No pointer back to NS node in package %p\n", obj_desc));
+		return_ACPI_STATUS (AE_AML_INTERNAL);
+	}
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package JIT Init\n"));
+
+	/* Execute the AML code for the Term_arg arguments */
+
+	status = acpi_ds_execute_arguments (node, node,
+			 obj_desc->package.aml_length, obj_desc->package.aml_start);
 	return_ACPI_STATUS (status);
 }
 
@@ -202,7 +298,7 @@
 {
 	acpi_namespace_node     *node;
 	acpi_status             status;
-	acpi_operand_object     *region_obj2;
+	acpi_operand_object     *extra_desc;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("Ds_get_region_arguments", obj_desc);
@@ -212,22 +308,23 @@
 		return_ACPI_STATUS (AE_OK);
 	}
 
-	region_obj2 = acpi_ns_get_secondary_object (obj_desc);
-	if (!region_obj2) {
+	extra_desc = acpi_ns_get_secondary_object (obj_desc);
+	if (!extra_desc) {
 		return_ACPI_STATUS (AE_NOT_EXIST);
 	}
 
-	/* Get the AML pointer (method object) and region node */
+	/* Get the Region node */
 
 	node = obj_desc->region.node;
 
 	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (node, " [Operation Region]"));
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] Op_region Init at AML %p\n",
-		(char *) &node->name, region_obj2->extra.aml_start));
+		(char *) &node->name, extra_desc->extra.aml_start));
 
 
-	status = acpi_ds_execute_arguments (node, region_obj2);
+	status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node),
+			 extra_desc->extra.aml_length, extra_desc->extra.aml_start);
 	return_ACPI_STATUS (status);
 }
 
@@ -306,7 +403,7 @@
 
 	next_op = op->value.arg;
 
-	/* Acpi_evaluate/create the address and length operands */
+	/* Evaluate/create the address and length operands */
 
 	status = acpi_ds_create_operands (walk_state, next_op);
 	if (ACPI_FAILURE (status)) {
@@ -556,7 +653,7 @@
 
 	next_op = next_op->next;
 
-	/* Acpi_evaluate/create the address and length operands */
+	/* Evaluate/create the address and length operands */
 
 	status = acpi_ds_create_operands (walk_state, next_op);
 	if (ACPI_FAILURE (status)) {
@@ -608,6 +705,95 @@
 
 	return_ACPI_STATUS (status);
 }
+
+
+/*****************************************************************************
+ *
+ * FUNCTION:    Acpi_ds_eval_data_object_operands
+ *
+ * PARAMETERS:  Op              - A valid Data_object Op object
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get the operands and complete the following data objec types:
+ *              Buffer
+ *              Package
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_eval_data_object_operands (
+	acpi_walk_state         *walk_state,
+	acpi_parse_object       *op,
+	acpi_operand_object     *obj_desc)
+{
+	acpi_status             status;
+	acpi_operand_object     *arg_desc;
+	u32                     length;
+
+
+	ACPI_FUNCTION_TRACE ("Ds_eval_data_object_operands");
+
+
+	/* The first operand (for all of these data objects) is the length */
+
+	status = acpi_ds_create_operand (walk_state, op->value.arg, 1);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	status = acpi_ex_resolve_operands (walk_state->opcode,
+			  &(walk_state->operands [walk_state->num_operands -1]),
+			  walk_state);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* Extract length operand */
+
+	arg_desc = walk_state->operands [walk_state->num_operands - 1];
+	length = (u32) arg_desc->integer.value;
+
+	/* Cleanup for length operand */
+
+	acpi_ds_obj_stack_pop (1, walk_state);
+	acpi_ut_remove_reference (arg_desc);
+
+	/*
+	 * Create the actual data object
+	 */
+	switch (op->opcode) {
+	case AML_BUFFER_OP:
+
+		status = acpi_ds_build_internal_buffer_obj (walk_state, op, length, &obj_desc);
+		break;
+
+	case AML_PACKAGE_OP:
+	case AML_VAR_PACKAGE_OP:
+
+		status = acpi_ds_build_internal_package_obj (walk_state, op, length, &obj_desc);
+		break;
+
+	default:
+		return_ACPI_STATUS (AE_AML_BAD_OPCODE);
+	}
+
+	if (ACPI_SUCCESS (status)) {
+		/*
+		 * Return the object in the Walk_state, unless the parent is a package --
+		 * in this case, the return object will be stored in the parse tree
+		 * for the package.
+		 */
+		if ((!op->parent) ||
+			((op->parent->opcode != AML_PACKAGE_OP) &&
+			 (op->parent->opcode != AML_VAR_PACKAGE_OP) &&
+			 (op->parent->opcode != AML_NAME_OP))) {
+			walk_state->result_obj = obj_desc;
+		}
+	}
+
+	return_ACPI_STATUS (status);
+}
 
 
 /*******************************************************************************
diff -urN linux-2.5.8-pre2/drivers/acpi/dispatcher/dsutils.c linux-2.5.8-pre3/drivers/acpi/dispatcher/dsutils.c
--- linux-2.5.8-pre2/drivers/acpi/dispatcher/dsutils.c	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/drivers/acpi/dispatcher/dsutils.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dsutils - Dispatcher utilities
- *              $Revision: 88 $
+ *              $Revision: 89 $
  *
  ******************************************************************************/
 
@@ -133,7 +133,11 @@
 	case AML_CLASS_NAMED_OBJECT:
 
 		if ((op->parent->opcode == AML_REGION_OP)       ||
-			(op->parent->opcode == AML_DATA_REGION_OP)) {
+			(op->parent->opcode == AML_DATA_REGION_OP)  ||
+			(op->parent->opcode == AML_PACKAGE_OP)      ||
+			(op->parent->opcode == AML_VAR_PACKAGE_OP)  ||
+			(op->parent->opcode == AML_BUFFER_OP)       ||
+			(op->parent->opcode == AML_INT_EVAL_SUBTREE_OP)) {
 			/*
 			 * These opcodes allow Term_arg(s) as operands and therefore
 			 * the operands can be method calls.  The result is used.
@@ -144,11 +148,12 @@
 		goto result_not_used;
 
 
-	/*
-	 * In all other cases. the parent will actually use the return
-	 * object, so keep it.
-	 */
 	default:
+
+		/*
+		 * In all other cases. the parent will actually use the return
+		 * object, so keep it.
+		 */
 		goto result_used;
 	}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/dispatcher/dswexec.c linux-2.5.8-pre3/drivers/acpi/dispatcher/dswexec.c
--- linux-2.5.8-pre2/drivers/acpi/dispatcher/dswexec.c	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/drivers/acpi/dispatcher/dswexec.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: dswexec - Dispatcher method execution callbacks;
  *                        dispatch to interpreter.
- *              $Revision: 89 $
+ *              $Revision: 90 $
  *
  *****************************************************************************/
 
@@ -498,6 +498,50 @@
 			break;
 
 
+		case AML_TYPE_CREATE_OBJECT:
+
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+				"Executing Create_object (Buffer/Package) Op=%p\n", op));
+
+			switch (op->parent->opcode) {
+			case AML_NAME_OP:
+
+				/*
+				 * Put the Node on the object stack (Contains the ACPI Name of
+				 * this object)
+				 */
+				walk_state->operands[0] = (void *) op->parent->node;
+				walk_state->num_operands = 1;
+
+				status = acpi_ds_create_node (walk_state, op->parent->node, op->parent);
+				if (ACPI_FAILURE (status)) {
+					break;
+				}
+
+				/* Fall through */
+
+			case AML_INT_EVAL_SUBTREE_OP:
+
+				status = acpi_ds_eval_data_object_operands (walk_state, op, acpi_ns_get_attached_object (op->parent->node));
+				break;
+
+			default:
+
+				status = acpi_ds_eval_data_object_operands (walk_state, op, NULL);
+				break;
+			}
+
+			/*
+			 * If a result object was returned from above, push it on the
+			 * current result stack
+			 */
+			if (ACPI_SUCCESS (status) &&
+				walk_state->result_obj) {
+				status = acpi_ds_result_push (walk_state->result_obj, walk_state);
+			}
+			break;
+
+
 		case AML_TYPE_NAMED_FIELD:
 		case AML_TYPE_NAMED_COMPLEX:
 		case AML_TYPE_NAMED_SIMPLE:
diff -urN linux-2.5.8-pre2/drivers/acpi/dispatcher/dswload.c linux-2.5.8-pre3/drivers/acpi/dispatcher/dswload.c
--- linux-2.5.8-pre2/drivers/acpi/dispatcher/dswload.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/acpi/dispatcher/dswload.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dswload - Dispatcher namespace load callbacks
- *              $Revision: 61 $
+ *              $Revision: 62 $
  *
  *****************************************************************************/
 
@@ -167,7 +167,7 @@
 
 	/* Initialize */
 
-	((acpi_parse2_object *)op)->name = node->name;
+	((acpi_parse2_object *)op)->name = node->name.integer;
 
 	/*
 	 * Put the Node in the "op" object that the parser uses, so we
@@ -381,7 +381,7 @@
 
 			/* Initialize the new op */
 
-			((acpi_parse2_object *)op)->name = node->name;
+			((acpi_parse2_object *)op)->name = node->name.integer;
 			*out_op = op;
 		}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/events/evevent.c linux-2.5.8-pre3/drivers/acpi/events/evevent.c
--- linux-2.5.8-pre2/drivers/acpi/events/evevent.c	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/drivers/acpi/events/evevent.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evevent - Fixed and General Purpose Even handling and dispatch
- *              $Revision: 71 $
+ *              $Revision: 78 $
  *
  *****************************************************************************/
 
@@ -326,11 +326,14 @@
 	 *  FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
 	 *  to be the same size."
 	 */
-	acpi_gbl_gpe_block_info[0].register_count = (u16) ACPI_DIV_2 (acpi_gbl_FADT->gpe0_blk_len);
-	acpi_gbl_gpe_block_info[1].register_count = (u16) ACPI_DIV_2 (acpi_gbl_FADT->gpe1_blk_len);
+	acpi_gbl_gpe_block_info[0].address_space_id = acpi_gbl_FADT->Xgpe0_blk.address_space_id;
+	acpi_gbl_gpe_block_info[1].address_space_id = acpi_gbl_FADT->Xgpe1_blk.address_space_id;
 
-	acpi_gbl_gpe_block_info[0].block_address = (u16) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0_blk.address);
-	acpi_gbl_gpe_block_info[1].block_address = (u16) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address);
+	acpi_gbl_gpe_block_info[0].register_count = (u16) ACPI_DIV_16 (acpi_gbl_FADT->Xgpe0_blk.register_bit_width);
+	acpi_gbl_gpe_block_info[1].register_count = (u16) ACPI_DIV_16 (acpi_gbl_FADT->Xgpe1_blk.register_bit_width);
+
+	acpi_gbl_gpe_block_info[0].block_address = &acpi_gbl_FADT->Xgpe0_blk;
+	acpi_gbl_gpe_block_info[1].block_address = &acpi_gbl_FADT->Xgpe1_blk;
 
 	acpi_gbl_gpe_block_info[0].block_base_number = 0;
 	acpi_gbl_gpe_block_info[1].block_base_number = acpi_gbl_FADT->gpe1_base;
@@ -421,9 +424,20 @@
 			/* Init the Register info for this entire GPE register (8 GPEs) */
 
 			gpe_register_info->base_gpe_number = (u8) (acpi_gbl_gpe_block_info[gpe_block].block_base_number + (ACPI_MUL_8 (i)));
-			gpe_register_info->status_addr = (u16) (acpi_gbl_gpe_block_info[gpe_block].block_address + i);
-			gpe_register_info->enable_addr = (u16) (acpi_gbl_gpe_block_info[gpe_block].block_address + i +
-					  acpi_gbl_gpe_block_info[gpe_block].register_count);
+
+			ACPI_STORE_ADDRESS (gpe_register_info->status_address.address,
+					   (ACPI_GET_ADDRESS (acpi_gbl_gpe_block_info[gpe_block].block_address->address) + i));
+
+			ACPI_STORE_ADDRESS (gpe_register_info->enable_address.address,
+					   (ACPI_GET_ADDRESS (acpi_gbl_gpe_block_info[gpe_block].block_address->address) + i +
+							  acpi_gbl_gpe_block_info[gpe_block].register_count));
+
+			gpe_register_info->status_address.address_space_id = acpi_gbl_gpe_block_info[gpe_block].address_space_id;
+			gpe_register_info->enable_address.address_space_id = acpi_gbl_gpe_block_info[gpe_block].address_space_id;
+			gpe_register_info->status_address.register_bit_width = 8;
+			gpe_register_info->enable_address.register_bit_width = 8;
+			gpe_register_info->status_address.register_bit_offset = 8;
+			gpe_register_info->enable_address.register_bit_offset = 8;
 
 			/* Init the Index mapping info for each GPE number within this register */
 
@@ -440,18 +454,24 @@
 			 * are cleared by writing a '1', while enable registers are cleared
 			 * by writing a '0'.
 			 */
-			acpi_os_write_port (gpe_register_info->enable_addr, 0x00, 8);
-			acpi_os_write_port (gpe_register_info->status_addr, 0xFF, 8);
+
+			acpi_hw_low_level_write (8, 0x00, &gpe_register_info->enable_address, 0);
+			acpi_hw_low_level_write (8, 0xFF, &gpe_register_info->status_address, 0);
 
 			gpe_register++;
 		}
-	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "GPE registers: %X@%8.8X%8.8X (Blk0) %X@%8.8X%8.8X (Blk1)\n",
-		acpi_gbl_gpe_block_info[0].register_count,
-		ACPI_HIDWORD (acpi_gbl_FADT->Xgpe0_blk.address), ACPI_LODWORD (acpi_gbl_FADT->Xgpe0_blk.address),
-		acpi_gbl_gpe_block_info[1].register_count,
-		ACPI_HIDWORD (acpi_gbl_FADT->Xgpe1_blk.address), ACPI_LODWORD (acpi_gbl_FADT->Xgpe1_blk.address)));
+		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "GPE Block%d: %X registers at %8.8X%8.8X\n",
+			gpe_block, acpi_gbl_gpe_block_info[0].register_count,
+			ACPI_HIDWORD (acpi_gbl_gpe_block_info[gpe_block].block_address->address),
+			ACPI_LODWORD (acpi_gbl_gpe_block_info[gpe_block].block_address->address)));
+
+		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "GPE Block%d Range GPE #%2.2X to GPE #%2.2X\n",
+			gpe_block,
+			acpi_gbl_gpe_block_info[gpe_block].block_base_number,
+			acpi_gbl_gpe_block_info[gpe_block].block_base_number +
+				((acpi_gbl_gpe_block_info[gpe_block].register_count * 8) -1)));
+	}
 
 	return_ACPI_STATUS (AE_OK);
 
@@ -645,17 +665,18 @@
 	for (i = 0; i < acpi_gbl_gpe_register_count; i++) {
 		gpe_register_info = &acpi_gbl_gpe_register_info[i];
 
-		acpi_os_read_port (gpe_register_info->status_addr,
-				  &gpe_register_info->status, 8);
+		gpe_register_info->status = (u8) acpi_hw_low_level_read (8,
+				   &gpe_register_info->status_address, 0);
 
-		acpi_os_read_port (gpe_register_info->enable_addr,
-				  &gpe_register_info->enable, 8);
+		gpe_register_info->enable = (u8) acpi_hw_low_level_read (8,
+				   &gpe_register_info->enable_address, 0);
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
-			"GPE block at %X - Enable %08X Status %08X\n",
-			gpe_register_info->enable_addr,
-			gpe_register_info->status,
-			gpe_register_info->enable));
+			"GPE block at %8.8X%8.8X - Enable %08X Status %08X\n",
+			ACPI_HIDWORD (gpe_register_info->enable_address.address),
+			ACPI_LODWORD (gpe_register_info->enable_address.address),
+			gpe_register_info->enable,
+			gpe_register_info->status));
 
 		/* First check if there is anything active at all in this register */
 
@@ -816,18 +837,18 @@
 	}
 	else if (gpe_info->method_handle) {
 		/*
+		 * Disable GPE, so it doesn't keep firing before the method has a
+		 * chance to run.
+		 */
+		acpi_hw_disable_gpe (gpe_number);
+
+		/*
 		 * Execute the method associated with the GPE.
 		 */
 		if (ACPI_FAILURE (acpi_os_queue_for_execution (OSD_PRIORITY_GPE,
 				 acpi_ev_asynch_execute_gpe_method,
 				 ACPI_TO_POINTER (gpe_number)))) {
-			ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%X], disabling event\n", gpe_number));
-
-			/*
-			 * Disable the GPE on error.  The GPE will remain disabled until the ACPI
-			 * Core Subsystem is restarted, or the handler is reinstalled.
-			 */
-			acpi_hw_disable_gpe (gpe_number);
+			ACPI_REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%X], event is disabled\n", gpe_number));
 		}
 	}
 	else {
diff -urN linux-2.5.8-pre2/drivers/acpi/events/evmisc.c linux-2.5.8-pre3/drivers/acpi/events/evmisc.c
--- linux-2.5.8-pre2/drivers/acpi/events/evmisc.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/acpi/events/evmisc.c	Tue Apr  9 18:35:19 2002
@@ -1,8 +1,7 @@
 /******************************************************************************
  *
- * Module Name: evmisc - ACPI device notification handler dispatch
- *                       and ACPI Global Lock support
- *              $Revision: 47 $
+ * Module Name: evmisc - Miscellaneous event manager support functions
+ *              $Revision: 48 $
  *
  *****************************************************************************/
 
@@ -35,6 +34,40 @@
 
 
 /*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ev_is_notify_object
+ *
+ * PARAMETERS:  Node            - Node to check
+ *
+ * RETURN:      TRUE if notifies allowed on this object
+ *
+ * DESCRIPTION: Check type of node for a object that supports notifies.
+ *
+ *              TBD: This could be replaced by a flag bit in the node.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ev_is_notify_object (
+	acpi_namespace_node     *node)
+{
+	switch (node->type) {
+	case ACPI_TYPE_DEVICE:
+	case ACPI_TYPE_PROCESSOR:
+	case ACPI_TYPE_POWER:
+	case ACPI_TYPE_THERMAL:
+		/*
+		 * These are the ONLY objects that can receive ACPI notifications
+		 */
+		return (TRUE);
+
+	default:
+		return (FALSE);
+	}
+}
+
+
+/*******************************************************************************
  *
  * FUNCTION:    Acpi_ev_get_gpe_register_index
  *
diff -urN linux-2.5.8-pre2/drivers/acpi/events/evxface.c linux-2.5.8-pre3/drivers/acpi/events/evxface.c
--- linux-2.5.8-pre2/drivers/acpi/events/evxface.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/events/evxface.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evxface - External interfaces for ACPI events
- *              $Revision: 125 $
+ *              $Revision: 126 $
  *
  *****************************************************************************/
 
@@ -191,7 +191,7 @@
 {
 	acpi_operand_object     *obj_desc;
 	acpi_operand_object     *notify_obj;
-	acpi_namespace_node     *device_node;
+	acpi_namespace_node     *node;
 	acpi_status             status;
 
 
@@ -200,7 +200,8 @@
 
 	/* Parameter validation */
 
-	if ((!handler) ||
+	if ((!device)  ||
+		(!handler) ||
 		(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
@@ -212,8 +213,8 @@
 
 	/* Convert and validate the device handle */
 
-	device_node = acpi_ns_map_handle_to_node (device);
-	if (!device_node) {
+	node = acpi_ns_map_handle_to_node (device);
+	if (!node) {
 		status = AE_BAD_PARAMETER;
 		goto unlock_and_exit;
 	}
@@ -236,12 +237,12 @@
 		}
 
 		if (handler_type == ACPI_SYSTEM_NOTIFY) {
-			acpi_gbl_sys_notify.node = device_node;
+			acpi_gbl_sys_notify.node = node;
 			acpi_gbl_sys_notify.handler = handler;
 			acpi_gbl_sys_notify.context = context;
 		}
 		else /* ACPI_DEVICE_NOTIFY */ {
-			acpi_gbl_drv_notify.node = device_node;
+			acpi_gbl_drv_notify.node = node;
 			acpi_gbl_drv_notify.handler = handler;
 			acpi_gbl_drv_notify.context = context;
 		}
@@ -255,28 +256,24 @@
 	 * Note that only certain object types can receive notifications.
 	 */
 	else {
-		/*
-		 * These are the ONLY objects that can receive ACPI notifications
-		 */
-		if ((device_node->type != ACPI_TYPE_DEVICE)    &&
-			(device_node->type != ACPI_TYPE_PROCESSOR) &&
-			(device_node->type != ACPI_TYPE_POWER)     &&
-			(device_node->type != ACPI_TYPE_THERMAL)) {
-			status = AE_BAD_PARAMETER;
+		/* Notifies allowed on this object? */
+
+		if (!acpi_ev_is_notify_object (node)) {
+			status = AE_TYPE;
 			goto unlock_and_exit;
 		}
 
 		/* Check for an existing internal object */
 
-		obj_desc = acpi_ns_get_attached_object (device_node);
+		obj_desc = acpi_ns_get_attached_object (node);
 		if (obj_desc) {
 
 			/* Object exists - make sure there's no handler */
 
 			if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
-				  obj_desc->device.sys_handler) ||
+				  obj_desc->common_notify.sys_handler) ||
 				((handler_type == ACPI_DEVICE_NOTIFY) &&
-				  obj_desc->device.drv_handler)) {
+				  obj_desc->common_notify.drv_handler)) {
 				status = AE_ALREADY_EXISTS;
 				goto unlock_and_exit;
 			}
@@ -284,7 +281,7 @@
 		else {
 			/* Create a new object */
 
-			obj_desc = acpi_ut_create_internal_object (device_node->type);
+			obj_desc = acpi_ut_create_internal_object (node->type);
 			if (!obj_desc) {
 				status = AE_NO_MEMORY;
 				goto unlock_and_exit;
@@ -292,7 +289,7 @@
 
 			/* Attach new object to the Node */
 
-			status = acpi_ns_attach_object (device, obj_desc, device_node->type);
+			status = acpi_ns_attach_object (device, obj_desc, node->type);
 			if (ACPI_FAILURE (status)) {
 				goto unlock_and_exit;
 			}
@@ -306,16 +303,15 @@
 			goto unlock_and_exit;
 		}
 
-		notify_obj->notify_handler.node = device_node;
+		notify_obj->notify_handler.node = node;
 		notify_obj->notify_handler.handler = handler;
 		notify_obj->notify_handler.context = context;
 
-
 		if (handler_type == ACPI_SYSTEM_NOTIFY) {
-			obj_desc->device.sys_handler = notify_obj;
+			obj_desc->common_notify.sys_handler = notify_obj;
 		}
 		else /* ACPI_DEVICE_NOTIFY */ {
-			obj_desc->device.drv_handler = notify_obj;
+			obj_desc->common_notify.drv_handler = notify_obj;
 		}
 	}
 
@@ -349,7 +345,7 @@
 {
 	acpi_operand_object     *notify_obj;
 	acpi_operand_object     *obj_desc;
-	acpi_namespace_node     *device_node;
+	acpi_namespace_node     *node;
 	acpi_status             status;
 
 
@@ -358,7 +354,8 @@
 
 	/* Parameter validation */
 
-	if ((!handler) ||
+	if ((!device)  ||
+		(!handler) ||
 		(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
@@ -370,8 +367,8 @@
 
 	/* Convert and validate the device handle */
 
-	device_node = acpi_ns_map_handle_to_node (device);
-	if (!device_node) {
+	node = acpi_ns_map_handle_to_node (device);
+	if (!node) {
 		status = AE_BAD_PARAMETER;
 		goto unlock_and_exit;
 	}
@@ -406,20 +403,16 @@
 	 * All Other Objects
 	 */
 	else {
-		/*
-		 * These are the ONLY objects that can receive ACPI notifications
-		 */
-		if ((device_node->type != ACPI_TYPE_DEVICE)    &&
-			(device_node->type != ACPI_TYPE_PROCESSOR) &&
-			(device_node->type != ACPI_TYPE_POWER)     &&
-			(device_node->type != ACPI_TYPE_THERMAL)) {
-			status = AE_BAD_PARAMETER;
+		/* Notifies allowed on this object? */
+
+		if (!acpi_ev_is_notify_object (node)) {
+			status = AE_TYPE;
 			goto unlock_and_exit;
 		}
 
 		/* Check for an existing internal object */
 
-		obj_desc = acpi_ns_get_attached_object (device_node);
+		obj_desc = acpi_ns_get_attached_object (node);
 		if (!obj_desc) {
 			status = AE_NOT_EXIST;
 			goto unlock_and_exit;
@@ -428,10 +421,10 @@
 		/* Object exists - make sure there's an existing handler */
 
 		if (handler_type == ACPI_SYSTEM_NOTIFY) {
-			notify_obj = obj_desc->device.sys_handler;
+			notify_obj = obj_desc->common_notify.sys_handler;
 		}
 		else {
-			notify_obj = obj_desc->device.drv_handler;
+			notify_obj = obj_desc->common_notify.drv_handler;
 		}
 
 		if ((!notify_obj) ||
@@ -443,10 +436,10 @@
 		/* Remove the handler */
 
 		if (handler_type == ACPI_SYSTEM_NOTIFY) {
-			obj_desc->device.sys_handler = NULL;
+			obj_desc->common_notify.sys_handler = NULL;
 		}
 		else {
-			obj_desc->device.drv_handler = NULL;
+			obj_desc->common_notify.drv_handler = NULL;
 		}
 
 		acpi_ut_remove_reference (notify_obj);
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exconfig.c linux-2.5.8-pre3/drivers/acpi/executer/exconfig.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exconfig.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exconfig.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
- *              $Revision: 59 $
+ *              $Revision: 60 $
  *
  *****************************************************************************/
 
@@ -329,7 +329,7 @@
 		 * Read the entire field and thus the entire table.  Buffer is
 		 * allocated during the read.
 		 */
-		status = acpi_ex_read_data_from_field (obj_desc, &buffer_desc);
+		status = acpi_ex_read_data_from_field (walk_state, obj_desc, &buffer_desc);
 		if (ACPI_FAILURE (status)) {
 			goto cleanup;
 		}
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exconvrt.c linux-2.5.8-pre3/drivers/acpi/executer/exconvrt.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exconvrt.c	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exconvrt.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exconvrt - Object conversion routines
- *              $Revision: 30 $
+ *              $Revision: 32 $
  *
  *****************************************************************************/
 
@@ -215,8 +215,7 @@
 		if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) {
 			/*
 			 * We are running a method that exists in a 32-bit ACPI table.
-			 * Truncate the value to 32 bits by zeroing out the upper
-			 * 32-bit field
+			 * Use only 32 bits of the Integer for conversion.
 			 */
 			integer_size = sizeof (u32);
 		}
@@ -259,6 +258,9 @@
 		return_ACPI_STATUS (AE_TYPE);
 	}
 
+	/* Mark buffer initialized */
+
+	(*result_desc)->common.flags |= AOPOBJ_DATA_VALID;
 	return_ACPI_STATUS (AE_OK);
 }
 
@@ -399,8 +401,7 @@
 		if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) {
 			/*
 			 * We are running a method that exists in a 32-bit ACPI table.
-			 * Truncate the value to 32 bits by zeroing out the upper
-			 * 32-bit field
+			 * Use only 32 bits of the Integer
 			 */
 			integer_size = sizeof (u32);
 		}
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exdump.c linux-2.5.8-pre3/drivers/acpi/executer/exdump.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exdump.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exdump.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exdump - Interpreter debug output routines
- *              $Revision: 145 $
+ *              $Revision: 147 $
  *
  *****************************************************************************/
 
@@ -149,7 +149,7 @@
 	ACPI_FUNCTION_NAME ("Ex_dump_operand")
 
 
-	if (!((ACPI_LV_INFO & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
+	if (!((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
 		return (AE_OK);
 	}
 
@@ -159,25 +159,25 @@
 		 * since most (if not all)
 		 * code that dumps the stack expects something to be there!
 		 */
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Null stack entry ptr\n"));
+		acpi_os_printf ("Null stack entry ptr\n");
 		return (AE_OK);
 	}
 
 	if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%p NS Node: ", obj_desc));
-		ACPI_DUMP_ENTRY (obj_desc, ACPI_LV_INFO);
+		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p NS Node: ", obj_desc));
+		ACPI_DUMP_ENTRY (obj_desc, ACPI_LV_EXEC);
 		return (AE_OK);
 	}
 
 	if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_INTERNAL) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%p is not a local object\n", obj_desc));
+		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p is not a local object\n", obj_desc));
 		ACPI_DUMP_BUFFER (obj_desc, sizeof (acpi_operand_object));
 		return (AE_OK);
 	}
 
 	/*  Obj_desc is a valid object */
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%p ", obj_desc));
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc));
 
 	switch (obj_desc->common.type) {
 	case INTERNAL_TYPE_REFERENCE:
@@ -427,7 +427,7 @@
 
 		if (!obj_desc->buffer_field.buffer_obj)
 		{
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "*NULL* \n"));
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n"));
 		}
 
 		else if (ACPI_TYPE_BUFFER !=
@@ -541,7 +541,7 @@
 	}
 
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 		"************* Operand Stack Contents (Opcode [%s], %d Operands)\n",
 		ident, num_levels));
 
@@ -562,7 +562,7 @@
 		}
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 		"************* Stack dump from %s(%d), %s\n",
 		module_name, line_number, note));
 	return;
@@ -734,7 +734,6 @@
 		acpi_ex_out_integer ("Flags",        obj_desc->package.flags);
 		acpi_ex_out_integer ("Count",        obj_desc->package.count);
 		acpi_ex_out_pointer ("Elements",     obj_desc->package.elements);
-		acpi_ex_out_pointer ("Next_element", obj_desc->package.next_element);
 
 		/* Dump the package contents */
 
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exfield.c linux-2.5.8-pre3/drivers/acpi/executer/exfield.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exfield.c	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exfield.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
- *              $Revision: 105 $
+ *              $Revision: 108 $
  *
  *****************************************************************************/
 
@@ -41,7 +41,8 @@
  *
  * FUNCTION:    Acpi_ex_read_data_from_field
  *
- * PARAMETERS:  Obj_desc            - The named field
+ * PARAMETERS:  Walk_state          - Current execution state
+ *              Obj_desc            - The named field
  *              Ret_buffer_desc     - Where the return data object is stored
  *
  * RETURN:      Status
@@ -53,12 +54,14 @@
 
 acpi_status
 acpi_ex_read_data_from_field (
+	acpi_walk_state         *walk_state,
 	acpi_operand_object     *obj_desc,
 	acpi_operand_object     **ret_buffer_desc)
 {
 	acpi_status             status;
 	acpi_operand_object     *buffer_desc;
 	u32                     length;
+	u32                     integer_size;
 	void                    *buffer;
 	u8                      locked;
 
@@ -97,7 +100,18 @@
 	 */
 	length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->field.bit_length);
 
-	if (length > sizeof (acpi_integer)) {
+	/* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */
+
+	integer_size = sizeof (acpi_integer);
+	if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) {
+		/*
+		 * We are running a method that exists in a 32-bit ACPI table.
+		 * Integer size is 4.
+		 */
+		integer_size = sizeof (u32);
+	}
+
+	if (length > integer_size) {
 		/* Field is too large for an Integer, create a Buffer instead */
 
 		buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
@@ -113,6 +127,7 @@
 			return_ACPI_STATUS (AE_NO_MEMORY);
 		}
 
+		buffer_desc->common.flags = AOPOBJ_DATA_VALID;
 		buffer_desc->buffer.length = length;
 		buffer = buffer_desc->buffer.pointer;
 	}
@@ -124,14 +139,15 @@
 			return_ACPI_STATUS (AE_NO_MEMORY);
 		}
 
-		length = sizeof (buffer_desc->integer.value);
+		length = integer_size;
+		buffer_desc->integer.value = 0;
 		buffer = &buffer_desc->integer.value;
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 		"Obj=%p Type=%X Buf=%p Len=%X\n",
 		obj_desc, obj_desc->common.type, buffer, length));
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 		"Field_write: Bit_len=%X Bit_off=%X Byte_off=%X\n",
 		obj_desc->common_field.bit_length,
 		obj_desc->common_field.start_field_bit_offset,
@@ -257,10 +273,10 @@
 		length = required_length;
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 		"Obj=%p Type=%X Buf=%p Len=%X\n",
 		obj_desc, obj_desc->common.type, buffer, length));
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 		"Field_read: Bit_len=%X Bit_off=%X Byte_off=%X\n",
 		obj_desc->common_field.bit_length,
 		obj_desc->common_field.start_field_bit_offset,
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exfldio.c linux-2.5.8-pre3/drivers/acpi/executer/exfldio.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exfldio.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exfldio.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exfldio - Aml Field I/O
- *              $Revision: 82 $
+ *              $Revision: 84 $
  *
  *****************************************************************************/
 
@@ -148,7 +148,7 @@
 	ACPI_PHYSICAL_ADDRESS   address;
 
 
-	ACPI_FUNCTION_TRACE ("Acpi_ex_access_region");
+	ACPI_FUNCTION_TRACE ("Ex_access_region");
 
 
 	/*
@@ -672,7 +672,7 @@
 	 */
 	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
 	if (byte_field_length > buffer_length) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 			"Field size %X (bytes) too large for buffer (%X)\n",
 			byte_field_length, buffer_length));
 
@@ -684,7 +684,7 @@
 	datum_count = ACPI_ROUND_UP_TO (byte_field_length,
 			   obj_desc->common_field.access_byte_width);
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 		"Byte_len=%x, Datum_len=%x, Byte_gran=%x\n",
 		byte_field_length, datum_count,obj_desc->common_field.access_byte_width));
 
@@ -852,7 +852,7 @@
 	 */
 	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
 	if (buffer_length < byte_field_length) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Buffer length %X too small for field %X\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n",
 			buffer_length, byte_field_length));
 
 		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
@@ -862,7 +862,7 @@
 
 	datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width);
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 		"Byte_len=%x, Datum_len=%x, Byte_gran=%x\n",
 		byte_field_length, datum_count, obj_desc->common_field.access_byte_width));
 
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exoparg1.c linux-2.5.8-pre3/drivers/acpi/executer/exoparg1.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exoparg1.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exoparg1.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg1 - AML execution - opcodes with 1 argument
- *              $Revision: 134 $
+ *              $Revision: 135 $
  *
  *****************************************************************************/
 
@@ -791,10 +791,21 @@
 				 */
 				switch (operand[0]->reference.target_type) {
 				case ACPI_TYPE_BUFFER_FIELD:
+
+					/* Ensure that the Buffer arguments are evaluated */
+
+					temp_desc = operand[0]->reference.object;
+#if 0
+
+					status = acpi_ds_get_buffer_arguments (temp_desc);
+					if (ACPI_FAILURE (status)) {
+						goto cleanup;
+					}
+#endif
+
 					/*
-					 * The target is a buffer, we must create a new object that
-					 * contains one element of the buffer, the element pointed
-					 * to by the index.
+					 * Create a new object that contains one element of the
+					 * buffer -- the element pointed to by the index.
 					 *
 					 * NOTE: index into a buffer is NOT a pointer to a
 					 * sub-buffer of the main buffer, it is only a pointer to a
@@ -811,7 +822,6 @@
 					 * indexed location, we don't need to add an additional
 					 * reference to the buffer itself.
 					 */
-					temp_desc = operand[0]->reference.object;
 					return_desc->integer.value =
 						temp_desc->buffer.pointer[operand[0]->reference.offset];
 					break;
@@ -819,10 +829,17 @@
 
 				case ACPI_TYPE_PACKAGE:
 
+#if 0
+					/* Ensure that the Package arguments are evaluated */
+
+					status = acpi_ds_get_package_arguments (operand[0]->reference.object);
+					if (ACPI_FAILURE (status)) {
+						goto cleanup;
+					}
+#endif
 					/*
-					 * The target is a package, we want to return the referenced
-					 * element of the package.  We must add another reference to
-					 * this object, however.
+					 * Return the referenced element of the package.  We must add
+					 * another reference to the referenced object, however.
 					 */
 					return_desc = *(operand[0]->reference.where);
 					if (!return_desc) {
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exoparg2.c linux-2.5.8-pre3/drivers/acpi/executer/exoparg2.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exoparg2.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exoparg2.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg2 - AML execution - opcodes with 2 arguments
- *              $Revision: 104 $
+ *              $Revision: 105 $
  *
  *****************************************************************************/
 
@@ -84,49 +84,45 @@
 	acpi_status             status = AE_OK;
 
 
-	ACPI_FUNCTION_TRACE_STR ("Ex_opcode_2A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+	ACPI_FUNCTION_TRACE_STR ("Ex_opcode_2A_0T_0R",
+			acpi_ps_get_opcode_name (walk_state->opcode));
 
 
 	/* Examine the opcode */
 
 	switch (walk_state->opcode) {
-
 	case AML_NOTIFY_OP:         /* Notify (Notify_object, Notify_value) */
 
 		/* The first operand is a namespace node */
 
 		node = (acpi_namespace_node *) operand[0];
 
-		/* The node must refer to a device or thermal zone or processor */
-
-		switch (node->type) {
-		case ACPI_TYPE_DEVICE:
-		case ACPI_TYPE_THERMAL:
-		case ACPI_TYPE_PROCESSOR:
-
-			/*
-			 * Dispatch the notify to the appropriate handler
-			 * NOTE: the request is queued for execution after this method
-			 * completes.  The notify handlers are NOT invoked synchronously
-			 * from this thread -- because handlers may in turn run other
-			 * control methods.
-			 */
-			status = acpi_ev_queue_notify_request (node,
-					 (u32) operand[1]->integer.value);
-			break;
+		/* Notifies allowed on this object? */
 
-		default:
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unexpected notify object type %X\n",
-				node->type));
+		if (!acpi_ev_is_notify_object (node)) {
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unexpected notify object type [%s]\n",
+					acpi_ut_get_type_name (node->type)));
 
 			status = AE_AML_OPERAND_TYPE;
 			break;
 		}
+
+		/*
+		 * Dispatch the notify to the appropriate handler
+		 * NOTE: the request is queued for execution after this method
+		 * completes.  The notify handlers are NOT invoked synchronously
+		 * from this thread -- because handlers may in turn run other
+		 * control methods.
+		 */
+		status = acpi_ev_queue_notify_request (node,
+				  (u32) operand[1]->integer.value);
 		break;
 
+
 	default:
 
-		ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_0T_0R: Unknown opcode %X\n", walk_state->opcode));
+		ACPI_REPORT_ERROR (("Acpi_ex_opcode_2A_0T_0R: Unknown opcode %X\n",
+				walk_state->opcode));
 		status = AE_AML_BAD_OPCODE;
 	}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exprep.c linux-2.5.8-pre3/drivers/acpi/executer/exprep.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exprep.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exprep.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities
- *              $Revision: 114 $
+ *              $Revision: 115 $
  *
  *****************************************************************************/
 
@@ -204,61 +204,77 @@
 	 * two pieces of information - the width of each field access and the
 	 * necessary Byte_alignment (address granularity) of the access.
 	 *
-	 * For Any_acc, the Access_bit_width is the largest width that is both necessary
-	 * and possible in an attempt to access the whole field in one
-	 * I/O operation.  However, for Any_acc, the Byte_alignment is always one byte.
+	 * For Any_acc, the Access_bit_width is the largest width that is both
+	 * necessary and possible in an attempt to access the whole field in one
+	 * I/O operation.  However, for Any_acc, the Byte_alignment is always one
+	 * byte.
 	 *
 	 * For all Buffer Fields, the Byte_alignment is always one byte.
 	 *
-	 * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is the
-	 * same (equivalent) as the Byte_alignment.
+	 * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is
+	 * the same (equivalent) as the Byte_alignment.
 	 */
-	access_bit_width = acpi_ex_decode_field_access (obj_desc, field_flags, &byte_alignment);
+	access_bit_width = acpi_ex_decode_field_access (obj_desc, field_flags,
+			  &byte_alignment);
 	if (!access_bit_width) {
 		return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
 	}
 
 	/* Setup width (access granularity) fields */
 
-	obj_desc->common_field.access_byte_width = (u8) ACPI_DIV_8 (access_bit_width); /* 1, 2, 4,  8 */
+	obj_desc->common_field.access_byte_width = (u8)
+			ACPI_DIV_8 (access_bit_width); /* 1, 2, 4,  8 */
 
 	/*
-	 * Base_byte_offset is the address of the start of the field within the region. It is
-	 * the byte address of the first *datum* (field-width data unit) of the field.
-	 * (i.e., the first datum that contains at least the first *bit* of the field.)
-	 * Note: Byte_alignment is always either equal to the Access_bit_width or 8 (Byte access),
-	 * and it defines the addressing granularity of the parent region or buffer.
+	 * Base_byte_offset is the address of the start of the field within the
+	 * region.  It is the byte address of the first *datum* (field-width data
+	 * unit) of the field. (i.e., the first datum that contains at least the
+	 * first *bit* of the field.)
+	 *
+	 * Note: Byte_alignment is always either equal to the Access_bit_width or 8
+	 * (Byte access), and it defines the addressing granularity of the parent
+	 * region or buffer.
 	 */
-	nearest_byte_address                     = ACPI_ROUND_BITS_DOWN_TO_BYTES (field_bit_position);
-	obj_desc->common_field.base_byte_offset  = ACPI_ROUND_DOWN (nearest_byte_address, byte_alignment);
+	nearest_byte_address =
+			ACPI_ROUND_BITS_DOWN_TO_BYTES (field_bit_position);
+	obj_desc->common_field.base_byte_offset =
+			ACPI_ROUND_DOWN (nearest_byte_address, byte_alignment);
 
 	/*
-	 * Start_field_bit_offset is the offset of the first bit of the field within a field datum.
+	 * Start_field_bit_offset is the offset of the first bit of the field within
+	 * a field datum.
 	 */
-	obj_desc->common_field.start_field_bit_offset = (u8) (field_bit_position -
-			  ACPI_MUL_8 (obj_desc->common_field.base_byte_offset));
+	obj_desc->common_field.start_field_bit_offset = (u8)
+		(field_bit_position - ACPI_MUL_8 (obj_desc->common_field.base_byte_offset));
 
 	/*
 	 * Valid bits -- the number of bits that compose a partial datum,
-	 * 1) At the end of the field within the region (arbitrary starting bit offset)
-	 * 2) At the end of a buffer used to contain the field (starting offset always zero)
+	 * 1) At the end of the field within the region (arbitrary starting bit
+	 *    offset)
+	 * 2) At the end of a buffer used to contain the field (starting offset
+	 *    always zero)
 	 */
-	obj_desc->common_field.end_field_valid_bits = (u8) ((obj_desc->common_field.start_field_bit_offset + field_bit_length) %
-			   access_bit_width);
-	obj_desc->common_field.end_buffer_valid_bits = (u8) (field_bit_length % access_bit_width); /* Start_buffer_bit_offset always = 0 */
+	obj_desc->common_field.end_field_valid_bits = (u8)
+		((obj_desc->common_field.start_field_bit_offset + field_bit_length) %
+				  access_bit_width);
+	/* Start_buffer_bit_offset always = 0 */
+
+	obj_desc->common_field.end_buffer_valid_bits = (u8)
+		(field_bit_length % access_bit_width);
 
 	/*
-	 * Datum_valid_bits is the number of valid field bits in the first field datum.
+	 * Datum_valid_bits is the number of valid field bits in the first
+	 * field datum.
 	 */
-	obj_desc->common_field.datum_valid_bits  = (u8) (access_bit_width -
-			  obj_desc->common_field.start_field_bit_offset);
+	obj_desc->common_field.datum_valid_bits  = (u8)
+		(access_bit_width - obj_desc->common_field.start_field_bit_offset);
 
 	/*
 	 * Does the entire field fit within a single field access element? (datum)
 	 * (i.e., without crossing a datum boundary)
 	 */
 	if ((obj_desc->common_field.start_field_bit_offset + field_bit_length) <=
-		(u16) access_bit_width) {
+			(u16) access_bit_width) {
 		obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM;
 	}
 
@@ -341,7 +357,7 @@
 
 		acpi_ut_add_reference (obj_desc->field.region_obj);
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 			"Region_field: Bitoff=%X Off=%X Gran=%X Region %p\n",
 			obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset,
 			obj_desc->field.access_byte_width, obj_desc->field.region_obj));
@@ -359,9 +375,12 @@
 		acpi_ut_add_reference (obj_desc->bank_field.region_obj);
 		acpi_ut_add_reference (obj_desc->bank_field.bank_obj);
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Bank Field: Bit_off=%X Off=%X Gran=%X Region %p Bank_reg %p\n",
-			obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset,
-			obj_desc->field.access_byte_width, obj_desc->bank_field.region_obj,
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+			"Bank Field: Bit_off=%X Off=%X Gran=%X Region %p Bank_reg %p\n",
+			obj_desc->bank_field.start_field_bit_offset,
+			obj_desc->bank_field.base_byte_offset,
+			obj_desc->field.access_byte_width,
+			obj_desc->bank_field.region_obj,
 			obj_desc->bank_field.bank_obj));
 		break;
 
@@ -370,8 +389,8 @@
 
 		obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node);
 		obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node);
-		obj_desc->index_field.value  = (u32) (info->field_bit_position /
-				  ACPI_MUL_8 (obj_desc->field.access_byte_width));
+		obj_desc->index_field.value  = (u32)
+			(info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width));
 
 		if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) {
 			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Index Object\n"));
@@ -383,9 +402,12 @@
 		acpi_ut_add_reference (obj_desc->index_field.data_obj);
 		acpi_ut_add_reference (obj_desc->index_field.index_obj);
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Index_field: bitoff=%X off=%X gran=%X Index %p Data %p\n",
-			obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset,
-			obj_desc->field.access_byte_width, obj_desc->index_field.index_obj,
+		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+			"Index_field: bitoff=%X off=%X gran=%X Index %p Data %p\n",
+			obj_desc->index_field.start_field_bit_offset,
+			obj_desc->index_field.base_byte_offset,
+			obj_desc->field.access_byte_width,
+			obj_desc->index_field.index_obj,
 			obj_desc->index_field.data_obj));
 		break;
 	}
@@ -397,7 +419,7 @@
 	status = acpi_ns_attach_object (info->field_node, obj_desc,
 			  acpi_ns_get_type (info->field_node));
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "set Named_obj %p (%4.4s) val = %p\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "set Named_obj %p (%4.4s) val = %p\n",
 			info->field_node, (char *) &(info->field_node->name), obj_desc));
 
 	/* Remove local reference to the object */
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exregion.c linux-2.5.8-pre3/drivers/acpi/executer/exregion.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exregion.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exregion.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exregion - ACPI default Op_region (address space) handlers
- *              $Revision: 72 $
+ *              $Revision: 74 $
  *
  *****************************************************************************/
 
@@ -69,7 +69,6 @@
 	acpi_mem_space_context  *mem_info = region_context;
 	u32                     length;
 	u32                     window_size;
-	u32                     remaining;
 
 
 	ACPI_FUNCTION_TRACE ("Ex_system_memory_space_handler");
@@ -123,13 +122,10 @@
 		 * Don't attempt to map memory beyond the end of the region, and
 		 * constrain the maximum mapping size to something reasonable.
 		 */
-		remaining = (u32) ((mem_info->address + (ACPI_PHYSICAL_ADDRESS) mem_info->length) - address);
-		if (remaining > SYSMEM_REGION_WINDOW_SIZE) {
+		window_size = (u32) ((mem_info->address + mem_info->length) - address);
+		if (window_size > SYSMEM_REGION_WINDOW_SIZE) {
 			window_size = SYSMEM_REGION_WINDOW_SIZE;
 		}
-		else {
-			window_size = remaining;
-		}
 
 		/* Create a new mapping starting at the address given */
 
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exresnte.c linux-2.5.8-pre3/drivers/acpi/executer/exresnte.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exresnte.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exresnte.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresnte - AML Interpreter object resolution
- *              $Revision: 50 $
+ *              $Revision: 52 $
  *
  *****************************************************************************/
 
@@ -122,10 +122,13 @@
 			return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 		}
 
-		/* Return an additional reference to the object */
+		status = acpi_ds_get_package_arguments (source_desc);
+		if (ACPI_SUCCESS (status)) {
+			/* Return an additional reference to the object */
 
-		obj_desc = source_desc;
-		acpi_ut_add_reference (obj_desc);
+			obj_desc = source_desc;
+			acpi_ut_add_reference (obj_desc);
+		}
 		break;
 
 
@@ -137,10 +140,13 @@
 			return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 		}
 
-		/* Return an additional reference to the object */
+		status = acpi_ds_get_buffer_arguments (source_desc);
+		if (ACPI_SUCCESS (status)) {
+			/* Return an additional reference to the object */
 
-		obj_desc = source_desc;
-		acpi_ut_add_reference (obj_desc);
+			obj_desc = source_desc;
+			acpi_ut_add_reference (obj_desc);
+		}
 		break;
 
 
@@ -182,7 +188,7 @@
 		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Field_read Node=%p Source_desc=%p Type=%X\n",
 			node, source_desc, entry_type));
 
-		status = acpi_ex_read_data_from_field (source_desc, &obj_desc);
+		status = acpi_ex_read_data_from_field (walk_state, source_desc, &obj_desc);
 		break;
 
 	/*
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exresolv.c linux-2.5.8-pre3/drivers/acpi/executer/exresolv.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exresolv.c	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exresolv.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresolv - AML Interpreter object resolution
- *              $Revision: 106 $
+ *              $Revision: 109 $
  *
  *****************************************************************************/
 
@@ -94,7 +94,7 @@
 		}
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Resolved object %p\n", *stack_ptr));
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr));
 	return_ACPI_STATUS (AE_OK);
 }
 
@@ -177,7 +177,7 @@
 			acpi_ut_remove_reference (stack_desc);
 			*stack_ptr = obj_desc;
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "[Arg/Local %d] Value_obj is %p\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %d] Value_obj is %p\n",
 				stack_desc->reference.offset, obj_desc));
 			break;
 
@@ -290,6 +290,19 @@
 
 		break; /* case INTERNAL_TYPE_REFERENCE */
 
+
+	case ACPI_TYPE_BUFFER:
+
+		status = acpi_ds_get_buffer_arguments (stack_desc);
+		break;
+
+
+	case ACPI_TYPE_PACKAGE:
+
+		status = acpi_ds_get_package_arguments (stack_desc);
+		break;
+
+
 	/*
 	 * These cases may never happen here, but just in case..
 	 */
@@ -301,7 +314,7 @@
 		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Field_read Source_desc=%p Type=%X\n",
 			stack_desc, stack_desc->common.type));
 
-		status = acpi_ex_read_data_from_field (stack_desc, &obj_desc);
+		status = acpi_ex_read_data_from_field (walk_state, stack_desc, &obj_desc);
 		*stack_ptr = (void *) obj_desc;
 		break;
 
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exresop.c linux-2.5.8-pre3/drivers/acpi/executer/exresop.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exresop.c	Mon Mar 18 12:37:11 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exresop.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresop - AML Interpreter operand/object resolution
- *              $Revision: 47 $
+ *              $Revision: 48 $
  *
  *****************************************************************************/
 
@@ -69,7 +69,7 @@
 	}
 
 	if (type_needed != this_type) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 			"Needed [%s], found [%s] %p\n",
 			acpi_ut_get_type_name (type_needed),
 			acpi_ut_get_type_name (this_type), object));
@@ -135,8 +135,8 @@
 		return_ACPI_STATUS (AE_AML_INTERNAL);
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X Operand_types=%X \n",
-		opcode, arg_types));
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] Operand_types=%X \n",
+		opcode, op_info->name, arg_types));
 
 	/*
 	 * Normal exit is with (Arg_types == 0) at end of argument list.
@@ -203,7 +203,7 @@
 				case AML_LOCAL_OP:
 				case AML_REVISION_OP:
 
-					ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+					ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 						"Reference Opcode: %s\n", op_info->name)));
 					break;
 
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exstore.c linux-2.5.8-pre3/drivers/acpi/executer/exstore.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exstore.c	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exstore.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exstore - AML Interpreter object store support
- *              $Revision: 162 $
+ *              $Revision: 163 $
  *
  *****************************************************************************/
 
@@ -150,7 +150,7 @@
 		 * Storing to the Debug object causes the value stored to be
 		 * displayed and otherwise has no effect -- see ACPI Specification
 		 */
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Write to Debug Object: ****:\n\n"));
+		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "**** Write to Debug Object: ****:\n\n"));
 
 		ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ",
 				  acpi_ut_get_type_name (source_desc->common.type)));
@@ -191,7 +191,7 @@
 			break;
 		}
 
-		ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "\n"));
+		ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n"));
 		break;
 
 
@@ -404,7 +404,7 @@
 	target_type = acpi_ns_get_type (node);
 	target_desc = acpi_ns_get_attached_object (node);
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Storing %p(%s) into node %p(%s)\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
 		source_desc, acpi_ut_get_type_name (source_desc->common.type),
 			  node, acpi_ut_get_type_name (target_type)));
 
@@ -456,7 +456,7 @@
 			 */
 			status = acpi_ns_attach_object (node, new_desc, target_type);
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 				"Store %s into %s via Convert/Attach\n",
 				acpi_ut_get_type_name (source_desc->common.type),
 				acpi_ut_get_type_name (new_desc->common.type)));
@@ -466,7 +466,7 @@
 
 	default:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 			"Storing %s (%p) directly into node (%p), no implicit conversion\n",
 			acpi_ut_get_type_name (source_desc->common.type), source_desc, node));
 
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exstoren.c linux-2.5.8-pre3/drivers/acpi/executer/exstoren.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exstoren.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exstoren.c	Tue Apr  9 18:35:19 2002
@@ -3,7 +3,7 @@
  *
  * Module Name: exstoren - AML Interpreter object store support,
  *                        Store to Node (namespace object)
- *              $Revision: 46 $
+ *              $Revision: 47 $
  *
  *****************************************************************************/
 
@@ -145,7 +145,7 @@
  * FUNCTION:    Acpi_ex_store_object_to_object
  *
  * PARAMETERS:  Source_desc         - Object to store
- *              Dest_desc           - Object to recieve a copy of the source
+ *              Dest_desc           - Object to receive a copy of the source
  *              New_desc            - New object if Dest_desc is obsoleted
  *              Walk_state          - Current walk state
  *
diff -urN linux-2.5.8-pre2/drivers/acpi/executer/exstorob.c linux-2.5.8-pre3/drivers/acpi/executer/exstorob.c
--- linux-2.5.8-pre2/drivers/acpi/executer/exstorob.c	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/acpi/executer/exstorob.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exstorob - AML Interpreter object store support, store to object
- *              $Revision: 41 $
+ *              $Revision: 42 $
  *
  *****************************************************************************/
 
@@ -104,6 +104,10 @@
 			length, target_desc->buffer.length));
 	}
 
+	/* Copy flags */
+
+	target_desc->buffer.flags = source_desc->buffer.flags;
+
 	return (AE_OK);
 }
 
diff -urN linux-2.5.8-pre2/drivers/acpi/hardware/hwgpe.c linux-2.5.8-pre3/drivers/acpi/hardware/hwgpe.c
--- linux-2.5.8-pre2/drivers/acpi/hardware/hwgpe.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/acpi/hardware/hwgpe.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
- *              $Revision: 39 $
+ *              $Revision: 40 $
  *
  *****************************************************************************/
 
@@ -89,10 +89,10 @@
 	 * Read the current value of the register, set the appropriate bit
 	 * to enable the GPE, and write out the new register.
 	 */
-	in_byte = 0;
-	acpi_os_read_port (acpi_gbl_gpe_register_info[register_index].enable_addr, &in_byte, 8);
-	acpi_os_write_port (acpi_gbl_gpe_register_info[register_index].enable_addr,
-			  (in_byte | bit_mask), 8);
+	in_byte = acpi_hw_low_level_read (8,
+			 &acpi_gbl_gpe_register_info[register_index].enable_address, 0);
+	acpi_hw_low_level_write (8, (in_byte | bit_mask),
+			 &acpi_gbl_gpe_register_info[register_index].enable_address, 0);
 }
 
 
@@ -171,10 +171,10 @@
 	 * Read the current value of the register, clear the appropriate bit,
 	 * and write out the new register value to disable the GPE.
 	 */
-	in_byte = 0;
-	acpi_os_read_port (acpi_gbl_gpe_register_info[register_index].enable_addr, &in_byte, 8);
-	acpi_os_write_port (acpi_gbl_gpe_register_info[register_index].enable_addr,
-			 (in_byte & ~bit_mask), 8);
+	in_byte = acpi_hw_low_level_read (8,
+			 &acpi_gbl_gpe_register_info[register_index].enable_address, 0);
+	acpi_hw_low_level_write (8, (in_byte & ~bit_mask),
+			 &acpi_gbl_gpe_register_info[register_index].enable_address, 0);
 
 	acpi_hw_disable_gpe_for_wakeup(gpe_number);
 }
@@ -254,7 +254,8 @@
 	 * Write a one to the appropriate bit in the status register to
 	 * clear this GPE.
 	 */
-	acpi_os_write_port (acpi_gbl_gpe_register_info[register_index].status_addr, bit_mask, 8);
+	acpi_hw_low_level_write (8, bit_mask,
+			   &acpi_gbl_gpe_register_info[register_index].status_address, 0);
 }
 
 
@@ -301,8 +302,7 @@
 
 	/* GPE Enabled? */
 
-	in_byte = 0;
-	acpi_os_read_port (gpe_register_info->enable_addr, &in_byte, 8);
+	in_byte = acpi_hw_low_level_read (8, &gpe_register_info->enable_address, 0);
 	if (bit_mask & in_byte) {
 		(*event_status) |= ACPI_EVENT_FLAG_ENABLED;
 	}
@@ -315,8 +315,7 @@
 
 	/* GPE active (set)? */
 
-	in_byte = 0;
-	acpi_os_read_port (gpe_register_info->status_addr, &in_byte, 8);
+	in_byte = acpi_hw_low_level_read (8, &gpe_register_info->status_address, 0);
 	if (bit_mask & in_byte) {
 		(*event_status) |= ACPI_EVENT_FLAG_SET;
 	}
@@ -357,14 +356,14 @@
 		 * Read the enabled status of all GPEs. We
 		 * will be using it to restore all the GPEs later.
 		 */
-		acpi_os_read_port (gpe_register_info->enable_addr,
-				  &gpe_register_info->enable, 8);
+		gpe_register_info->enable = (u8) acpi_hw_low_level_read (8,
+				 &gpe_register_info->enable_address, 0);
 
 		/*
 		 * Disable all GPEs except wakeup GPEs.
 		 */
-		acpi_os_write_port(gpe_register_info->enable_addr,
-				  gpe_register_info->wake_enable, 8);
+		acpi_hw_low_level_write (8, gpe_register_info->wake_enable,
+				&gpe_register_info->enable_address, 0);
 	}
 }
 
@@ -399,7 +398,7 @@
 		 * We previously stored the enabled status of all GPEs.
 		 * Blast them back in.
 		 */
-		acpi_os_write_port(gpe_register_info->enable_addr,
-				  gpe_register_info->enable, 8);
+		acpi_hw_low_level_write (8, gpe_register_info->enable, &
+				gpe_register_info->enable_address, 0);
 	}
 }
diff -urN linux-2.5.8-pre2/drivers/acpi/hardware/hwregs.c linux-2.5.8-pre3/drivers/acpi/hardware/hwregs.c
--- linux-2.5.8-pre2/drivers/acpi/hardware/hwregs.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/drivers/acpi/hardware/hwregs.c	Tue Apr  9 18:35:19 2002
@@ -3,7 +3,7 @@
  *
  * Module Name: hwregs - Read/write access functions for the various ACPI
  *                       control and status registers.
- *              $Revision: 120 $
+ *              $Revision: 121 $
  *
  ******************************************************************************/
 
@@ -73,18 +73,16 @@
 	/* Clear the fixed events */
 
 	if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address)) {
-		acpi_os_write_port ((ACPI_IO_ADDRESS)
-			ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm1b_evt_blk.address),
-			ACPI_BITMASK_ALL_FIXED_STATUS, 16);
+		acpi_hw_low_level_write (16, ACPI_BITMASK_ALL_FIXED_STATUS,
+				&acpi_gbl_FADT->Xpm1b_evt_blk, 0);
 	}
 
 	/* Clear the GPE Bits */
 
 	for (gpe_block = 0; gpe_block < ACPI_MAX_GPE_BLOCKS; gpe_block++) {
 		for (i = 0; i < acpi_gbl_gpe_block_info[gpe_block].register_count; i++) {
-			acpi_os_write_port ((ACPI_IO_ADDRESS)
-				(acpi_gbl_gpe_block_info[gpe_block].block_address + i),
-				0xFF, 8);
+			acpi_hw_low_level_write (8, 0xFF,
+				acpi_gbl_gpe_block_info[gpe_block].block_address, i);
 		}
 	}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/hardware/hwsleep.c linux-2.5.8-pre3/drivers/acpi/hardware/hwsleep.c
--- linux-2.5.8-pre2/drivers/acpi/hardware/hwsleep.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/acpi/hardware/hwsleep.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
- *              $Revision: 35 $
+ *              $Revision: 37 $
  *
  *****************************************************************************/
 
@@ -237,6 +237,7 @@
 	PM1Bcontrol |= sleep_enable_reg_info->access_bit_mask;
 
 	/* Write #2: SLP_TYP + SLP_EN */
+	ACPI_FLUSH_CPU_CACHE();
 
 	acpi_hw_register_write (ACPI_MTX_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
 	acpi_hw_register_write (ACPI_MTX_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
diff -urN linux-2.5.8-pre2/drivers/acpi/hardware/hwtimer.c linux-2.5.8-pre3/drivers/acpi/hardware/hwtimer.c
--- linux-2.5.8-pre2/drivers/acpi/hardware/hwtimer.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/acpi/hardware/hwtimer.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Name: hwtimer.c - ACPI Power Management Timer Interface
- *              $Revision: 19 $
+ *              $Revision: 20 $
  *
  *****************************************************************************/
 
@@ -88,8 +88,7 @@
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
-	acpi_os_read_port ((ACPI_IO_ADDRESS)
-		ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address), ticks, 32);
+	*ticks = acpi_hw_low_level_read (32, &acpi_gbl_FADT->Xpm_tmr_blk, 0);
 
 	return_ACPI_STATUS (AE_OK);
 }
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acconfig.h linux-2.5.8-pre3/drivers/acpi/include/acconfig.h
--- linux-2.5.8-pre2/drivers/acpi/include/acconfig.h	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acconfig.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acconfig.h - Global configuration constants
- *       $Revision: 94 $
+ *       $Revision: 96 $
  *
  *****************************************************************************/
 
@@ -54,7 +54,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION             0x20020308
+#define ACPI_CA_VERSION             0x20020403
 
 /* Version of ACPI supported */
 
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acdebug.h linux-2.5.8-pre3/drivers/acpi/include/acdebug.h
--- linux-2.5.8-pre2/drivers/acpi/include/acdebug.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acdebug.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acdebug.h - ACPI/AML debugger
- *       $Revision: 57 $
+ *       $Revision: 58 $
  *
  *****************************************************************************/
 
@@ -271,6 +271,9 @@
 acpi_db_load_acpi_table (
 	NATIVE_CHAR             *filename);
 
+acpi_status
+acpi_db_get_acpi_table (
+	NATIVE_CHAR             *filename);
 
 /*
  * dbhistry - debugger HISTORY command
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acdispat.h linux-2.5.8-pre3/drivers/acpi/include/acdispat.h
--- linux-2.5.8-pre2/drivers/acpi/include/acdispat.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acdispat.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acdispat.h - dispatcher (parser to interpreter interface)
- *       $Revision: 51 $
+ *       $Revision: 52 $
  *
  *****************************************************************************/
 
@@ -65,6 +65,14 @@
 acpi_ds_get_region_arguments (
 	acpi_operand_object     *rgn_desc);
 
+acpi_status
+acpi_ds_get_buffer_arguments (
+	acpi_operand_object     *obj_desc);
+
+acpi_status
+acpi_ds_get_package_arguments (
+	acpi_operand_object     *obj_desc);
+
 
 /* dsctrl - Parser/Interpreter interface, control stack routines */
 
@@ -267,9 +275,17 @@
 	acpi_namespace_node     *start_node);
 
 acpi_status
+acpi_ds_build_internal_buffer_obj (
+	acpi_walk_state         *walk_state,
+	acpi_parse_object       *op,
+	u32                     buffer_length,
+	acpi_operand_object     **obj_desc_ptr);
+
+acpi_status
 acpi_ds_build_internal_package_obj (
 	acpi_walk_state         *walk_state,
 	acpi_parse_object       *op,
+	u32                     package_length,
 	acpi_operand_object     **obj_desc);
 
 acpi_status
@@ -305,6 +321,12 @@
 	acpi_parse_object       *op);
 
 acpi_status
+acpi_ds_eval_data_object_operands (
+	acpi_walk_state         *walk_state,
+	acpi_parse_object       *op,
+	acpi_operand_object     *obj_desc);
+
+acpi_status
 acpi_ds_initialize_region (
 	acpi_handle             obj_handle);
 
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acevents.h linux-2.5.8-pre3/drivers/acpi/include/acevents.h
--- linux-2.5.8-pre2/drivers/acpi/include/acevents.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acevents.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acevents.h - Event subcomponent prototypes and defines
- *       $Revision: 75 $
+ *       $Revision: 76 $
  *
  *****************************************************************************/
 
@@ -57,6 +57,10 @@
  * Evmisc
  */
 
+u8
+acpi_ev_is_notify_object (
+	acpi_namespace_node     *node);
+
 acpi_status
 acpi_ev_acquire_global_lock(
 	u32                     timeout);
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acexcep.h linux-2.5.8-pre3/drivers/acpi/include/acexcep.h
--- linux-2.5.8-pre2/drivers/acpi/include/acexcep.h	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acexcep.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acexcep.h - Exception codes returned by the ACPI subsystem
- *       $Revision: 57 $
+ *       $Revision: 59 $
  *
  *****************************************************************************/
 
@@ -74,8 +74,9 @@
 #define AE_ALREADY_ACQUIRED             (acpi_status) (0x0018 | AE_CODE_ENVIRONMENTAL)
 #define AE_NO_HARDWARE_RESPONSE         (acpi_status) (0x0019 | AE_CODE_ENVIRONMENTAL)
 #define AE_NO_GLOBAL_LOCK               (acpi_status) (0x001A | AE_CODE_ENVIRONMENTAL)
+#define AE_LOGICAL_ADDRESS              (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL)
 
-#define AE_CODE_ENV_MAX                 0x001A
+#define AE_CODE_ENV_MAX                 0x001B
 
 /*
  * Programmer exceptions
@@ -86,8 +87,11 @@
 #define AE_BAD_DATA                     (acpi_status) (0x0004 | AE_CODE_PROGRAMMER)
 #define AE_BAD_ADDRESS                  (acpi_status) (0x0005 | AE_CODE_PROGRAMMER)
 #define AE_ALIGNMENT                    (acpi_status) (0x0006 | AE_CODE_PROGRAMMER)
+#define AE_BAD_HEX_CONSTANT             (acpi_status) (0x0007 | AE_CODE_PROGRAMMER)
+#define AE_BAD_OCTAL_CONSTANT           (acpi_status) (0x0008 | AE_CODE_PROGRAMMER)
+#define AE_BAD_DECIMAL_CONSTANT         (acpi_status) (0x0009 | AE_CODE_PROGRAMMER)
 
-#define AE_CODE_PGM_MAX                 0x0006
+#define AE_CODE_PGM_MAX                 0x0009
 
 
 /*
@@ -188,7 +192,8 @@
 	"AE_NOT_ACQUIRED",
 	"AE_ALREADY_ACQUIRED",
 	"AE_NO_HARDWARE_RESPONSE",
-	"AE_NO_GLOBAL_LOCK"
+	"AE_NO_GLOBAL_LOCK",
+	"AE_LOGICAL_ADDRESS"
 };
 
 NATIVE_CHAR const   *acpi_gbl_exception_names_pgm[] =
@@ -198,7 +203,10 @@
 	"AE_BAD_PATHNAME",
 	"AE_BAD_DATA",
 	"AE_BAD_ADDRESS",
-	"AE_ALIGNMENT"
+	"AE_ALIGNMENT",
+	"AE_BAD_HEX_CONSTANT",
+	"AE_BAD_OCTAL_CONSTANT",
+	"AE_BAD_DECIMAL_CONSTANT"
 };
 
 NATIVE_CHAR const   *acpi_gbl_exception_names_tbl[] =
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acglobal.h linux-2.5.8-pre3/drivers/acpi/include/acglobal.h
--- linux-2.5.8-pre2/drivers/acpi/include/acglobal.h	Mon Mar 18 12:37:01 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acglobal.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acglobal.h - Declarations for global variables
- *       $Revision: 120 $
+ *       $Revision: 121 $
  *
  *****************************************************************************/
 
@@ -71,6 +71,7 @@
  * of each in the system.  Each global points to the actual table.
  *
  */
+ACPI_EXTERN u32                         acpi_gbl_table_flags;
 ACPI_EXTERN RSDP_DESCRIPTOR            *acpi_gbl_RSDP;
 ACPI_EXTERN xsdt_descriptor            *acpi_gbl_XSDT;
 ACPI_EXTERN FADT_DESCRIPTOR            *acpi_gbl_FADT;
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acinterp.h linux-2.5.8-pre3/drivers/acpi/include/acinterp.h
--- linux-2.5.8-pre2/drivers/acpi/include/acinterp.h	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acinterp.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acinterp.h - Interpreter subcomponent prototypes and defines
- *       $Revision: 132 $
+ *       $Revision: 133 $
  *
  *****************************************************************************/
 
@@ -147,6 +147,7 @@
 
 acpi_status
 acpi_ex_read_data_from_field (
+	acpi_walk_state         *walk_state,
 	acpi_operand_object     *obj_desc,
 	acpi_operand_object     **ret_buffer_desc);
 
diff -urN linux-2.5.8-pre2/drivers/acpi/include/aclocal.h linux-2.5.8-pre3/drivers/acpi/include/aclocal.h
--- linux-2.5.8-pre2/drivers/acpi/include/aclocal.h	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/aclocal.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: aclocal.h - Internal data types used across the ACPI subsystem
- *       $Revision: 159 $
+ *       $Revision: 162 $
  *
  *****************************************************************************/
 
@@ -182,12 +182,18 @@
  * be the first byte in this structure.
  */
 
+typedef union acpi_name_union
+{
+	u32                     integer;
+	char                    ascii[4];
+} ACPI_NAME_UNION;
+
 typedef struct acpi_node
 {
 	u8                      descriptor;     /* Used to differentiate object descriptor types */
 	u8                      type;           /* Type associated with this name */
 	u16                     owner_id;
-	u32                     name;           /* ACPI Name, always 4 chars per ACPI spec */
+	ACPI_NAME_UNION         name;           /* ACPI Name, always 4 chars per ACPI spec */
 
 
 	union acpi_operand_obj  *object;        /* Pointer to attached ACPI object (optional) */
@@ -314,8 +320,9 @@
 
 typedef struct
 {
+	u8                      address_space_id;
+	acpi_generic_address    *block_address;
 	u16                     register_count;
-	u16                     block_address;
 	u8                      block_base_number;
 
 } ACPI_GPE_BLOCK_INFO;
@@ -324,8 +331,8 @@
 
 typedef struct
 {
-	u16                     status_addr;    /* Address of status reg */
-	u16                     enable_addr;    /* Address of enable reg */
+	acpi_generic_address    status_address; /* Address of status reg */
+	acpi_generic_address    enable_address; /* Address of enable reg */
 	u8                      status;         /* Current value of status reg */
 	u8                      enable;         /* Current value of enable reg */
 	u8                      wake_enable;    /* Mask of bits to keep enabled when sleeping */
@@ -410,11 +417,11 @@
 
 #define ACPI_STATE_COMMON                  /* Two 32-bit fields and a pointer */\
 	u8                      data_type;          /* To differentiate various internal objs */\
-	u8                      flags; \
-	u16                     value; \
-	u16                     state; \
-	u16                     acpi_eval; \
-	void                    *next; \
+	u8                      flags;      \
+	u16                     value;      \
+	u16                     state;      \
+	u16                     reserved;   \
+	void                    *next;      \
 
 typedef struct acpi_common_state
 {
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acobject.h linux-2.5.8-pre3/drivers/acpi/include/acobject.h
--- linux-2.5.8-pre2/drivers/acpi/include/acobject.h	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acobject.h	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Name: acobject.h - Definition of acpi_operand_object  (Internal object only)
- *       $Revision: 106 $
+ *       $Revision: 110 $
  *
  *****************************************************************************/
 
@@ -32,23 +32,14 @@
  * The acpi_operand_object  is used to pass AML operands from the dispatcher
  * to the interpreter, and to keep track of the various handlers such as
  * address space handlers and notify handlers.  The object is a constant
- * size in order to allow them to be cached and reused.
- *
- * All variants of the acpi_operand_object  are defined with the same
- * sequence of field types, with fields that are not used in a particular
- * variant being named "Reserved".  This is not strictly necessary, but
- * may in some circumstances simplify understanding if these structures
- * need to be displayed in a debugger having limited (or no) support for
- * union types.  It also simplifies some debug code in Dump_table() which
- * dumps multi-level values: fetching Buffer.Pointer suffices to pick up
- * the value or next level for any of several types.
+ * size in order to allow it to be cached and reused.
  */
 
-/******************************************************************************
+/*******************************************************************************
  *
  * Common Descriptors
  *
- *****************************************************************************/
+ ******************************************************************************/
 
 /*
  * Common area for all objects.
@@ -56,8 +47,6 @@
  * Data_type is used to differentiate between internal descriptors, and MUST
  * be the first byte in this structure.
  */
-
-
 #define ACPI_OBJECT_COMMON_HEADER           /* SIZE/ALIGNMENT: 32 bits, one ptr plus trailing 8-bit flag */\
 	u8                          descriptor;         /* To differentiate various internal objs */\
 	u8                          type;               /* acpi_object_type */\
@@ -65,7 +54,7 @@
 	union acpi_operand_obj      *next_object;       /* Objects linked to parent NS node */\
 	u8                          flags; \
 
-/* Defines for flag byte above */
+/* Values for flag byte above */
 
 #define AOPOBJ_RESERVED             0x01
 #define AOPOBJ_STATIC_POINTER       0x02
@@ -101,29 +90,29 @@
 	u32                         length;
 
 
+/*
+ * Common fields for objects that support ASL notifications
+ */
+#define ACPI_COMMON_NOTIFY_INFO \
+	union acpi_operand_obj      *sys_handler;        /* Handler for system notifies */\
+	union acpi_operand_obj      *drv_handler;        /* Handler for driver notifies */\
+	union acpi_operand_obj      *addr_handler;       /* Handler for Address space */
+
+
 /******************************************************************************
  *
- * Individual Object Descriptors
+ * Basic data types
  *
  *****************************************************************************/
 
-
-typedef struct /* COMMON */
+typedef struct acpi_object_common
 {
 	ACPI_OBJECT_COMMON_HEADER
 
 } ACPI_OBJECT_COMMON;
 
 
-typedef struct /* CACHE_LIST */
-{
-	ACPI_OBJECT_COMMON_HEADER
-	union acpi_operand_obj      *next;              /* Link for object cache and internal lists*/
-
-} ACPI_OBJECT_CACHE_LIST;
-
-
-typedef struct /* NUMBER - has value */
+typedef struct acpi_object_integer
 {
 	ACPI_OBJECT_COMMON_HEADER
 
@@ -132,48 +121,47 @@
 } ACPI_OBJECT_INTEGER;
 
 
-typedef struct /* STRING - has length and pointer - Null terminated, ASCII characters only */
+typedef struct acpi_object_string                   /* Null terminated, ASCII characters only */
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_COMMON_BUFFER_INFO
-	NATIVE_CHAR                 *pointer;           /* String value in AML stream or in allocated space */
+	NATIVE_CHAR                 *pointer;           /* String in AML stream or allocated string */
 
 } ACPI_OBJECT_STRING;
 
 
-typedef struct /* BUFFER - has length and pointer - not null terminated */
+typedef struct acpi_object_buffer
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_COMMON_BUFFER_INFO
-	u8                          *pointer;           /* Buffer value in AML stream or in allocated space */
+	u8                          *pointer;           /* Buffer in AML stream or allocated buffer */
 	acpi_namespace_node         *node;              /* Link back to parent node */
+	u8                          *aml_start;
+	u32                         aml_length;
 
 } ACPI_OBJECT_BUFFER;
 
 
-typedef struct /* PACKAGE - has count, elements, next element */
+typedef struct acpi_object_package
 {
 	ACPI_OBJECT_COMMON_HEADER
 
 	u32                         count;              /* # of elements in package */
+	u32                         aml_length;
+	u8                          *aml_start;
+	acpi_namespace_node         *node;              /* Link back to parent node */
 	union acpi_operand_obj      **elements;         /* Array of pointers to Acpi_objects */
-	union acpi_operand_obj      **next_element;     /* used only while initializing */
 
 } ACPI_OBJECT_PACKAGE;
 
 
-typedef struct /* DEVICE - has handle and notification handler/context */
-{
-	ACPI_OBJECT_COMMON_HEADER
-
-	union acpi_operand_obj      *sys_handler;        /* Handler for system notifies */
-	union acpi_operand_obj      *drv_handler;        /* Handler for driver notifies */
-	union acpi_operand_obj      *addr_handler;       /* Handler for Address space */
-
-} ACPI_OBJECT_DEVICE;
-
+/******************************************************************************
+ *
+ * Complex data types
+ *
+ *****************************************************************************/
 
-typedef struct /* EVENT */
+typedef struct acpi_object_event
 {
 	ACPI_OBJECT_COMMON_HEADER
 	void                        *semaphore;
@@ -183,7 +171,7 @@
 
 #define INFINITE_CONCURRENCY        0xFF
 
-typedef struct /* METHOD */
+typedef struct acpi_object_method
 {
 	ACPI_OBJECT_COMMON_HEADER
 	u8                          method_flags;
@@ -201,7 +189,7 @@
 } ACPI_OBJECT_METHOD;
 
 
-typedef struct acpi_obj_mutex /* MUTEX */
+typedef struct acpi_object_mutex
 {
 	ACPI_OBJECT_COMMON_HEADER
 	u16                         sync_level;
@@ -215,65 +203,82 @@
 } ACPI_OBJECT_MUTEX;
 
 
-typedef struct /* REGION */
+typedef struct acpi_object_region
 {
 	ACPI_OBJECT_COMMON_HEADER
 
 	u8                          space_id;
-	u32                         length;
-	ACPI_PHYSICAL_ADDRESS       address;
 
 	union acpi_operand_obj      *addr_handler;      /* Handler for system notifies */
 	acpi_namespace_node         *node;              /* containing object */
 	union acpi_operand_obj      *next;
+	u32                         length;
+	ACPI_PHYSICAL_ADDRESS       address;
 
 } ACPI_OBJECT_REGION;
 
 
-typedef struct /* POWER RESOURCE - has Handle and notification handler/context*/
+/******************************************************************************
+ *
+ * Objects that can be notified.  All share a common Notify_info area.
+ *
+ *****************************************************************************/
+
+typedef struct acpi_object_notify_common            /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
+{
+	ACPI_OBJECT_COMMON_HEADER
+	ACPI_COMMON_NOTIFY_INFO
+
+} ACPI_OBJECT_NOTIFY_COMMON;
+
+
+typedef struct acpi_object_device
+{
+	ACPI_OBJECT_COMMON_HEADER
+	ACPI_COMMON_NOTIFY_INFO
+
+} ACPI_OBJECT_DEVICE;
+
+
+typedef struct acpi_object_power_resource
 {
 	ACPI_OBJECT_COMMON_HEADER
+	ACPI_COMMON_NOTIFY_INFO
 
 	u32                         system_level;
 	u32                         resource_order;
 
-	union acpi_operand_obj      *sys_handler;       /* Handler for system notifies */
-	union acpi_operand_obj      *drv_handler;       /* Handler for driver notifies */
-
 } ACPI_OBJECT_POWER_RESOURCE;
 
 
-typedef struct /* PROCESSOR - has Handle and notification handler/context*/
+typedef struct acpi_object_processor
 {
 	ACPI_OBJECT_COMMON_HEADER
+	ACPI_COMMON_NOTIFY_INFO
 
 	u32                         proc_id;
 	u32                         length;
 	ACPI_IO_ADDRESS             address;
 
-	union acpi_operand_obj      *sys_handler;       /* Handler for system notifies */
-	union acpi_operand_obj      *drv_handler;       /* Handler for driver notifies */
-	union acpi_operand_obj      *addr_handler;      /* Handler for Address space */
-
 } ACPI_OBJECT_PROCESSOR;
 
 
-typedef struct /* THERMAL ZONE - has Handle and Handler/Context */
+typedef struct acpi_object_thermal_zone
 {
 	ACPI_OBJECT_COMMON_HEADER
+	ACPI_COMMON_NOTIFY_INFO
 
-	union acpi_operand_obj      *sys_handler;       /* Handler for system notifies */
-	union acpi_operand_obj      *drv_handler;       /* Handler for driver notifies */
-	union acpi_operand_obj      *addr_handler;      /* Handler for Address space */
 
 } ACPI_OBJECT_THERMAL_ZONE;
 
 
-/*
+/******************************************************************************
+ *
  * Fields.  All share a common header/info field.
- */
+ *
+ *****************************************************************************/
 
-typedef struct /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
+typedef struct acpi_object_field_common             /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_COMMON_FIELD_INFO
@@ -282,7 +287,7 @@
 } ACPI_OBJECT_FIELD_COMMON;
 
 
-typedef struct /* REGION FIELD */
+typedef struct acpi_object_region_field
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_COMMON_FIELD_INFO
@@ -291,7 +296,7 @@
 } ACPI_OBJECT_REGION_FIELD;
 
 
-typedef struct /* BANK FIELD */
+typedef struct acpi_object_bank_field
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_COMMON_FIELD_INFO
@@ -302,7 +307,7 @@
 } ACPI_OBJECT_BANK_FIELD;
 
 
-typedef struct /* INDEX FIELD */
+typedef struct acpi_object_index_field
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_COMMON_FIELD_INFO
@@ -320,7 +325,7 @@
 
 /* The Buffer_field is different in that it is part of a Buffer, not an Op_region */
 
-typedef struct /* BUFFER FIELD */
+typedef struct acpi_object_buffer_field
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_COMMON_FIELD_INFO
@@ -330,11 +335,13 @@
 } ACPI_OBJECT_BUFFER_FIELD;
 
 
-/*
- * Handlers
- */
+/******************************************************************************
+ *
+ * Objects for handlers
+ *
+ *****************************************************************************/
 
-typedef struct /* NOTIFY HANDLER */
+typedef struct acpi_object_notify_handler
 {
 	ACPI_OBJECT_COMMON_HEADER
 
@@ -350,7 +357,7 @@
 #define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED  0x1
 
 
-typedef struct /* ADDRESS HANDLER */
+typedef struct acpi_object_addr_handler
 {
 	ACPI_OBJECT_COMMON_HEADER
 
@@ -367,12 +374,17 @@
 } ACPI_OBJECT_ADDR_HANDLER;
 
 
+/******************************************************************************
+ *
+ * Special internal objects
+ *
+ *****************************************************************************/
+
 /*
  * The Reference object type is used for these opcodes:
  * Arg[0-6], Local[0-7], Index_op, Name_op, Zero_op, One_op, Ones_op, Debug_op
  */
-
-typedef struct /* Reference - Local object type */
+typedef struct acpi_object_reference
 {
 	ACPI_OBJECT_COMMON_HEADER
 
@@ -394,8 +406,7 @@
  *
  * Currently: Region and Field_unit types
  */
-
-typedef struct /* EXTRA */
+typedef struct acpi_object_extra
 {
 	ACPI_OBJECT_COMMON_HEADER
 	u8                          byte_fill1;
@@ -408,7 +419,9 @@
 } ACPI_OBJECT_EXTRA;
 
 
-typedef struct /* DATA */
+/* Additional data that can be attached to namespace nodes */
+
+typedef struct acpi_object_data
 {
 	ACPI_OBJECT_COMMON_HEADER
 	ACPI_OBJECT_HANDLER         handler;
@@ -417,38 +430,55 @@
 } ACPI_OBJECT_DATA;
 
 
+/* Structure used when objects are cached for reuse */
+
+typedef struct acpi_object_cache_list
+{
+	ACPI_OBJECT_COMMON_HEADER
+	union acpi_operand_obj      *next;              /* Link for object cache and internal lists*/
+
+} ACPI_OBJECT_CACHE_LIST;
+
+
 /******************************************************************************
  *
- * acpi_operand_object  Descriptor - a giant union of all of the above
+ * acpi_operand_object Descriptor - a giant union of all of the above
  *
  *****************************************************************************/
 
 typedef union acpi_operand_obj
 {
 	ACPI_OBJECT_COMMON          common;
-	ACPI_OBJECT_CACHE_LIST      cache;
+
 	ACPI_OBJECT_INTEGER         integer;
 	ACPI_OBJECT_STRING          string;
 	ACPI_OBJECT_BUFFER          buffer;
 	ACPI_OBJECT_PACKAGE         package;
-	ACPI_OBJECT_BUFFER_FIELD    buffer_field;
-	ACPI_OBJECT_DEVICE          device;
+
 	ACPI_OBJECT_EVENT           event;
 	ACPI_OBJECT_METHOD          method;
 	ACPI_OBJECT_MUTEX           mutex;
 	ACPI_OBJECT_REGION          region;
+
+	ACPI_OBJECT_NOTIFY_COMMON   common_notify;
+	ACPI_OBJECT_DEVICE          device;
 	ACPI_OBJECT_POWER_RESOURCE  power_resource;
 	ACPI_OBJECT_PROCESSOR       processor;
 	ACPI_OBJECT_THERMAL_ZONE    thermal_zone;
+
 	ACPI_OBJECT_FIELD_COMMON    common_field;
 	ACPI_OBJECT_REGION_FIELD    field;
+	ACPI_OBJECT_BUFFER_FIELD    buffer_field;
 	ACPI_OBJECT_BANK_FIELD      bank_field;
 	ACPI_OBJECT_INDEX_FIELD     index_field;
-	ACPI_OBJECT_REFERENCE       reference;
+
 	ACPI_OBJECT_NOTIFY_HANDLER  notify_handler;
 	ACPI_OBJECT_ADDR_HANDLER    addr_handler;
+
+	ACPI_OBJECT_REFERENCE       reference;
 	ACPI_OBJECT_EXTRA           extra;
 	ACPI_OBJECT_DATA            data;
+	ACPI_OBJECT_CACHE_LIST      cache;
 
 } acpi_operand_object;
 
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acpiosxf.h linux-2.5.8-pre3/drivers/acpi/include/acpiosxf.h
--- linux-2.5.8-pre2/drivers/acpi/include/acpiosxf.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acpiosxf.h	Tue Apr  9 18:35:19 2002
@@ -83,10 +83,20 @@
 acpi_os_terminate (
 	void);
 
+
+/*
+ * ACPI Table interfaces
+ */
+
 acpi_status
 acpi_os_get_root_pointer (
 	u32                     flags,
-	ACPI_PHYSICAL_ADDRESS   *rsdp_physical_address);
+	ACPI_POINTER            *address);
+
+acpi_status
+acpi_os_table_override (
+	acpi_table_header       *existing_table,
+	acpi_table_header       **new_table);
 
 
 /*
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acpixf.h linux-2.5.8-pre3/drivers/acpi/include/acpixf.h
--- linux-2.5.8-pre2/drivers/acpi/include/acpixf.h	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acpixf.h	Tue Apr  9 18:35:19 2002
@@ -96,7 +96,7 @@
 acpi_status
 acpi_find_root_pointer (
 	u32                     flags,
-	ACPI_PHYSICAL_ADDRESS   *rsdp_physical_address);
+	ACPI_POINTER            *rsdp_address);
 
 acpi_status
 acpi_load_tables (
diff -urN linux-2.5.8-pre2/drivers/acpi/include/acstruct.h linux-2.5.8-pre3/drivers/acpi/include/acstruct.h
--- linux-2.5.8-pre2/drivers/acpi/include/acstruct.h	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/acstruct.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acstruct.h - Internal structs
- *       $Revision: 16 $
+ *       $Revision: 17 $
  *
  *****************************************************************************/
 
@@ -104,8 +104,12 @@
 	u16                     method_count;
 	u16                     op_region_count;
 	u16                     field_count;
+	u16                     buffer_count;
+	u16                     package_count;
 	u16                     op_region_init;
 	u16                     field_init;
+	u16                     buffer_init;
+	u16                     package_init;
 	u16                     object_count;
 	acpi_table_desc         *table_desc;
 
diff -urN linux-2.5.8-pre2/drivers/acpi/include/actables.h linux-2.5.8-pre3/drivers/acpi/include/actables.h
--- linux-2.5.8-pre2/drivers/acpi/include/actables.h	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/actables.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: actables.h - ACPI table management
- *       $Revision: 35 $
+ *       $Revision: 36 $
  *
  *****************************************************************************/
 
@@ -71,22 +71,16 @@
 
 acpi_status
 acpi_tb_get_table (
-	ACPI_PHYSICAL_ADDRESS   physical_address,
-	acpi_table_header       *buffer_ptr,
+	ACPI_POINTER            *address,
 	acpi_table_desc         *table_info);
 
 acpi_status
 acpi_tb_verify_rsdp (
-	ACPI_PHYSICAL_ADDRESS   RSDP_physical_address);
+	ACPI_POINTER            *address);
 
-acpi_status
-acpi_tb_get_table_facs (
-	acpi_table_header       *buffer_ptr,
-	acpi_table_desc         *table_info);
-
-ACPI_PHYSICAL_ADDRESS
+void
 acpi_tb_get_rsdt_address (
-	void);
+	ACPI_POINTER            *out_address);
 
 acpi_status
 acpi_tb_validate_rsdt (
@@ -94,7 +88,7 @@
 
 acpi_status
 acpi_tb_get_table_pointer (
-	ACPI_PHYSICAL_ADDRESS   physical_address,
+	ACPI_POINTER            *address,
 	u32                     flags,
 	u32                     *size,
 	acpi_table_header       **table_ptr);
diff -urN linux-2.5.8-pre2/drivers/acpi/include/actypes.h linux-2.5.8-pre3/drivers/acpi/include/actypes.h
--- linux-2.5.8-pre2/drivers/acpi/include/actypes.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/actypes.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: actypes.h - Common data types for the entire ACPI subsystem
- *       $Revision: 224 $
+ *       $Revision: 227 $
  *
  *****************************************************************************/
 
@@ -57,12 +57,13 @@
 typedef unsigned short                  UINT16;
 typedef int                             INT32;
 typedef unsigned int                    UINT32;
+typedef COMPILER_DEPENDENT_INT64        INT64;
 typedef COMPILER_DEPENDENT_UINT64       UINT64;
 
 typedef UINT64                          NATIVE_UINT;
 typedef UINT64                          NATIVE_INT;
 
-typedef NATIVE_UINT                     ACPI_TBLPTR;
+typedef UINT64                          ACPI_TBLPTR;
 typedef UINT64                          ACPI_IO_ADDRESS;
 typedef UINT64                          ACPI_PHYSICAL_ADDRESS;
 typedef UINT64                          ACPI_SIZE;
@@ -119,12 +120,13 @@
 typedef unsigned short                  UINT16;
 typedef int                             INT32;
 typedef unsigned int                    UINT32;
+typedef COMPILER_DEPENDENT_INT64        INT64;
 typedef COMPILER_DEPENDENT_UINT64       UINT64;
 
 typedef UINT32                          NATIVE_UINT;
 typedef INT32                           NATIVE_INT;
 
-typedef NATIVE_UINT                     ACPI_TBLPTR;
+typedef UINT64                          ACPI_TBLPTR;
 typedef UINT32                          ACPI_IO_ADDRESS;
 typedef UINT64                          ACPI_PHYSICAL_ADDRESS;
 typedef UINT32                          ACPI_SIZE;
@@ -148,7 +150,6 @@
 /*
  * Data type ranges
  */
-
 #define ACPI_UINT8_MAX                  (UINT8)  0xFF
 #define ACPI_UINT16_MAX                 (UINT16) 0xFFFF
 #define ACPI_UINT32_MAX                 (UINT32) 0xFFFFFFFF
@@ -171,6 +172,31 @@
 
 
 /*
+ * Pointer overlays to avoid lots of typecasting for
+ * code that accepts both physical and logical pointers.
+ */
+typedef union acpi_pointers
+{
+	ACPI_PHYSICAL_ADDRESS       physical;
+	void                        *logical;
+	ACPI_TBLPTR                 value;
+
+} ACPI_POINTERS;
+
+typedef struct acpi_pointer
+{
+	u32                         pointer_type;
+	ACPI_POINTERS               pointer;
+
+} ACPI_POINTER;
+
+/* Pointer_types for above */
+
+#define ACPI_LOGICAL_POINTER            0x01
+#define ACPI_PHYSICAL_POINTER           0x02
+
+
+/*
  * Useful defines
  */
 
diff -urN linux-2.5.8-pre2/drivers/acpi/include/amlcode.h linux-2.5.8-pre3/drivers/acpi/include/amlcode.h
--- linux-2.5.8-pre2/drivers/acpi/include/amlcode.h	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/amlcode.h	Tue Apr  9 18:35:19 2002
@@ -3,7 +3,7 @@
  * Name: amlcode.h - Definitions for AML, as included in "definition blocks"
  *                   Declarations and definitions contained herein are derived
  *                   directly from the ACPI specification.
- *       $Revision: 66 $
+ *       $Revision: 67 $
  *
  *****************************************************************************/
 
@@ -185,6 +185,7 @@
 #define AML_INT_STATICSTRING_OP     (u16) 0x0034
 #define AML_INT_METHODCALL_OP       (u16) 0x0035
 #define AML_INT_RETURN_VALUE_OP     (u16) 0x0036
+#define AML_INT_EVAL_SUBTREE_OP     (u16) 0x0037
 
 
 #define ARG_NONE                    0x0
@@ -335,15 +336,16 @@
 /* Misc */
 
 #define AML_TYPE_CREATE_FIELD       0x11
-#define AML_TYPE_CONTROL            0x12
-#define AML_TYPE_NAMED_NO_OBJ       0x13
-#define AML_TYPE_NAMED_FIELD        0x14
-#define AML_TYPE_NAMED_SIMPLE       0x15
-#define AML_TYPE_NAMED_COMPLEX      0x16
-#define AML_TYPE_RETURN             0x17
+#define AML_TYPE_CREATE_OBJECT      0x12
+#define AML_TYPE_CONTROL            0x13
+#define AML_TYPE_NAMED_NO_OBJ       0x14
+#define AML_TYPE_NAMED_FIELD        0x15
+#define AML_TYPE_NAMED_SIMPLE       0x16
+#define AML_TYPE_NAMED_COMPLEX      0x17
+#define AML_TYPE_RETURN             0x18
 
-#define AML_TYPE_UNDEFINED          0x18
-#define AML_TYPE_BOGUS              0x19
+#define AML_TYPE_UNDEFINED          0x19
+#define AML_TYPE_BOGUS              0x1A
 
 
 /*
diff -urN linux-2.5.8-pre2/drivers/acpi/include/platform/acenv.h linux-2.5.8-pre3/drivers/acpi/include/platform/acenv.h
--- linux-2.5.8-pre2/drivers/acpi/include/platform/acenv.h	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/platform/acenv.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acenv.h - Generation environment specific items
- *       $Revision: 85 $
+ *       $Revision: 86 $
  *
  *****************************************************************************/
 
@@ -284,11 +284,9 @@
 #define ACPI_INTERNAL_VAR_XFACE
 
 #define ACPI_ASM_MACROS
-#define causeinterrupt(level)
 #define BREAKPOINT3
-#define acpi_disable_irqs()
-#define acpi_enable_irqs()
-#define halt()
+#define ACPI_DISABLE_IRQS()
+#define ACPI_ENABLE_IRQS()
 #define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acq)
 #define ACPI_RELEASE_GLOBAL_LOCK(Glptr, acq)
 
@@ -299,9 +297,7 @@
 
 /* Don't want software interrupts within a ring3 application */
 
-#undef causeinterrupt
 #undef BREAKPOINT3
-#define causeinterrupt(level)
 #define BREAKPOINT3
 #endif
 
diff -urN linux-2.5.8-pre2/drivers/acpi/include/platform/acgcc.h linux-2.5.8-pre3/drivers/acpi/include/platform/acgcc.h
--- linux-2.5.8-pre2/drivers/acpi/include/platform/acgcc.h	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/platform/acgcc.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acgcc.h - GCC specific defines, etc.
- *       $Revision: 19 $
+ *       $Revision: 22 $
  *
  *****************************************************************************/
 
@@ -30,7 +30,8 @@
 #ifdef __ia64__
 #define _IA64
 
-#define COMPILER_DEPENDENT_UINT64   unsigned long
+#define COMPILER_DEPENDENT_INT64   long
+#define COMPILER_DEPENDENT_UINT64  unsigned long
 
 /*
  * Calling conventions:
@@ -52,10 +53,9 @@
 /* Asm macros */
 
 #define ACPI_ASM_MACROS
-#define causeinterrupt(level)
 #define BREAKPOINT3
-#define acpi_disable_irqs() __cli()
-#define acpi_enable_irqs()  __sti()
+#define ACPI_DISABLE_IRQS() __cli()
+#define ACPI_ENABLE_IRQS()  __sti()
 
 /*! [Begin] no source code translation */
 
@@ -111,7 +111,8 @@
 
 #else /* DO IA32 */
 
-#define COMPILER_DEPENDENT_UINT64   unsigned long long
+#define COMPILER_DEPENDENT_INT64   long long
+#define COMPILER_DEPENDENT_UINT64  unsigned long long
 
 /*
  * Calling conventions:
@@ -129,11 +130,9 @@
 /* Asm macros */
 
 #define ACPI_ASM_MACROS
-#define causeinterrupt(level)
 #define BREAKPOINT3
-#define acpi_disable_irqs() __cli()
-#define acpi_enable_irqs()  __sti()
-#define halt()    __asm__ __volatile__ ("sti; hlt":::"memory")
+#define ACPI_DISABLE_IRQS() __cli()
+#define ACPI_ENABLE_IRQS()  __sti()
 
 /*! [Begin] no source code translation
  *
diff -urN linux-2.5.8-pre2/drivers/acpi/include/platform/aclinux.h linux-2.5.8-pre3/drivers/acpi/include/platform/aclinux.h
--- linux-2.5.8-pre2/drivers/acpi/include/platform/aclinux.h	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/include/platform/aclinux.h	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: aclinux.h - OS specific defines, etc.
- *       $Revision: 15 $
+ *       $Revision: 19 $
  *
  *****************************************************************************/
 
@@ -42,14 +42,20 @@
 
 #define strtoul simple_strtoul
 
+#ifdef _IA64
+#define ACPI_FLUSH_CPU_CACHE()
 #else
+#define ACPI_FLUSH_CPU_CACHE()	wbinvd()
+#endif
+
+#else /* !__KERNEL__ */
 
 #include <stdarg.h>
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
 
-#endif
+#endif /* __KERNEL__ */
 
 /* Linux uses GCC */
 
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nsaccess.c linux-2.5.8-pre3/drivers/acpi/namespace/nsaccess.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nsaccess.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nsaccess.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: nsaccess - Top-level functions for accessing ACPI namespace
- *              $Revision: 152 $
+ *              $Revision: 153 $
  *
  ******************************************************************************/
 
@@ -522,8 +522,9 @@
 				return_ACPI_STATUS (status);
 			}
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
-				"Setting global scope to %p\n", this_node));
+			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+				"Setting current scope to [%4.4s] (%p)\n",
+				this_node->name.ascii, this_node));
 		}
 	}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nsalloc.c linux-2.5.8-pre3/drivers/acpi/namespace/nsalloc.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nsalloc.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nsalloc.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: nsalloc - Namespace allocation and deletion utilities
- *              $Revision: 70 $
+ *              $Revision: 72 $
  *
  ******************************************************************************/
 
@@ -62,7 +62,7 @@
 
 	ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_allocated++);
 
-	node->name           = name;
+	node->name.integer   = name;
 	node->reference_count = 1;
 	ACPI_SET_DESCRIPTOR_TYPE (node, ACPI_DESC_TYPE_NAMED);
 
@@ -206,7 +206,7 @@
 		 * We will fill in the actual type when the
 		 * real definition is found later.
 		 */
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "[%4.4s] is a forward reference\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] is a forward reference\n",
 			(char *) &node->name));
 	}
 
@@ -302,7 +302,7 @@
 
 		ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++);
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object %p, Remaining %X\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p, Remaining %X\n",
 			child_node, acpi_gbl_current_node_count));
 
 		/*
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nsdump.c linux-2.5.8-pre3/drivers/acpi/namespace/nsdump.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nsdump.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nsdump.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsdump - table dumping routines for debug
- *              $Revision: 127 $
+ *              $Revision: 129 $
  *
  *****************************************************************************/
 
@@ -53,7 +53,7 @@
 	u32                     num_segments,
 	char                    *pathname)
 {
-	ACPI_FUNCTION_NAME ("Acpi_ns_print_pathname");
+	ACPI_FUNCTION_NAME ("Ns_print_pathname");
 
 
 	if (!(acpi_dbg_level & ACPI_LV_NAMES) || !(acpi_dbg_layer & ACPI_NAMESPACE)) {
@@ -228,7 +228,7 @@
 		type = INTERNAL_TYPE_DEF_ANY;  /* prints as *ERROR* */
 	}
 
-	if (!acpi_ut_valid_acpi_name (this_node->name)) {
+	if (!acpi_ut_valid_acpi_name (this_node->name.integer)) {
 		ACPI_REPORT_WARNING (("Invalid ACPI Name %08X\n", this_node->name));
 	}
 
@@ -255,59 +255,87 @@
 
 		switch (type) {
 		case ACPI_TYPE_PROCESSOR:
+
 			acpi_os_printf (" ID %d Addr %.4X Len %.4X\n",
 					 obj_desc->processor.proc_id,
 					 obj_desc->processor.address,
 					 obj_desc->processor.length);
 			break;
 
+
 		case ACPI_TYPE_DEVICE:
+
 			acpi_os_printf (" Notification object: %p", obj_desc);
 			break;
 
+
 		case ACPI_TYPE_METHOD:
+
 			acpi_os_printf (" Args %d Len %.4X Aml %p \n",
 					 obj_desc->method.param_count,
 					 obj_desc->method.aml_length,
 					 obj_desc->method.aml_start);
 			break;
 
+
 		case ACPI_TYPE_INTEGER:
+
 			acpi_os_printf (" = %8.8X%8.8X\n",
 					 ACPI_HIDWORD (obj_desc->integer.value),
 					 ACPI_LODWORD (obj_desc->integer.value));
 			break;
 
+
 		case ACPI_TYPE_PACKAGE:
-			acpi_os_printf (" Elements %.2X\n",
-					 obj_desc->package.count);
+
+			if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+				acpi_os_printf (" Elements %.2X\n",
+						 obj_desc->package.count);
+			}
+			else {
+				acpi_os_printf (" [Length not yet evaluated]\n");
+			}
 			break;
 
-		case ACPI_TYPE_BUFFER:
-			acpi_os_printf (" Len %.2X",
-					 obj_desc->buffer.length);
 
-			/* Dump some of the buffer */
+		case ACPI_TYPE_BUFFER:
 
-			if (obj_desc->buffer.length > 0) {
-				acpi_os_printf (" =");
-				for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) {
-					acpi_os_printf (" %.2X", obj_desc->buffer.pointer[i]);
+			if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+				acpi_os_printf (" Len %.2X",
+						 obj_desc->buffer.length);
+
+				/* Dump some of the buffer */
+
+				if (obj_desc->buffer.length > 0) {
+					acpi_os_printf (" =");
+					for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) {
+						acpi_os_printf (" %.2X", obj_desc->buffer.pointer[i]);
+					}
 				}
+				acpi_os_printf ("\n");
+			}
+			else {
+				acpi_os_printf (" [Length not yet evaluated]\n");
 			}
-			acpi_os_printf ("\n");
 			break;
 
+
 		case ACPI_TYPE_STRING:
+
 			acpi_os_printf (" Len %.2X", obj_desc->string.length);
 
 			if (obj_desc->string.length > 0) {
-				 acpi_os_printf (" = \"%.32s\"...", obj_desc->string.pointer);
+				acpi_os_printf (" = \"%.32s\"", obj_desc->string.pointer);
+				if (obj_desc->string.length > 32) {
+					acpi_os_printf ("...");
+				}
 			}
 			acpi_os_printf ("\n");
 			break;
 
+
 		case ACPI_TYPE_REGION:
+
 			acpi_os_printf (" [%s]", acpi_ut_get_region_name (obj_desc->region.space_id));
 			if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
 				acpi_os_printf (" Addr %8.8X%8.8X Len %.4X\n",
@@ -316,16 +344,20 @@
 						 obj_desc->region.length);
 			}
 			else {
-				acpi_os_printf (" [Address/Length not evaluated]\n");
+				acpi_os_printf (" [Address/Length not yet evaluated]\n");
 			}
 			break;
 
+
 		case INTERNAL_TYPE_REFERENCE:
+
 			acpi_os_printf (" [%s]\n",
 					acpi_ps_get_opcode_name (obj_desc->reference.opcode));
 			break;
 
+
 		case ACPI_TYPE_BUFFER_FIELD:
+
 			if (obj_desc->buffer_field.buffer_obj &&
 				obj_desc->buffer_field.buffer_obj->buffer.node) {
 				acpi_os_printf (" Buf [%4.4s]",
@@ -333,24 +365,32 @@
 			}
 			break;
 
+
 		case INTERNAL_TYPE_REGION_FIELD:
+
 			acpi_os_printf (" Rgn [%4.4s]",
 					(char *) &obj_desc->common_field.region_obj->region.node->name);
 			break;
 
+
 		case INTERNAL_TYPE_BANK_FIELD:
+
 			acpi_os_printf (" Rgn [%4.4s] Bnk [%4.4s]",
 					(char *) &obj_desc->common_field.region_obj->region.node->name,
 					(char *) &obj_desc->bank_field.bank_obj->common_field.node->name);
 			break;
 
+
 		case INTERNAL_TYPE_INDEX_FIELD:
+
 			acpi_os_printf (" Idx [%4.4s] Dat [%4.4s]",
 					(char *) &obj_desc->index_field.index_obj->common_field.node->name,
 					(char *) &obj_desc->index_field.data_obj->common_field.node->name);
 			break;
 
+
 		default:
+
 			acpi_os_printf (" Object %p\n", obj_desc);
 			break;
 		}
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nseval.c linux-2.5.8-pre3/drivers/acpi/namespace/nseval.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nseval.c	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nseval.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nseval - Object evaluation interfaces -- includes control
  *                       method lookup and execution.
- *              $Revision: 109 $
+ *              $Revision: 112 $
  *
  ******************************************************************************/
 
@@ -113,7 +113,7 @@
 	(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
 
 	if (ACPI_FAILURE (status)) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object [%s] not found [%s]\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object [%s] not found [%s]\n",
 			pathname, acpi_format_exception (status)));
 		goto cleanup;
 	}
@@ -122,12 +122,12 @@
 	 * Now that we have a handle to the object, we can attempt
 	 * to evaluate it.
 	 */
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s [%p] Value %p\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
 		pathname, node, acpi_ns_get_attached_object (node)));
 
 	status = acpi_ns_evaluate_by_handle (node, params, return_object);
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "*** Completed eval of object %s ***\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n",
 		pathname));
 
 cleanup:
@@ -192,7 +192,7 @@
 	(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
 
 	if (ACPI_FAILURE (status)) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object at [%s] was not found, status=%.4X\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object at [%s] was not found, status=%.4X\n",
 			pathname, status));
 		goto cleanup;
 	}
@@ -201,12 +201,12 @@
 	 * Now that we have a handle to the object, we can attempt
 	 * to evaluate it.
 	 */
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s [%p] Value %p\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
 		pathname, node, acpi_ns_get_attached_object (node)));
 
 	status = acpi_ns_evaluate_by_handle (node, params, return_object);
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "*** Completed eval of object %s ***\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n",
 		pathname));
 
 
@@ -390,16 +390,11 @@
 		return_ACPI_STATUS (AE_NULL_OBJECT);
 	}
 
-
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Control method at Offset %p Length %x]\n",
-		obj_desc->method.aml_start + 1, obj_desc->method.aml_length - 1));
-
 	ACPI_DUMP_PATHNAME (method_node, "Ns_execute_control_method: Executing",
-		ACPI_LV_NAMES, _COMPONENT);
-
-	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "At offset %p\n",
-			obj_desc->method.aml_start + 1));
+		ACPI_LV_INFO, _COMPONENT);
 
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %x\n",
+		obj_desc->method.aml_start + 1, obj_desc->method.aml_length - 1));
 
 	/*
 	 * Unlock the namespace before execution.  This allows namespace access
@@ -497,7 +492,7 @@
 		if (ACPI_SUCCESS (status)) {
 			status = AE_CTRL_RETURN_VALUE;
 			*return_obj_desc = obj_desc;
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Returning obj %p\n", *return_obj_desc));
+			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning obj %p\n", *return_obj_desc));
 		}
 	}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nsinit.c linux-2.5.8-pre3/drivers/acpi/namespace/nsinit.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nsinit.c	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nsinit.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsinit - namespace initialization
- *              $Revision: 41 $
+ *              $Revision: 43 $
  *
  *****************************************************************************/
 
@@ -59,15 +59,11 @@
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
 		"**** Starting initialization of namespace objects ****\n"));
-	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Completing Region and Field initialization:"));
+	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Completing Region/Field/Buffer/Package initialization:"));
 
+	/* Set all init info to zero */
 
-	info.field_count = 0;
-	info.field_init = 0;
-	info.op_region_count = 0;
-	info.op_region_init = 0;
-	info.object_count = 0;
-
+	ACPI_MEMSET (&info, 0, sizeof (acpi_init_walk_info));
 
 	/* Walk entire namespace from the supplied root */
 
@@ -79,9 +75,11 @@
 	}
 
 	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK,
-		"\n%d/%d Regions, %d/%d Fields initialized (%d nodes total)\n",
-		info.op_region_init, info.op_region_count, info.field_init,
-		info.field_count, info.object_count));
+		"\n Initialized %d/%d Regions %d/%d Fields %d/%d Buffers %d/%d Packages (%d nodes)\n",
+		info.op_region_init, info.op_region_count,
+		info.field_init,    info.field_count,
+		info.buffer_init,   info.buffer_count,
+		info.package_init,  info.package_count, info.object_count));
 	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
 		"%d Control Methods found\n", info.method_count));
 	ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
@@ -118,12 +116,15 @@
 	ACPI_FUNCTION_TRACE ("Ns_initialize_devices");
 
 
+	/* Init counters */
+
 	info.device_count = 0;
 	info.num_STA = 0;
 	info.num_INI = 0;
 
+	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Executing all Device _STA and_INI methods:"));
 
-	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "Executing device _INI methods:"));
+	/* Walk namespace for all objects of type Device */
 
 	status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 			  ACPI_UINT32_MAX, FALSE, acpi_ns_init_one_device, &info, NULL);
@@ -132,9 +133,8 @@
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Walk_namespace failed! %x\n", status));
 	}
 
-
 	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK,
-		"\n%d Devices found: %d _STA, %d _INI\n",
+		"\n%d Devices found containing: %d _STA, %d _INI methods\n",
 		info.device_count, info.num_STA, info.num_INI));
 
 	return_ACPI_STATUS (status);
@@ -180,7 +180,6 @@
 
 	info->object_count++;
 
-
 	/* And even then, we are only interested in a few object types */
 
 	type = acpi_ns_get_type (obj_handle);
@@ -189,11 +188,37 @@
 		return (AE_OK);
 	}
 
-	if ((type != ACPI_TYPE_REGION) &&
-		(type != ACPI_TYPE_BUFFER_FIELD)) {
+	/* Increment counters for object types we are looking for */
+
+	switch (type) {
+	case ACPI_TYPE_REGION:
+		info->op_region_count++;
+		break;
+
+	case ACPI_TYPE_BUFFER_FIELD:
+		info->field_count++;
+		break;
+
+	case ACPI_TYPE_BUFFER:
+		info->buffer_count++;
+		break;
+
+	case ACPI_TYPE_PACKAGE:
+		info->package_count++;
+		break;
+
+	default:
+
+		/* No init required, just exit now */
 		return (AE_OK);
 	}
 
+	/*
+	 * If the object is already initialized, nothing else to do
+	 */
+	if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+		return (AE_OK);
+	}
 
 	/*
 	 * Must lock the interpreter before executing AML code
@@ -203,61 +228,53 @@
 		return (status);
 	}
 
+	/*
+	 * Each of these types can contain executable AML code within
+	 * the declaration.
+	 */
 	switch (type) {
-
 	case ACPI_TYPE_REGION:
 
-		info->op_region_count++;
-		if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
-			break;
-		}
-
 		info->op_region_init++;
 		status = acpi_ds_get_region_arguments (obj_desc);
-		if (ACPI_FAILURE (status)) {
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n"));
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-					"%s while getting region arguments [%4.4s]\n",
-					acpi_format_exception (status), (char *) &node->name));
-		}
-
-		if (!(acpi_dbg_level & ACPI_LV_INIT)) {
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "."));
-		}
-
 		break;
 
 
 	case ACPI_TYPE_BUFFER_FIELD:
 
-		info->field_count++;
-		if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
-			break;
-		}
-
 		info->field_init++;
 		status = acpi_ds_get_buffer_field_arguments (obj_desc);
-		if (ACPI_FAILURE (status)) {
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n"));
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-					"%s while getting buffer field arguments [%4.4s]\n",
-					acpi_format_exception (status), (char *) &node->name));
-		}
-		if (!(acpi_dbg_level & ACPI_LV_INIT)) {
-			ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "."));
-		}
+		break;
 
 
+	case ACPI_TYPE_BUFFER:
+
+		info->buffer_init++;
+		status = acpi_ds_get_buffer_arguments (obj_desc);
 		break;
 
-	default:
+
+	case ACPI_TYPE_PACKAGE:
+
+		info->package_init++;
+		status = acpi_ds_get_package_arguments (obj_desc);
 		break;
 	}
 
+	if (ACPI_FAILURE (status)) {
+		ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n"));
+		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+				"Could not execute arguments for [%4.4s] (%s), %s\n",
+				(char *) &node->name, acpi_ut_get_type_name (type), acpi_format_exception (status)));
+	}
+
+	if (!(acpi_dbg_level & ACPI_LV_INIT)) {
+		ACPI_DEBUG_PRINT_RAW ((ACPI_DB_OK, "."));
+	}
 
 	/*
 	 * We ignore errors from above, and always return OK, since
-	 * we don't want to abort the walk on a single error.
+	 * we don't want to abort the walk on any single error.
 	 */
 	acpi_ex_exit_interpreter ();
 	return (AE_OK);
@@ -335,7 +352,6 @@
 		return_ACPI_STATUS(AE_CTRL_DEPTH);
 	}
 
-
 	/*
 	 * The device is present. Run _INI.
 	 */
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nsobject.c linux-2.5.8-pre3/drivers/acpi/namespace/nsobject.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nsobject.c	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nsobject.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nsobject - Utilities for objects attached to namespace
  *                         table entries
- *              $Revision: 78 $
+ *              $Revision: 80 $
  *
  ******************************************************************************/
 
@@ -221,7 +221,7 @@
 
 	node->type = ACPI_TYPE_ANY;
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Node %p [%4.4s] Object %p\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n",
 		node, (char *) &node->name, obj_desc));
 
 	/* Remove one reference on the object (and all subobjects) */
@@ -280,7 +280,7 @@
 acpi_ns_get_secondary_object (
 	acpi_operand_object     *obj_desc)
 {
-	ACPI_FUNCTION_TRACE_PTR ("Acpi_ns_get_secondary_object", obj_desc);
+	ACPI_FUNCTION_TRACE_PTR ("Ns_get_secondary_object", obj_desc);
 
 
 	if ((!obj_desc)                                  ||
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nssearch.c linux-2.5.8-pre3/drivers/acpi/namespace/nssearch.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nssearch.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nssearch.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: nssearch - Namespace search
- *              $Revision: 83 $
+ *              $Revision: 84 $
  *
  ******************************************************************************/
 
@@ -95,7 +95,7 @@
 	while (next_node) {
 		/* Check for match against the name */
 
-		if (next_node->name == target_name) {
+		if (next_node->name.integer == target_name) {
 			/*
 			 * Found matching entry.  Capture the type if appropriate, before
 			 * returning the entry.
@@ -146,8 +146,8 @@
 
 	/* Searched entire table, not found */
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Name %4.4s (type %X) not found at %p\n",
-		(char *) &target_name, type, next_node));
+	ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Name %4.4s Type [%s] not found at %p\n",
+		(char *) &target_name, acpi_ut_get_type_name (type), next_node));
 
 	return_ACPI_STATUS (AE_NOT_FOUND);
 }
@@ -206,8 +206,8 @@
 		}
 
 		if (acpi_ns_local (type)) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] type %X is local(no search)\n",
-				(char *) &target_name, type));
+			ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] type [%s] must be local to this scope (no parent search)\n",
+				(char *) &target_name, acpi_ut_get_type_name (type)));
 		}
 
 		return_ACPI_STATUS (AE_NOT_FOUND);
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nsutils.c linux-2.5.8-pre3/drivers/acpi/namespace/nsutils.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nsutils.c	Mon Mar 18 12:37:15 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nsutils.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
  *                        parents and siblings and Scope manipulation
- *              $Revision: 104 $
+ *              $Revision: 105 $
  *
  *****************************************************************************/
 
@@ -254,7 +254,6 @@
 			result = &internal_name[3];
 		}
 	}
-
 	else {
 		/*
 		 * Not fully qualified.
@@ -281,7 +280,6 @@
 		}
 	}
 
-
 	/* Build the name (minus path separators) */
 
 	for (; num_segments; num_segments--) {
@@ -319,11 +317,11 @@
 
 	if (info->fully_qualified) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "returning [%p] (abs) \"\\%s\"\n",
-			internal_name, &internal_name[0]));
+			internal_name, internal_name));
 	}
 	else {
 		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "returning [%p] (rel) \"%s\"\n",
-			internal_name, &internal_name[2]));
+			internal_name, internal_name));
 	}
 
 	return_ACPI_STATUS (AE_OK);
@@ -823,8 +821,8 @@
 				child_node, (char *) &child_node->name,
 				parent_node, (char *) &parent_node->name));
 
-			if (parent_node->name) {
-				return_VALUE (parent_node->name);
+			if (parent_node->name.integer) {
+				return_VALUE (parent_node->name.integer);
 			}
 		}
 
@@ -863,7 +861,7 @@
 		return (FALSE);
 	}
 
-	if (node->name) {
+	if (node->name.integer) {
 		return (TRUE);
 	}
 
diff -urN linux-2.5.8-pre2/drivers/acpi/namespace/nsxfname.c linux-2.5.8-pre3/drivers/acpi/namespace/nsxfname.c
--- linux-2.5.8-pre2/drivers/acpi/namespace/nsxfname.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/acpi/namespace/nsxfname.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nsxfname - Public interfaces to the ACPI subsystem
  *                         ACPI Namespace oriented interfaces
- *              $Revision: 89 $
+ *              $Revision: 90 $
  *
  *****************************************************************************/
 
@@ -243,8 +243,8 @@
 		return (AE_BAD_PARAMETER);
 	}
 
-	info->type      = node->type;
-	info->name      = node->name;
+	info->type = node->type;
+	info->name = node->name.integer;
 
 	status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE (status)) {
diff -urN linux-2.5.8-pre2/drivers/acpi/parser/psopcode.c linux-2.5.8-pre3/drivers/acpi/parser/psopcode.c
--- linux-2.5.8-pre2/drivers/acpi/parser/psopcode.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/acpi/parser/psopcode.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psopcode - Parser/Interpreter opcode information table
- *              $Revision: 64 $
+ *              $Revision: 66 $
  *
  *****************************************************************************/
 
@@ -219,7 +219,7 @@
 #define ARGI_BIT_XOR_OP                 ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_BREAK_OP                   ARG_NONE
 #define ARGI_BREAK_POINT_OP             ARG_NONE
-#define ARGI_BUFFER_OP                  ARGI_INVALID_OPCODE
+#define ARGI_BUFFER_OP                  ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_BYTE_OP                    ARGI_INVALID_OPCODE
 #define ARGI_BYTELIST_OP                ARGI_INVALID_OPCODE
 #define ARGI_CONCAT_OP                  ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA,   ARGI_TARGETREF)
@@ -284,7 +284,7 @@
 #define ARGI_NOTIFY_OP                  ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER)
 #define ARGI_ONE_OP                     ARG_NONE
 #define ARGI_ONES_OP                    ARG_NONE
-#define ARGI_PACKAGE_OP                 ARGI_INVALID_OPCODE
+#define ARGI_PACKAGE_OP                 ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_POWER_RES_OP               ARGI_INVALID_OPCODE
 #define ARGI_PROCESSOR_OP               ARGI_INVALID_OPCODE
 #define ARGI_QWORD_OP                   ARGI_INVALID_OPCODE
@@ -315,7 +315,7 @@
 #define ARGI_TO_STRING_OP               ARGI_LIST3 (ARGI_BUFFER,     ARGI_INTEGER,       ARGI_FIXED_TARGET)
 #define ARGI_TYPE_OP                    ARGI_LIST1 (ARGI_ANYTYPE)
 #define ARGI_UNLOAD_OP                  ARGI_LIST1 (ARGI_DDBHANDLE)
-#define ARGI_VAR_PACKAGE_OP             ARGI_INVALID_OPCODE
+#define ARGI_VAR_PACKAGE_OP             ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_WAIT_OP                    ARGI_LIST2 (ARGI_EVENT,      ARGI_INTEGER)
 #define ARGI_WHILE_OP                   ARGI_INVALID_OPCODE
 #define ARGI_WORD_OP                    ARGI_INVALID_OPCODE
@@ -422,6 +422,7 @@
 	AML_CREATE_DWORD_FIELD_OP
 	AML_CREATE_QWORD_FIELD_OP
 	AML_REGION_OP
+	AML_BUFFER_OP
 
   Field opcodes
 
@@ -461,8 +462,8 @@
 /* 06 */ ACPI_OP ("DwordConst",         ARGP_DWORD_OP,             ARGI_DWORD_OP,              ACPI_TYPE_INTEGER,       AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         0),
 /* 07 */ ACPI_OP ("String",             ARGP_STRING_OP,            ARGI_STRING_OP,             ACPI_TYPE_STRING,        AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         0),
 /* 08 */ ACPI_OP ("Scope",              ARGP_SCOPE_OP,             ARGI_SCOPE_OP,              INTERNAL_TYPE_SCOPE,     AML_CLASS_NAMED_OBJECT,    AML_TYPE_NAMED_NO_OBJ,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
-/* 09 */ ACPI_OP ("Buffer",             ARGP_BUFFER_OP,            ARGI_BUFFER_OP,             ACPI_TYPE_BUFFER,        AML_CLASS_ARGUMENT,        AML_TYPE_DATA_TERM,       AML_HAS_ARGS),
-/* 0A */ ACPI_OP ("Package",            ARGP_PACKAGE_OP,           ARGI_PACKAGE_OP,            ACPI_TYPE_PACKAGE,       AML_CLASS_ARGUMENT,        AML_TYPE_DATA_TERM,       AML_HAS_ARGS),
+/* 09 */ ACPI_OP ("Buffer",             ARGP_BUFFER_OP,            ARGI_BUFFER_OP,             ACPI_TYPE_BUFFER,        AML_CLASS_CREATE,          AML_TYPE_CREATE_OBJECT,   AML_HAS_ARGS | AML_DEFER),
+/* 0A */ ACPI_OP ("Package",            ARGP_PACKAGE_OP,           ARGI_PACKAGE_OP,            ACPI_TYPE_PACKAGE,       AML_CLASS_CREATE,          AML_TYPE_CREATE_OBJECT,   AML_HAS_ARGS | AML_DEFER),
 /* 0B */ ACPI_OP ("Method",             ARGP_METHOD_OP,            ARGI_METHOD_OP,             ACPI_TYPE_METHOD,        AML_CLASS_NAMED_OBJECT,    AML_TYPE_NAMED_COMPLEX,   AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER),
 /* 0C */ ACPI_OP ("Local0",             ARGP_LOCAL0,               ARGI_LOCAL0,                INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT,        AML_TYPE_LOCAL_VARIABLE,  0),
 /* 0D */ ACPI_OP ("Local1",             ARGP_LOCAL1,               ARGI_LOCAL1,                INTERNAL_TYPE_REFERENCE, AML_CLASS_ARGUMENT,        AML_TYPE_LOCAL_VARIABLE,  0),
@@ -573,7 +574,7 @@
 /* ACPI 2.0 opcodes */
 
 /* 6E */ ACPI_OP ("QwordConst",         ARGP_QWORD_OP,             ARGI_QWORD_OP,              ACPI_TYPE_INTEGER,       AML_CLASS_ARGUMENT,        AML_TYPE_LITERAL,         0),
-/* 6F */ ACPI_OP ("Package /*Var*/",    ARGP_VAR_PACKAGE_OP,       ARGI_VAR_PACKAGE_OP,        ACPI_TYPE_PACKAGE,       AML_CLASS_ARGUMENT,        AML_TYPE_DATA_TERM,       AML_HAS_ARGS | AML_DEFER),
+/* 6F */ ACPI_OP ("Package /*Var*/",    ARGP_VAR_PACKAGE_OP,       ARGI_VAR_PACKAGE_OP,        ACPI_TYPE_PACKAGE,       AML_CLASS_CREATE,          AML_TYPE_CREATE_OBJECT,   AML_HAS_ARGS | AML_DEFER),
 /* 70 */ ACPI_OP ("ConcatenateResTemplate", ARGP_CONCAT_RES_OP,    ARGI_CONCAT_RES_OP,         ACPI_TYPE_ANY,           AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_1T_1R,   AML_FLAGS_EXEC_2A_1T_1R),
 /* 71 */ ACPI_OP ("Mod",                ARGP_MOD_OP,               ARGI_MOD_OP,                ACPI_TYPE_ANY,           AML_CLASS_EXECUTE,         AML_TYPE_EXEC_2A_1T_1R,   AML_FLAGS_EXEC_2A_1T_1R),
 /* 72 */ ACPI_OP ("CreateQWordField",   ARGP_CREATE_QWORD_FIELD_OP,ARGI_CREATE_QWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD,  AML_CLASS_CREATE,          AML_TYPE_CREATE_FIELD,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
@@ -587,6 +588,7 @@
 /* 7A */ ACPI_OP ("Continue",           ARGP_CONTINUE_OP,          ARGI_CONTINUE_OP,           ACPI_TYPE_ANY,           AML_CLASS_CONTROL,         AML_TYPE_CONTROL,         0),
 /* 7B */ ACPI_OP ("LoadTable",          ARGP_LOAD_TABLE_OP,        ARGI_LOAD_TABLE_OP,         ACPI_TYPE_ANY,           AML_CLASS_EXECUTE,         AML_TYPE_EXEC_6A_0T_1R,   AML_FLAGS_EXEC_6A_0T_1R),
 /* 7C */ ACPI_OP ("DataTableRegion",    ARGP_DATA_REGION_OP,       ARGI_DATA_REGION_OP,        ACPI_TYPE_REGION,        AML_CLASS_NAMED_OBJECT,    AML_TYPE_NAMED_SIMPLE,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 7D */ ACPI_OP ("[EvalSubTree]",      ARGP_SCOPE_OP,             ARGI_SCOPE_OP,              INTERNAL_TYPE_SCOPE,     AML_CLASS_NAMED_OBJECT,    AML_TYPE_NAMED_NO_OBJ,    AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE)
 
 /*! [End] no source code translation !*/
 };
@@ -606,7 +608,7 @@
 /* 0x18 */	_UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
 /* 0x20 */	_UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
 /* 0x28 */	_UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
-/* 0x30 */	0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, _UNK,
+/* 0x30 */	0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D,
 /* 0x38 */	_UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
 /* 0x40 */	_UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
 /* 0x48 */	_ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
diff -urN linux-2.5.8-pre2/drivers/acpi/parser/psparse.c linux-2.5.8-pre3/drivers/acpi/parser/psparse.c
--- linux-2.5.8-pre2/drivers/acpi/parser/psparse.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/acpi/parser/psparse.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psparse - Parser top level AML parse routines
- *              $Revision: 119 $
+ *              $Revision: 121 $
  *
  *****************************************************************************/
 
@@ -220,7 +220,7 @@
 
 				/*
 				 * These opcodes contain Term_arg operands. The current
-				 * op must be replace by a placeholder return op
+				 * op must be replaced by a placeholder return op
 				 */
 				replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
 				if (!replacement_op) {
@@ -232,15 +232,35 @@
 
 				/*
 				 * These opcodes contain Term_arg operands. The current
-				 * op must be replace by a placeholder return op
+				 * op must be replaced by a placeholder return op
 				 */
-				if ((op->parent->opcode == AML_REGION_OP)               ||
-					(op->parent->opcode == AML_DATA_REGION_OP)) {
+				if ((op->parent->opcode == AML_REGION_OP)       ||
+					(op->parent->opcode == AML_DATA_REGION_OP)  ||
+					(op->parent->opcode == AML_BUFFER_OP)       ||
+					(op->parent->opcode == AML_PACKAGE_OP)      ||
+					(op->parent->opcode == AML_VAR_PACKAGE_OP)) {
 					replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
 					if (!replacement_op) {
 						return_VALUE (FALSE);
 					}
 				}
+
+				if ((op->parent->opcode == AML_NAME_OP) &&
+					(walk_state->descending_callback != acpi_ds_exec_begin_op)) {
+					if ((op->opcode == AML_BUFFER_OP) ||
+						(op->opcode == AML_PACKAGE_OP) ||
+						(op->opcode == AML_VAR_PACKAGE_OP)) {
+						replacement_op = acpi_ps_alloc_op (op->opcode);
+						if (!replacement_op) {
+							return_VALUE (FALSE);
+						}
+
+						((acpi_parse2_object *) replacement_op)->data =
+							((acpi_parse2_object *) op)->data;
+						((acpi_parse2_object *) replacement_op)->length =
+							((acpi_parse2_object *) op)->length;
+					}
+				}
 				break;
 
 			default:
@@ -259,6 +279,7 @@
 				if (replacement_op) {
 					replacement_op->parent   = op->parent;
 					replacement_op->value.arg = NULL;
+					replacement_op->node     = op->node;
 					op->parent->value.arg    = replacement_op;
 					replacement_op->next     = op->next;
 				}
@@ -275,10 +296,11 @@
 				next = prev->next;
 				if (next == op) {
 					if (replacement_op) {
-						replacement_op->parent = op->parent;
+						replacement_op->parent   = op->parent;
 						replacement_op->value.arg = NULL;
-						prev->next = replacement_op;
-						replacement_op->next = op->next;
+						replacement_op->node     = op->node;
+						prev->next               = replacement_op;
+						replacement_op->next     = op->next;
 						next = NULL;
 					}
 					else {
@@ -312,9 +334,10 @@
  *
  * PARAMETERS:  Parser_state        - Current parser state object
  *
- * RETURN:
+ * RETURN:      Status
  *
- * DESCRIPTION:
+ * DESCRIPTION: Update the parser state based upon the return exception from
+ *              the parser callback.
  *
  ******************************************************************************/
 
@@ -441,7 +464,7 @@
 	acpi_parse_object       *arg = NULL;
 	acpi_parse_object       pre_op;
 	acpi_parse_state        *parser_state;
-	u8                      *aml_op_start;
+	u8                      *aml_op_start = NULL;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("Ps_parse_loop", walk_state);
@@ -465,7 +488,6 @@
 				(walk_state->control_state) &&
 				(walk_state->control_state->common.state ==
 					ACPI_CONTROL_PREDICATE_EXECUTING)) {
-
 				/*
 				 * A predicate was just completed, get the value of the
 				 * predicate and branch based on that value
@@ -491,7 +513,6 @@
 			acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count);
 			ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op));
 		}
-
 		else if (walk_state->prev_op) {
 			/* We were in the middle of an op */
 
@@ -535,8 +556,8 @@
 				/* The opcode is unrecognized.  Just skip unknown opcodes */
 
 				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-					"Found unknown opcode %X at AML offset %X, ignoring\n",
-					walk_state->opcode, walk_state->aml_offset));
+					"Found unknown opcode %X at AML address %p offset %X, ignoring\n",
+					walk_state->opcode, parser_state->aml, walk_state->aml_offset));
 
 				ACPI_DUMP_BUFFER (parser_state->aml, 128);
 
@@ -552,10 +573,8 @@
 				parser_state->aml += acpi_ps_get_opcode_size (walk_state->opcode);
 				walk_state->arg_types = walk_state->op_info->parse_args;
 				break;
-
 			}
 
-
 			/* Create Op structure and append to parent's argument list */
 
 			if (walk_state->op_info->flags & AML_NAMED) {
@@ -570,7 +589,6 @@
 					INCREMENT_ARG_LIST (walk_state->arg_types);
 				}
 
-
 				/* We know that this arg is a name, move to next arg */
 
 				INCREMENT_ARG_LIST (walk_state->arg_types);
@@ -624,7 +642,6 @@
 					((acpi_parse2_object * ) op)->length  = 0;
 				}
 			}
-
 			else {
 				/* Not a named opcode, just allocate Op and append to parent */
 
@@ -680,7 +697,7 @@
 		walk_state->arg_count = 0;
 
 		if (walk_state->arg_types) /* Are there any arguments that must be processed? */ {
-			/* get arguments */
+			/* Get arguments */
 
 			switch (op->opcode) {
 			case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
@@ -689,7 +706,7 @@
 			case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
 			case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */
 
-				/* fill in constant or string argument directly */
+				/* Fill in constant or string argument directly */
 
 				acpi_ps_get_next_simple_arg (parser_state,
 						 GET_CURRENT_ARG_TYPE (walk_state->arg_types), op);
@@ -719,9 +736,11 @@
 					INCREMENT_ARG_LIST (walk_state->arg_types);
 				}
 
-				/* For a method, save the length and address of the body */
+				switch (op->opcode) {
+				case AML_METHOD_OP:
+
+					/* For a method, save the length and address of the body */
 
-				if (op->opcode == AML_METHOD_OP) {
 					/*
 					 * Skip parsing of control method or opregion body,
 					 * because we don't have enough info in the first pass
@@ -730,7 +749,6 @@
 					((acpi_parse2_object * ) op)->data   = parser_state->aml;
 					((acpi_parse2_object * ) op)->length = (u32) (parser_state->pkg_end -
 							  parser_state->aml);
-
 					/*
 					 * Skip body of method.  For Op_regions, we must continue
 					 * parsing because the opregion is not a standalone
@@ -738,17 +756,42 @@
 					 */
 					parser_state->aml   = parser_state->pkg_end;
 					walk_state->arg_count = 0;
-				}
-				else if (op->opcode == AML_WHILE_OP) {
+					break;
+
+				case AML_BUFFER_OP:
+				case AML_PACKAGE_OP:
+				case AML_VAR_PACKAGE_OP:
+
+					if ((op->parent) &&
+						(op->parent->opcode == AML_NAME_OP) &&
+						(walk_state->descending_callback != acpi_ds_exec_begin_op)) {
+						/*
+						 * Skip parsing of
+						 * because we don't have enough info in the first pass
+						 * to parse them correctly.
+						 */
+						((acpi_parse2_object * ) op)->data   = aml_op_start;
+						((acpi_parse2_object * ) op)->length = (u32) (parser_state->pkg_end -
+								  aml_op_start);
+						/*
+						 * Skip body
+						 */
+						parser_state->aml   = parser_state->pkg_end;
+						walk_state->arg_count = 0;
+					}
+					break;
+
+				case AML_WHILE_OP:
+
 					if (walk_state->control_state) {
 						walk_state->control_state->control.package_end = parser_state->pkg_end;
 					}
+					break;
 				}
 				break;
 			}
 		}
 
-
 		/* Check for arguments that need to be processed */
 
 		if (walk_state->arg_count) {
@@ -759,7 +802,6 @@
 			continue;
 		}
 
-
 		/* All arguments have been processed -- Op is complete, prepare for next */
 
 		walk_state->op_info = acpi_ps_get_opcode_info (op->opcode);
diff -urN linux-2.5.8-pre2/drivers/acpi/parser/psutils.c linux-2.5.8-pre3/drivers/acpi/parser/psutils.c
--- linux-2.5.8-pre2/drivers/acpi/parser/psutils.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/parser/psutils.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psutils - Parser miscellaneous utilities (Parser only)
- *              $Revision: 49 $
+ *              $Revision: 50 $
  *
  *****************************************************************************/
 
@@ -97,30 +97,25 @@
 		size = sizeof (acpi_parse2_object);
 		flags = ACPI_PARSEOP_DEFERRED;
 	}
-
 	else if (op_info->flags & AML_NAMED) {
 		size = sizeof (acpi_parse2_object);
 		flags = ACPI_PARSEOP_NAMED;
 	}
-
 	else if (opcode == AML_INT_BYTELIST_OP) {
 		size = sizeof (acpi_parse2_object);
 		flags = ACPI_PARSEOP_BYTELIST;
 	}
-
 	else {
 		size = sizeof (acpi_parse_object);
 		flags = ACPI_PARSEOP_GENERIC;
 	}
 
-
 	if (size == sizeof (acpi_parse_object)) {
 		/*
 		 * The generic op is by far the most common (16 to 1)
 		 */
 		op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE);
 	}
-
 	else {
 		op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE_EXT);
 	}
@@ -157,13 +152,12 @@
 
 
 	if (op->opcode == AML_INT_RETURN_VALUE_OP) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Free retval op: %p\n", op));
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", op));
 	}
 
 	if (op->flags == ACPI_PARSEOP_GENERIC) {
 		acpi_ut_release_to_cache (ACPI_MEM_LIST_PSNODE, op);
 	}
-
 	else {
 		acpi_ut_release_to_cache (ACPI_MEM_LIST_PSNODE_EXT, op);
 	}
diff -urN linux-2.5.8-pre2/drivers/acpi/parser/psxface.c linux-2.5.8-pre3/drivers/acpi/parser/psxface.c
--- linux-2.5.8-pre2/drivers/acpi/parser/psxface.c	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/drivers/acpi/parser/psxface.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psxface - Parser external interfaces
- *              $Revision: 59 $
+ *              $Revision: 61 $
  *
  *****************************************************************************/
 
@@ -102,7 +102,7 @@
 	 * 1) Perform the first pass parse of the method to enter any
 	 * named objects that it creates into the namespace
 	 */
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
 		"**** Begin Method Parse **** Entry=%p obj=%p\n",
 		method_node, obj_desc));
 
@@ -144,7 +144,7 @@
 	/*
 	 * 2) Execute the method.  Performs second pass parse simultaneously
 	 */
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
 		"**** Begin Method Execution **** Entry=%p obj=%p\n",
 		method_node, obj_desc));
 
@@ -157,7 +157,7 @@
 
 	/* Init new op with the method name and pointer back to the NS node */
 
-	acpi_ps_set_name (op, method_node->name);
+	acpi_ps_set_name (op, method_node->name.integer);
 	op->node = method_node;
 
 	/* Create and initialize a new walk state */
@@ -194,7 +194,7 @@
 	 * a control exception code
 	 */
 	if (*return_obj_desc) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Method returned Obj_desc=%p\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned Obj_desc=%p\n",
 			*return_obj_desc));
 		ACPI_DUMP_STACK_ENTRY (*return_obj_desc);
 
diff -urN linux-2.5.8-pre2/drivers/acpi/tables/tbget.c linux-2.5.8-pre3/drivers/acpi/tables/tbget.c
--- linux-2.5.8-pre2/drivers/acpi/tables/tbget.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/tables/tbget.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbget - ACPI Table get* routines
- *              $Revision: 63 $
+ *              $Revision: 67 $
  *
  *****************************************************************************/
 
@@ -125,8 +125,7 @@
 
 acpi_status
 acpi_tb_get_table (
-	ACPI_PHYSICAL_ADDRESS   physical_address,
-	acpi_table_header       *buffer_ptr,
+	ACPI_POINTER            *address,
 	acpi_table_desc         *table_info)
 {
 	acpi_table_header       *table_header = NULL;
@@ -139,21 +138,17 @@
 	ACPI_FUNCTION_TRACE ("Tb_get_table");
 
 
-	if (!table_info) {
+	if (!table_info || !address) {
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
-	if (buffer_ptr) {
+	switch (address->pointer_type) {
+	case ACPI_LOGICAL_POINTER:
+
 		/*
 		 * Getting data from a buffer, not BIOS tables
 		 */
-		table_header = buffer_ptr;
-		status = acpi_tb_validate_table_header (table_header);
-		if (ACPI_FAILURE (status)) {
-			/* Table failed verification, map all errors to BAD_DATA */
-
-			return_ACPI_STATUS (AE_BAD_DATA);
-		}
+		table_header = address->pointer.logical;
 
 		/* Allocate buffer for the entire table */
 
@@ -165,21 +160,23 @@
 		/* Copy the entire table (including header) to the local buffer */
 
 		size = table_header->length;
-		ACPI_MEMCPY (full_table, buffer_ptr, size);
+		ACPI_MEMCPY (full_table, table_header, size);
 
 		/* Save allocation type */
 
 		allocation = ACPI_MEM_ALLOCATED;
-	}
+		break;
 
-	/*
-	 * Not reading from a buffer, just map the table's physical memory
-	 * into our address space.
-	 */
-	else {
+
+	case ACPI_PHYSICAL_POINTER:
+
+		/*
+		 * Not reading from a buffer, just map the table's physical memory
+		 * into our address space.
+		 */
 		size = SIZE_IN_HEADER;
 
-		status = acpi_tb_map_acpi_table (physical_address, &size, &full_table);
+		status = acpi_tb_map_acpi_table (address->pointer.physical, &size, &full_table);
 		if (ACPI_FAILURE (status)) {
 			return_ACPI_STATUS (status);
 		}
@@ -187,6 +184,11 @@
 		/* Save allocation type */
 
 		allocation = ACPI_MEM_MAPPED;
+		break;
+
+
+	default:
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
 	/* Return values */
@@ -196,6 +198,12 @@
 	table_info->allocation  = allocation;
 	table_info->base_pointer = full_table;
 
+	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		"Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
+		full_table->signature,
+		ACPI_HIDWORD (address->pointer.physical),
+		ACPI_LODWORD (address->pointer.physical), full_table));
+
 	return_ACPI_STATUS (status);
 }
 
@@ -209,9 +217,15 @@
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Load and validate all tables other than the RSDT.  The RSDT must
+ * DESCRIPTION: Load and validate tables other than the RSDT.  The RSDT must
  *              already be loaded and validated.
  *
+ *              Get the minimum set of ACPI tables, namely:
+ *
+ *              1) FADT (via RSDT in loop below)
+ *              2) FACS (via FADT)
+ *              3) DSDT (via FADT)
+ *
  ******************************************************************************/
 
 acpi_status
@@ -222,6 +236,7 @@
 	acpi_status             status = AE_OK;
 	u32                     index;
 	acpi_table_desc         table_info;
+	ACPI_POINTER            address;
 
 
 	ACPI_FUNCTION_TRACE ("Tb_get_all_tables");
@@ -232,7 +247,9 @@
 	/*
 	 * Loop through all table pointers found in RSDT.
 	 * This will NOT include the FACS and DSDT - we must get
-	 * them after the loop
+	 * them after the loop.
+	 *
+	 * The ONLY table we are interested in getting here is the FADT.
 	 */
 	for (index = 0; index < number_of_tables; index++) {
 		/* Clear the Table_info each time */
@@ -241,18 +258,10 @@
 
 		/* Get the table via the XSDT */
 
-		status = acpi_tb_get_table ((ACPI_PHYSICAL_ADDRESS)
-				 ACPI_GET_ADDRESS (acpi_gbl_XSDT->table_offset_entry[index]),
-				 table_ptr, &table_info);
-
-		/* Ignore a table that failed verification */
-
-		if (status == AE_BAD_DATA) {
-			continue;
-		}
-
-		/* However, abort on serious errors */
+		address.pointer_type  = acpi_gbl_table_flags;
+		address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_XSDT->table_offset_entry[index]);
 
+		status = acpi_tb_get_table (&address, &table_info);
 		if (ACPI_FAILURE (status)) {
 			return_ACPI_STATUS (status);
 		}
@@ -267,6 +276,7 @@
 			 * determine if there are enough tables to continue.
 			 */
 			acpi_tb_uninstall_table (&table_info);
+			status = AE_OK;
 		}
 	}
 
@@ -276,24 +286,20 @@
 	 */
 	status = acpi_tb_convert_table_fadt ();
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n"));
 		return_ACPI_STATUS (status);
 	}
 
 	/*
-	 * Get the minimum set of ACPI tables, namely:
-	 *
-	 * 1) FADT (via RSDT in loop above)
-	 * 2) FACS
-	 * 3) DSDT
-	 *
-	 */
-
-	/*
 	 * Get the FACS (must have the FADT first, from loop above)
 	 * Acpi_tb_get_table_facs will fail if FADT pointer is not valid
 	 */
-	status = acpi_tb_get_table_facs (table_ptr, &table_info);
+	address.pointer_type  = acpi_gbl_table_flags;
+	address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xfirmware_ctrl);
+
+	status = acpi_tb_get_table (&address, &table_info);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not get the FACS\n"));
 		return_ACPI_STATUS (status);
 	}
 
@@ -301,6 +307,7 @@
 
 	status = acpi_tb_install_table (table_ptr, &table_info);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not install the FACS\n"));
 		return_ACPI_STATUS (status);
 	}
 
@@ -310,15 +317,19 @@
 	 */
 	status = acpi_tb_build_common_facs (&table_info);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not convert FACS to common internal format\n"));
 		return_ACPI_STATUS (status);
 	}
 
 	/*
 	 * Get the DSDT (We know that the FADT is valid now)
 	 */
-	status = acpi_tb_get_table ((ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xdsdt),
-			  table_ptr, &table_info);
+	address.pointer_type  = acpi_gbl_table_flags;
+	address.pointer.value = ACPI_GET_ADDRESS (acpi_gbl_FADT->Xdsdt);
+
+	status = acpi_tb_get_table (&address, &table_info);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not get the DSDT\n"));
 		return_ACPI_STATUS (status);
 	}
 
@@ -326,20 +337,16 @@
 
 	status = acpi_tb_install_table (table_ptr, &table_info);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_ERROR (("Could not install the DSDT\n"));
 		return_ACPI_STATUS (status);
 	}
 
-	/* Dump the DSDT Header */
-
-	ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Hex dump of DSDT Header:\n"));
-	ACPI_DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, sizeof (acpi_table_header));
-
 	/* Dump the entire DSDT */
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_TABLES,
-		"Hex dump of DSDT (After header), size %d (%x)\n",
+		"Hex dump of entire DSDT, size %d (0x%X)\n",
 		acpi_gbl_DSDT->length, acpi_gbl_DSDT->length));
-	ACPI_DUMP_BUFFER ((u8 *) (acpi_gbl_DSDT + 1), acpi_gbl_DSDT->length);
+	ACPI_DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, acpi_gbl_DSDT->length);
 
 	/* Always delete the RSDP mapping, we are done with it */
 
@@ -362,7 +369,7 @@
 
 acpi_status
 acpi_tb_verify_rsdp (
-	ACPI_PHYSICAL_ADDRESS   rsdp_physical_address)
+	ACPI_POINTER            *address)
 {
 	acpi_table_desc         table_info;
 	acpi_status             status;
@@ -372,13 +379,25 @@
 	ACPI_FUNCTION_TRACE ("Tb_verify_rsdp");
 
 
-	/*
-	 * Obtain access to the RSDP structure
-	 */
-	status = acpi_os_map_memory (rsdp_physical_address, sizeof (RSDP_DESCRIPTOR),
-			  (void **) &rsdp);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
+	switch (address->pointer_type) {
+	case ACPI_LOGICAL_POINTER:
+
+		rsdp = address->pointer.logical;
+		break;
+
+	case ACPI_PHYSICAL_POINTER:
+		/*
+		 * Obtain access to the RSDP structure
+		 */
+		status = acpi_os_map_memory (address->pointer.physical, sizeof (RSDP_DESCRIPTOR),
+				  (void **) &rsdp);
+		if (ACPI_FAILURE (status)) {
+			return_ACPI_STATUS (status);
+		}
+		break;
+
+	default:
+		return_ACPI_STATUS (AE_BAD_PARAMETER);
 	}
 
 	/*
@@ -407,7 +426,6 @@
 		}
 	}
 
-
 	/* The RSDP supplied is OK */
 
 	table_info.pointer     = (acpi_table_header *) rsdp;
@@ -431,7 +449,9 @@
 	/* Error exit */
 cleanup:
 
-	acpi_os_unmap_memory (rsdp, sizeof (RSDP_DESCRIPTOR));
+	if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
+		acpi_os_unmap_memory (rsdp, sizeof (RSDP_DESCRIPTOR));
+	}
 	return_ACPI_STATUS (status);
 }
 
@@ -449,28 +469,26 @@
  *
  ******************************************************************************/
 
-ACPI_PHYSICAL_ADDRESS
-acpi_tb_get_rsdt_address (void)
+void
+acpi_tb_get_rsdt_address (
+	ACPI_POINTER            *out_address)
 {
-	ACPI_PHYSICAL_ADDRESS   physical_address;
-
 
 	ACPI_FUNCTION_ENTRY ();
 
 
+	out_address->pointer_type = acpi_gbl_table_flags;
+
 	/*
 	 * For RSDP revision 0 or 1, we use the RSDT.
 	 * For RSDP revision 2 (and above), we use the XSDT
 	 */
 	if (acpi_gbl_RSDP->revision < 2) {
-		physical_address = (ACPI_PHYSICAL_ADDRESS) acpi_gbl_RSDP->rsdt_physical_address;
+		out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address;
 	}
 	else {
-		physical_address = (ACPI_PHYSICAL_ADDRESS)
-				   ACPI_GET_ADDRESS (acpi_gbl_RSDP->xsdt_physical_address);
+		out_address->pointer.value = ACPI_GET_ADDRESS (acpi_gbl_RSDP->xsdt_physical_address);
 	}
-
-	return (physical_address);
 }
 
 
@@ -543,25 +561,51 @@
 
 acpi_status
 acpi_tb_get_table_pointer (
-	ACPI_PHYSICAL_ADDRESS   physical_address,
+	ACPI_POINTER            *address,
 	u32                     flags,
 	u32                     *size,
 	acpi_table_header       **table_ptr)
 {
-	acpi_status             status;
+	acpi_status             status = AE_OK;
 
 
 	ACPI_FUNCTION_ENTRY ();
 
 
+	/*
+	 * What mode is the processor in? (Virtual or Physical addressing)
+	 */
 	if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-		*size = SIZE_IN_HEADER;
-		status = acpi_tb_map_acpi_table (physical_address, size, table_ptr);
+		/* Incoming pointer can be either logical or physical */
+
+		switch (address->pointer_type) {
+		case ACPI_PHYSICAL_POINTER:
+
+			*size = SIZE_IN_HEADER;
+			status = acpi_tb_map_acpi_table (address->pointer.physical, size, table_ptr);
+			break;
+
+		case ACPI_LOGICAL_POINTER:
+
+			*table_ptr = address->pointer.logical;
+			*size = 0;
+			break;
+		}
 	}
 	else {
-		*size = 0;
-		*table_ptr = ACPI_PHYSADDR_TO_PTR (physical_address);
-		status = AE_OK;
+		/* In Physical addressing mode, all pointers must be physical */
+
+		switch (address->pointer_type) {
+		case ACPI_PHYSICAL_POINTER:
+			*size = 0;
+			*table_ptr = address->pointer.logical;
+			break;
+
+		case ACPI_LOGICAL_POINTER:
+
+			status = AE_BAD_PARAMETER;
+			break;
+		}
 	}
 
 	return (status);
@@ -586,7 +630,7 @@
 {
 	acpi_table_desc         table_info;
 	acpi_status             status;
-	ACPI_PHYSICAL_ADDRESS   physical_address;
+	ACPI_POINTER            address;
 
 
 	ACPI_FUNCTION_TRACE ("Tb_get_table_rsdt");
@@ -601,11 +645,11 @@
 		ACPI_HIDWORD (acpi_gbl_RSDP->rsdt_physical_address),
 		ACPI_LODWORD (acpi_gbl_RSDP->rsdt_physical_address)));
 
-	physical_address = acpi_tb_get_rsdt_address ();
 
 	/* Get the RSDT/XSDT */
 
-	status = acpi_tb_get_table (physical_address, NULL, &table_info);
+	acpi_tb_get_rsdt_address (&address);
+	status = acpi_tb_get_table (&address, &table_info);
 	if (ACPI_FAILURE (status)) {
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT, %s\n",
 			acpi_format_exception (status)));
@@ -646,81 +690,3 @@
 }
 
 
-/******************************************************************************
- *
- * FUNCTION:    Acpi_tb_get_table_facs
- *
- * PARAMETERS:  *Buffer_ptr             - If Buffer_ptr is valid, read data from
- *                                        buffer rather than searching memory
- *              *Table_info             - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Returns a pointer to the FACS as defined in FADT.  This
- *              function assumes the global variable FADT has been
- *              correctly initialized.  The value of FADT->Firmware_ctrl
- *              into a far pointer which is returned.
- *
- *****************************************************************************/
-
-acpi_status
-acpi_tb_get_table_facs (
-	acpi_table_header       *buffer_ptr,
-	acpi_table_desc         *table_info)
-{
-	acpi_table_header       *table_ptr = NULL;
-	u32                     size;
-	u8                      allocation;
-	acpi_status             status = AE_OK;
-
-
-	ACPI_FUNCTION_TRACE ("Tb_get_table_facs");
-
-
-	/* Must have a valid FADT pointer */
-
-	if (!acpi_gbl_FADT) {
-		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
-	}
-
-	size = sizeof (FACS_DESCRIPTOR);
-	if (buffer_ptr) {
-		/*
-		 * Getting table from a file -- allocate a buffer and
-		 * read the table.
-		 */
-		table_ptr = ACPI_MEM_ALLOCATE (size);
-		if(!table_ptr) {
-			return_ACPI_STATUS (AE_NO_MEMORY);
-		}
-
-		ACPI_MEMCPY (table_ptr, buffer_ptr, size);
-
-		/* Save allocation type */
-
-		allocation = ACPI_MEM_ALLOCATED;
-	}
-	else {
-		/* Just map the physical memory to our address space */
-
-		status = acpi_tb_map_acpi_table ((ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xfirmware_ctrl),
-				   &size, &table_ptr);
-		if (ACPI_FAILURE (status)) {
-			return_ACPI_STATUS (status);
-		}
-
-		/* Save allocation type */
-
-		allocation = ACPI_MEM_MAPPED;
-	}
-
-	/* Return values */
-
-	table_info->pointer     = table_ptr;
-	table_info->length      = size;
-	table_info->allocation  = allocation;
-	table_info->base_pointer = table_ptr;
-
-	return_ACPI_STATUS (status);
-}
-
diff -urN linux-2.5.8-pre2/drivers/acpi/tables/tbinstal.c linux-2.5.8-pre3/drivers/acpi/tables/tbinstal.c
--- linux-2.5.8-pre2/drivers/acpi/tables/tbinstal.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/acpi/tables/tbinstal.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbinstal - ACPI table installation and removal
- *              $Revision: 55 $
+ *              $Revision: 57 $
  *
  *****************************************************************************/
 
@@ -177,28 +177,35 @@
 	 * We only "recognize" a limited number of ACPI tables -- namely, the
 	 * ones that are used by the subsystem (DSDT, FADT, etc.)
 	 *
-	 * An AE_NOT_FOUND means that the table was not recognized.
+	 * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized.
 	 * This can be any one of many valid ACPI tables, it just isn't one of
 	 * the tables that is consumed by the core subsystem
 	 */
 	status = acpi_tb_match_signature (table_header->signature, table_info);
-	if (ACPI_SUCCESS (status)) {
-		/* Return the table type and length via the info struct */
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
 
-		table_info->length  = table_header->length;
+	status = acpi_tb_validate_table_header (table_header);
+	if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
 
-		/*
-		 * Validate checksum for _most_ tables,
-		 * even the ones whose signature we don't recognize
-		 */
-		if (table_info->type != ACPI_TABLE_FACS) {
-			status = acpi_tb_verify_table_checksum (table_header);
-			if (ACPI_FAILURE (status) &&
-				(!ACPI_CHECKSUM_ABORT)) {
-				/* Ignore the error if configuration says so */
+	/* Return the table type and length via the info struct */
 
-				status = AE_OK;
-			}
+	table_info->length  = table_header->length;
+
+	/*
+	 * Validate checksum for _most_ tables,
+	 * even the ones whose signature we don't recognize
+	 */
+	if (table_info->type != ACPI_TABLE_FACS) {
+		status = acpi_tb_verify_table_checksum (table_header);
+		if (ACPI_FAILURE (status) &&
+			(!ACPI_CHECKSUM_ABORT)) {
+			/* Ignore the error if configuration says so */
+
+			status = AE_OK;
 		}
 	}
 
@@ -372,10 +379,6 @@
 		return;
 	}
 
-	/* Free the table */
-
-	acpi_tb_free_acpi_tables_of_type (&acpi_gbl_acpi_tables[type]);
-
 	/* Clear the appropriate "typed" global table pointer */
 
 	switch (type) {
@@ -405,6 +408,10 @@
 		break;
 	}
 
+	/* Free the table */
+
+	acpi_tb_free_acpi_tables_of_type (&acpi_gbl_acpi_tables[type]);
+
 	(void) acpi_ut_release_mutex (ACPI_MTX_TABLES);
 	return_VOID;
 }
diff -urN linux-2.5.8-pre2/drivers/acpi/tables/tbutils.c linux-2.5.8-pre3/drivers/acpi/tables/tbutils.c
--- linux-2.5.8-pre2/drivers/acpi/tables/tbutils.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/acpi/tables/tbutils.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbutils - Table manipulation utilities
- *              $Revision: 49 $
+ *              $Revision: 51 $
  *
  *****************************************************************************/
 
@@ -71,7 +71,6 @@
 		} while (list_head != &acpi_gbl_acpi_tables[i]);
 	}
 
-
 	ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Table_id=%X does not exist\n", table_id));
 	return (AE_BAD_PARAMETER);
 }
@@ -115,7 +114,6 @@
 		return (AE_BAD_ADDRESS);
 	}
 
-
 	/* Ensure that the signature is 4 ASCII characters */
 
 	ACPI_MOVE_UNALIGNED32_TO_32 (&signature, &table_header->signature);
@@ -124,12 +122,11 @@
 			"Table signature at %p [%p] has invalid characters\n",
 			table_header, &signature));
 
-		ACPI_REPORT_WARNING (("Invalid table signature %4.4s found\n", (char *) &signature));
+		ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n", (char *) &signature));
 		ACPI_DUMP_BUFFER (table_header, sizeof (acpi_table_header));
 		return (AE_BAD_SIGNATURE);
 	}
 
-
 	/* Validate the table length */
 
 	if (table_header->length < sizeof (acpi_table_header)) {
@@ -208,10 +205,10 @@
 		}
 	}
 
-
 	/* Map the physical memory for the correct length */
 
-	status = acpi_os_map_memory (physical_address, table_size, (void **) &table);
+	status = acpi_os_map_memory (physical_address, table_size,
+			  (void **) &table);
 	if (ACPI_FAILURE (status)) {
 		return (status);
 	}
@@ -222,7 +219,6 @@
 
 	*size = table_size;
 	*logical_address = table;
-
 	return (status);
 }
 
@@ -263,8 +259,6 @@
 
 		status = AE_BAD_CHECKSUM;
 	}
-
-
 	return_ACPI_STATUS (status);
 }
 
@@ -301,7 +295,6 @@
 			sum = (u8) (sum + *rover);
 		}
 	}
-
 	return (sum);
 }
 
diff -urN linux-2.5.8-pre2/drivers/acpi/tables/tbxface.c linux-2.5.8-pre3/drivers/acpi/tables/tbxface.c
--- linux-2.5.8-pre2/drivers/acpi/tables/tbxface.c	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/drivers/acpi/tables/tbxface.c	Tue Apr  9 18:35:19 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: tbxface - Public interfaces to the ACPI subsystem
  *                         ACPI table oriented interfaces
- *              $Revision: 51 $
+ *              $Revision: 52 $
  *
  *****************************************************************************/
 
@@ -51,7 +51,7 @@
 acpi_status
 acpi_load_tables (void)
 {
-	ACPI_PHYSICAL_ADDRESS   rsdp_physical_address;
+	ACPI_POINTER            rsdp_address;
 	acpi_status             status;
 	u32                     number_of_tables = 0;
 
@@ -62,7 +62,7 @@
 	/* Get the RSDP */
 
 	status = acpi_os_get_root_pointer (ACPI_LOGICAL_ADDRESSING,
-			  &rsdp_physical_address);
+			  &rsdp_address);
 	if (ACPI_FAILURE (status)) {
 		ACPI_REPORT_ERROR (("Acpi_load_tables: Could not get RSDP, %s\n",
 				  acpi_format_exception (status)));
@@ -71,7 +71,9 @@
 
 	/* Map and validate the RSDP */
 
-	status = acpi_tb_verify_rsdp (rsdp_physical_address);
+	acpi_gbl_table_flags = rsdp_address.pointer_type;
+
+	status = acpi_tb_verify_rsdp (&rsdp_address);
 	if (ACPI_FAILURE (status)) {
 		ACPI_REPORT_ERROR (("Acpi_load_tables: RSDP Failed validation: %s\n",
 				  acpi_format_exception (status)));
@@ -141,6 +143,7 @@
 {
 	acpi_status             status;
 	acpi_table_desc         table_info;
+	ACPI_POINTER            address;
 
 
 	ACPI_FUNCTION_TRACE ("Acpi_load_table");
@@ -152,7 +155,10 @@
 
 	/* Copy the table to a local buffer */
 
-	status = acpi_tb_get_table (0, table_ptr, &table_info);
+	address.pointer_type    = ACPI_LOGICAL_POINTER;
+	address.pointer.logical = table_ptr;
+
+	status = acpi_tb_get_table (&address, &table_info);
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
diff -urN linux-2.5.8-pre2/drivers/acpi/tables/tbxfroot.c linux-2.5.8-pre3/drivers/acpi/tables/tbxfroot.c
--- linux-2.5.8-pre2/drivers/acpi/tables/tbxfroot.c	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/drivers/acpi/tables/tbxfroot.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbxfroot - Find the root ACPI table (RSDT)
- *              $Revision: 58 $
+ *              $Revision: 61 $
  *
  *****************************************************************************/
 
@@ -118,7 +118,8 @@
 	u32                     flags,
 	acpi_table_header       **table_pointer)
 {
-	ACPI_PHYSICAL_ADDRESS   physical_address;
+	ACPI_POINTER            rsdp_address;
+	ACPI_POINTER            address;
 	acpi_table_header       *rsdt_ptr = NULL;
 	acpi_table_header       *table_ptr;
 	acpi_status             status;
@@ -149,7 +150,7 @@
 	if (!acpi_gbl_RSDP) {
 		/* Get the RSDP */
 
-		status = acpi_os_get_root_pointer (flags, &physical_address);
+		status = acpi_os_get_root_pointer (flags, &rsdp_address);
 		if (ACPI_FAILURE (status)) {
 			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP  not found\n"));
 			return_ACPI_STATUS (AE_NO_ACPI_TABLES);
@@ -158,14 +159,14 @@
 		/* Map and validate the RSDP */
 
 		if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-			status = acpi_os_map_memory (physical_address, sizeof (RSDP_DESCRIPTOR),
+			status = acpi_os_map_memory (rsdp_address.pointer.physical, sizeof (RSDP_DESCRIPTOR),
 					  (void **) &acpi_gbl_RSDP);
 			if (ACPI_FAILURE (status)) {
 				return_ACPI_STATUS (status);
 			}
 		}
 		else {
-			acpi_gbl_RSDP = ACPI_PHYSADDR_TO_PTR (physical_address);
+			acpi_gbl_RSDP = rsdp_address.pointer.logical;
 		}
 
 		/*
@@ -194,8 +195,9 @@
 
 	/* Get the RSDT and validate it */
 
-	physical_address = acpi_tb_get_rsdt_address ();
-	status = acpi_tb_get_table_pointer (physical_address, flags, &rsdt_size, &rsdt_ptr);
+	acpi_tb_get_rsdt_address (&address);
+
+	status = acpi_tb_get_table_pointer (&address, flags, &rsdt_size, &rsdt_ptr);
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
@@ -217,18 +219,18 @@
 	for (i = 0, j = 0; i < table_count; i++) {
 		/* Get the next table pointer */
 
+		address.pointer_type = acpi_gbl_table_flags;
 		if (acpi_gbl_RSDP->revision < 2) {
-			physical_address = (ACPI_PHYSICAL_ADDRESS)
-				((RSDT_DESCRIPTOR *) rsdt_ptr)->table_offset_entry[i];
+			address.pointer.value = ((RSDT_DESCRIPTOR *) rsdt_ptr)->table_offset_entry[i];
 		}
 		else {
-			physical_address = (ACPI_PHYSICAL_ADDRESS)
-				ACPI_GET_ADDRESS (((xsdt_descriptor *) rsdt_ptr)->table_offset_entry[i]);
+			address.pointer.value = ACPI_GET_ADDRESS (
+				((xsdt_descriptor *) rsdt_ptr)->table_offset_entry[i]);
 		}
 
 		/* Get addressibility if necessary */
 
-		status = acpi_tb_get_table_pointer (physical_address, flags, &table_size, &table_ptr);
+		status = acpi_tb_get_table_pointer (&address, flags, &table_size, &table_ptr);
 		if (ACPI_FAILURE (status)) {
 			goto cleanup;
 		}
@@ -276,8 +278,8 @@
  *
  * FUNCTION:    Acpi_find_root_pointer
  *
- * PARAMETERS:  **Rsdp_physical_address     - Where to place the RSDP address
- *              Flags                       - Logical/Physical addressing
+ * PARAMETERS:  **Rsdp_address          - Where to place the RSDP address
+ *              Flags                   - Logical/Physical addressing
  *
  * RETURN:      Status, Physical address of the RSDP
  *
@@ -288,7 +290,7 @@
 acpi_status
 acpi_find_root_pointer (
 	u32                     flags,
-	ACPI_PHYSICAL_ADDRESS   *rsdp_physical_address)
+	ACPI_POINTER            *rsdp_address)
 {
 	acpi_table_desc         table_info;
 	acpi_status             status;
@@ -305,7 +307,8 @@
 		return_ACPI_STATUS (AE_NO_ACPI_TABLES);
 	}
 
-	*rsdp_physical_address = table_info.physical_address;
+	rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER;
+	rsdp_address->pointer.physical = table_info.physical_address;
 	return_ACPI_STATUS (AE_OK);
 }
 
diff -urN linux-2.5.8-pre2/drivers/acpi/utilities/utcopy.c linux-2.5.8-pre3/drivers/acpi/utilities/utcopy.c
--- linux-2.5.8-pre2/drivers/acpi/utilities/utcopy.c	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/acpi/utilities/utcopy.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utcopy - Internal to external object translation utilities
- *              $Revision: 94 $
+ *              $Revision: 95 $
  *
  *****************************************************************************/
 
@@ -654,6 +654,9 @@
 	case ACPI_TYPE_BUFFER:
 
 		dest_desc->buffer.node = NULL;
+		dest_desc->common.flags = source_desc->common.flags;
+
+		/* Fall through to common string/buffer case */
 
 	case ACPI_TYPE_STRING:
 
@@ -744,6 +747,7 @@
 		}
 
 		target_object->package.count = source_object->package.count;
+		target_object->common.flags = source_object->common.flags;
 
 		/*
 		 * Pass the new package object back to the package walk routine
@@ -792,6 +796,7 @@
 
 
 	dest_obj->common.type   = source_obj->common.type;
+	dest_obj->common.flags  = source_obj->common.flags;
 	dest_obj->package.count = source_obj->package.count;
 
 
@@ -806,10 +811,6 @@
 		return_ACPI_STATUS (AE_NO_MEMORY);
 	}
 
-	/* Init */
-
-	dest_obj->package.next_element = dest_obj->package.elements;
-
 	/*
 	 * Copy the package element-by-element by walking the package "tree".
 	 * This handles nested packages of arbitrary depth.
diff -urN linux-2.5.8-pre2/drivers/acpi/utilities/utdebug.c linux-2.5.8-pre3/drivers/acpi/utilities/utdebug.c
--- linux-2.5.8-pre2/drivers/acpi/utilities/utdebug.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/acpi/utilities/utdebug.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utdebug - Debug print routines
- *              $Revision: 96 $
+ *              $Revision: 97 $
  *
  *****************************************************************************/
 
@@ -508,6 +508,11 @@
 		return;
 	}
 
+	if ((count < 4) || (count & 0x01)) {
+		display = DB_BYTE_DISPLAY;
+	}
+
+	acpi_os_printf ("\n_offset Value\n");
 
 	/*
 	 * Nasty little dump buffer routine!
diff -urN linux-2.5.8-pre2/drivers/acpi/utilities/utdelete.c linux-2.5.8-pre3/drivers/acpi/utilities/utdelete.c
--- linux-2.5.8-pre2/drivers/acpi/utilities/utdelete.c	Mon Mar 18 12:37:15 2002
+++ linux-2.5.8-pre3/drivers/acpi/utilities/utdelete.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: utdelete - object deletion and reference count utilities
- *              $Revision: 87 $
+ *              $Revision: 88 $
  *
  ******************************************************************************/
 
@@ -68,10 +68,9 @@
 	 * actual ACPI objects (for example, a raw buffer pointer).
 	 */
 	switch (object->common.type) {
-
 	case ACPI_TYPE_STRING:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** String %p, ptr %p\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** String %p, ptr %p\n",
 			object, object->string.pointer));
 
 		/* Free the actual string buffer */
@@ -84,7 +83,7 @@
 
 	case ACPI_TYPE_BUFFER:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Buffer %p, ptr %p\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** Buffer %p, ptr %p\n",
 			object, object->buffer.pointer));
 
 		/* Free the actual buffer */
@@ -95,7 +94,7 @@
 
 	case ACPI_TYPE_PACKAGE:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, " **** Package of count %X\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, " **** Package of count %X\n",
 			object->package.count));
 
 		/*
@@ -111,7 +110,7 @@
 
 	case ACPI_TYPE_MUTEX:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Mutex %p, Semaphore %p\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Mutex %p, Semaphore %p\n",
 			object, object->mutex.semaphore));
 
 		acpi_ex_unlink_mutex (object);
@@ -121,7 +120,7 @@
 
 	case ACPI_TYPE_EVENT:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Event %p, Semaphore %p\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Event %p, Semaphore %p\n",
 			object, object->event.semaphore));
 
 		acpi_os_delete_semaphore (object->event.semaphore);
@@ -131,7 +130,7 @@
 
 	case ACPI_TYPE_METHOD:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Method %p\n", object));
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object));
 
 		/* Delete the method semaphore if it exists */
 
@@ -144,7 +143,7 @@
 
 	case ACPI_TYPE_REGION:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Region %p\n", object));
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object));
 
 		second_desc = acpi_ns_get_secondary_object (object);
 		if (second_desc) {
@@ -168,7 +167,7 @@
 
 	case ACPI_TYPE_BUFFER_FIELD:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "***** Buffer Field %p\n", object));
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object));
 
 		second_desc = acpi_ns_get_secondary_object (object);
 		if (second_desc) {
@@ -185,14 +184,14 @@
 	/* Free any allocated memory (pointer within the object) found above */
 
 	if (obj_pointer) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting Object Subptr %p\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n",
 				obj_pointer));
 		ACPI_MEM_FREE (obj_pointer);
 	}
 
 	/* Now the object can be safely deleted */
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting Object %p [%s]\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n",
 			object, acpi_ut_get_type_name (object->common.type)));
 
 	acpi_ut_delete_object_desc (object);
@@ -232,7 +231,6 @@
 	/* Free the combined parameter pointer list and object array */
 
 	ACPI_MEM_FREE (obj_list);
-
 	return_ACPI_STATUS (AE_OK);
 }
 
@@ -261,11 +259,11 @@
 
 	ACPI_FUNCTION_NAME ("Ut_update_ref_count");
 
+
 	if (!object) {
 		return;
 	}
 
-
 	count = object->common.reference_count;
 	new_count = count;
 
@@ -279,7 +277,7 @@
 		new_count++;
 		object->common.reference_count = new_count;
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, [Incremented]\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Incremented]\n",
 			object, new_count));
 		break;
 
@@ -287,21 +285,20 @@
 	case REF_DECREMENT:
 
 		if (count < 1) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
 				object, new_count));
 
 			new_count = 0;
 		}
-
 		else {
 			new_count--;
 
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, [Decremented]\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Decremented]\n",
 				object, new_count));
 		}
 
 		if (object->common.type == ACPI_TYPE_METHOD) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Method Obj %p Refs=%X, [Decremented]\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Method Obj %p Refs=%X, [Decremented]\n",
 				object, new_count));
 		}
 
@@ -315,7 +312,7 @@
 
 	case REF_FORCE_DELETE:
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X, Force delete! (Set to 0)\n",
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, Force delete! (Set to 0)\n",
 			object, count));
 
 		new_count = 0;
@@ -330,7 +327,6 @@
 		break;
 	}
 
-
 	/*
 	 * Sanity check the reference count, for debug purposes only.
 	 * (A deleted object will have a huge reference count)
@@ -394,7 +390,7 @@
 	 * Make sure that this isn't a namespace handle
 	 */
 	if (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Object %p is NS handle\n", object));
+		ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p is NS handle\n", object));
 		return_ACPI_STATUS (AE_OK);
 	}
 
@@ -566,7 +562,6 @@
 	 * We have a valid ACPI internal object, now increment the reference count
 	 */
 	acpi_ut_update_object_reference (object, REF_INCREMENT);
-
 	return_VOID;
 }
 
@@ -607,7 +602,7 @@
 		return_VOID;
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Obj %p Refs=%X\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X\n",
 			object, object->common.reference_count));
 
 	/*
diff -urN linux-2.5.8-pre2/drivers/acpi/utilities/uteval.c linux-2.5.8-pre3/drivers/acpi/utilities/uteval.c
--- linux-2.5.8-pre2/drivers/acpi/utilities/uteval.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/acpi/utilities/uteval.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: uteval - Object evaluation
- *              $Revision: 37 $
+ *              $Revision: 38 $
  *
  *****************************************************************************/
 
@@ -68,7 +68,7 @@
 	status = acpi_ns_evaluate_relative (device_node, object_name, NULL, &obj_desc);
 	if (ACPI_FAILURE (status)) {
 		if (status == AE_NOT_FOUND) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s on %4.4s was not found\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s on %4.4s was not found\n",
 				object_name, (char *) &device_node->name));
 		}
 		else {
@@ -147,7 +147,7 @@
 			 METHOD_NAME__HID, NULL, &obj_desc);
 	if (ACPI_FAILURE (status)) {
 		if (status == AE_NOT_FOUND) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "_HID on %4.4s was not found\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_HID on %4.4s was not found\n",
 				(char *) &device_node->name));
 		}
 		else {
@@ -230,7 +230,7 @@
 			 METHOD_NAME__CID, NULL, &obj_desc);
 	if (ACPI_FAILURE (status)) {
 		if (status == AE_NOT_FOUND) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "_CID on %4.4s was not found\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_CID on %4.4s was not found\n",
 				(char *)&device_node->name));
 		}
 		else {
@@ -324,7 +324,7 @@
 			 METHOD_NAME__UID, NULL, &obj_desc);
 	if (ACPI_FAILURE (status)) {
 		if (status == AE_NOT_FOUND) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "_UID on %4.4s was not found\n",
+			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "_UID on %4.4s was not found\n",
 				(char *) &device_node->name));
 		}
 		else {
@@ -409,7 +409,7 @@
 	status = acpi_ns_evaluate_relative (device_node,
 			 METHOD_NAME__STA, NULL, &obj_desc);
 	if (AE_NOT_FOUND == status) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 			"_STA on %4.4s was not found, assuming present.\n",
 			(char *) &device_node->name));
 
diff -urN linux-2.5.8-pre2/drivers/acpi/utilities/utglobal.c linux-2.5.8-pre3/drivers/acpi/utilities/utglobal.c
--- linux-2.5.8-pre2/drivers/acpi/utilities/utglobal.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/acpi/utilities/utglobal.c	Tue Apr  9 18:35:19 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utglobal - Global variables for the ACPI subsystem
- *              $Revision: 153 $
+ *              $Revision: 155 $
  *
  *****************************************************************************/
 
@@ -56,51 +56,63 @@
 	acpi_status             sub_status;
 
 
-	sub_status = (status & ~AE_CODE_MASK);
+	ACPI_FUNCTION_NAME ("Format_exception");
+
 
+	sub_status = (status & ~AE_CODE_MASK);
 
 	switch (status & AE_CODE_MASK) {
 	case AE_CODE_ENVIRONMENTAL:
 
 		if (sub_status <= AE_CODE_ENV_MAX) {
 			exception = acpi_gbl_exception_names_env [sub_status];
+			break;
 		}
-		break;
+		goto unknown;
 
 	case AE_CODE_PROGRAMMER:
 
 		if (sub_status <= AE_CODE_PGM_MAX) {
 			exception = acpi_gbl_exception_names_pgm [sub_status -1];
+			break;
 		}
-		break;
+		goto unknown;
 
 	case AE_CODE_ACPI_TABLES:
 
 		if (sub_status <= AE_CODE_TBL_MAX) {
 			exception = acpi_gbl_exception_names_tbl [sub_status -1];
+			break;
 		}
-		break;
+		goto unknown;
 
 	case AE_CODE_AML:
 
 		if (sub_status <= AE_CODE_AML_MAX) {
 			exception = acpi_gbl_exception_names_aml [sub_status -1];
+			break;
 		}
-		break;
+		goto unknown;
 
 	case AE_CODE_CONTROL:
 
 		if (sub_status <= AE_CODE_CTRL_MAX) {
 			exception = acpi_gbl_exception_names_ctrl [sub_status -1];
+			break;
 		}
-		break;
+		goto unknown;
 
 	default:
-		break;
+		goto unknown;
 	}
 
 
 	return ((const char *) exception);
+
+unknown:
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown exception code: 0x%8.8X\n", status));
+	return ((const char *) exception);
 }
 
 
@@ -173,10 +185,10 @@
 	{"_SB_",    ACPI_TYPE_DEVICE},
 	{"_SI_",    INTERNAL_TYPE_DEF_ANY},
 	{"_TZ_",    INTERNAL_TYPE_DEF_ANY},
-	{"_REV",    ACPI_TYPE_INTEGER, "2"},
-	{"_OS_",    ACPI_TYPE_STRING, ACPI_OS_NAME},
-	{"_GL_",    ACPI_TYPE_MUTEX, "0"},
-	{NULL,      ACPI_TYPE_ANY}           /* Table terminator */
+	{"_REV",    ACPI_TYPE_INTEGER,          "2"},
+	{"_OS_",    ACPI_TYPE_STRING,           ACPI_OS_NAME},
+	{"_GL_",    ACPI_TYPE_MUTEX,            "0"},
+	{NULL,      ACPI_TYPE_ANY}              /* Table terminator */
 };
 
 
@@ -193,16 +205,16 @@
 	ACPI_NS_NORMAL,                     /* 01 Number           */
 	ACPI_NS_NORMAL,                     /* 02 String           */
 	ACPI_NS_NORMAL,                     /* 03 Buffer           */
-	ACPI_NS_LOCAL,                      /* 04 Package          */
+	ACPI_NS_NORMAL,                     /* 04 Package          */
 	ACPI_NS_NORMAL,                     /* 05 Field_unit       */
-	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 06 Device           */
-	ACPI_NS_LOCAL,                      /* 07 Acpi_event       */
-	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 08 Method           */
-	ACPI_NS_LOCAL,                      /* 09 Mutex            */
-	ACPI_NS_LOCAL,                      /* 10 Region           */
-	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 11 Power            */
-	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 12 Processor        */
-	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 13 Thermal          */
+	ACPI_NS_NEWSCOPE,                   /* 06 Device           */
+	ACPI_NS_NORMAL,                     /* 07 Event            */
+	ACPI_NS_NEWSCOPE,                   /* 08 Method           */
+	ACPI_NS_NORMAL,                     /* 09 Mutex            */
+	ACPI_NS_NORMAL,                     /* 10 Region           */
+	ACPI_NS_NEWSCOPE,                   /* 11 Power            */
+	ACPI_NS_NEWSCOPE,                   /* 12 Processor        */
+	ACPI_NS_NEWSCOPE,                   /* 13 Thermal          */
 	ACPI_NS_NORMAL,                     /* 14 Buffer_field     */
 	ACPI_NS_NORMAL,                     /* 15 Ddb_handle       */
 	ACPI_NS_NORMAL,                     /* 16 Debug Object     */
@@ -758,6 +770,7 @@
 
 	/* Miscellaneous variables */
 
+	acpi_gbl_table_flags                = ACPI_PHYSICAL_POINTER;
 	acpi_gbl_rsdp_original_location     = 0;
 	acpi_gbl_cm_single_step             = FALSE;
 	acpi_gbl_db_terminate_threads       = FALSE;
@@ -779,7 +792,7 @@
 
 	acpi_gbl_root_node                  = NULL;
 
-	acpi_gbl_root_node_struct.name      = ACPI_ROOT_NAME;
+	acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
 	acpi_gbl_root_node_struct.descriptor = ACPI_DESC_TYPE_NAMED;
 	acpi_gbl_root_node_struct.type      = ACPI_TYPE_ANY;
 	acpi_gbl_root_node_struct.child     = NULL;
diff -urN linux-2.5.8-pre2/drivers/block/blkpg.c linux-2.5.8-pre3/drivers/block/blkpg.c
--- linux-2.5.8-pre2/drivers/block/blkpg.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/block/blkpg.c	Tue Apr  9 18:35:19 2002
@@ -113,6 +113,7 @@
 	g->part[minor].nr_sects = plength;
 	if (g->sizes)
 		g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9));
+	devfs_register_partitions (g, first_minor, 0);
 	return 0;
 }
 
@@ -172,6 +173,7 @@
 	g->part[minor].nr_sects = 0;
 	if (g->sizes)
 		g->sizes[minor] = 0;
+	devfs_register_partitions (g, first_minor, 0);
 	bd_release(bdevp);
 	bdput(bdevp);
 
@@ -213,7 +215,6 @@
 int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
 {
 	request_queue_t *q;
-	struct gendisk *g;
 	u64 ullval = 0;
 	int intval;
 	unsigned short usval;
@@ -252,20 +253,18 @@
 			return 0;
 
 		case BLKSSZGET:
-			/* get block device sector size as needed e.g. by fdisk */
+			/* get block device hardware sector size */
 			intval = get_hardsect_size(dev);
 			return put_user(intval, (int *) arg);
 
 		case BLKGETSIZE:
+			/* size in sectors, works up to 2 TB */
+			ullval = blkdev_size_in_bytes(dev);
+			return put_user((unsigned long)(ullval >> 9), (unsigned long *) arg);
 		case BLKGETSIZE64:
-			g = get_gendisk(dev);
-			if (g)
-				ullval = g->part[minor(dev)].nr_sects;
-
-			if (cmd == BLKGETSIZE)
-				return put_user((unsigned long)ullval, (unsigned long *)arg);
-			else
-				return put_user((u64)ullval << 9 , (u64 *)arg);
+			/* size in bytes */
+			ullval = blkdev_size_in_bytes(dev);
+			return put_user(ullval, (u64 *) arg);
 #if 0
 		case BLKRRPART: /* Re-read partition tables */
 			if (!capable(CAP_SYS_ADMIN)) 
diff -urN linux-2.5.8-pre2/drivers/block/ll_rw_blk.c linux-2.5.8-pre3/drivers/block/ll_rw_blk.c
--- linux-2.5.8-pre2/drivers/block/ll_rw_blk.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/block/ll_rw_blk.c	Tue Apr  9 18:35:19 2002
@@ -62,7 +62,7 @@
 
 /*
  * blk_size contains the size of all block-devices in units of 1024 byte
- * sectors:
+ * blocks:
  *
  * blk_size[MAJOR][MINOR]
  *
@@ -1274,32 +1274,27 @@
  * */
 void generic_make_request(struct bio *bio)
 {
-	int major = major(bio->bi_dev);
-	int minor = minor(bio->bi_dev);
 	request_queue_t *q;
-	sector_t minorsize = 0;
+	sector_t maxsector;
 	int ret, nr_sectors = bio_sectors(bio);
 
 	/* Test device or partition size, when known. */
-	if (blk_size[major])
-		minorsize = blk_size[major][minor];
-	if (minorsize) {
-		unsigned long maxsector = (minorsize << 1) + 1;
-		unsigned long sector = bio->bi_sector;
-
-		if (maxsector < nr_sectors || maxsector - nr_sectors < sector) {
-			if (blk_size[major][minor]) {
-				
-				/* This may well happen - the kernel calls
-				 * bread() without checking the size of the
-				 * device, e.g., when mounting a device. */
-				printk(KERN_INFO
-				       "attempt to access beyond end of device\n");
-				printk(KERN_INFO "%s: rw=%ld, want=%ld, limit=%Lu\n",
-				       kdevname(bio->bi_dev), bio->bi_rw,
-				       (sector + nr_sectors)>>1,
-				       (long long) blk_size[major][minor]);
-			}
+	maxsector = (blkdev_size_in_bytes(bio->bi_dev) >> 9);
+	if (maxsector) {
+		sector_t sector = bio->bi_sector;
+
+		if (maxsector < nr_sectors ||
+		    maxsector - nr_sectors < sector) {
+			/* This may well happen - the kernel calls
+			 * bread() without checking the size of the
+			 * device, e.g., when mounting a device. */
+			printk(KERN_INFO
+			       "attempt to access beyond end of device\n");
+			printk(KERN_INFO "%s: rw=%ld, want=%ld, limit=%Lu\n",
+			       kdevname(bio->bi_dev), bio->bi_rw,
+			       sector + nr_sectors,
+			       (long long) maxsector);
+
 			set_bit(BIO_EOF, &bio->bi_flags);
 			goto end_io;
 		}
diff -urN linux-2.5.8-pre2/drivers/block/loop.c linux-2.5.8-pre3/drivers/block/loop.c
--- linux-2.5.8-pre2/drivers/block/loop.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/block/loop.c	Tue Apr  9 18:35:19 2002
@@ -154,14 +154,20 @@
 
 #define MAX_DISK_SIZE 1024*1024*1024
 
-static unsigned long compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
+static unsigned long
+compute_loop_size(struct loop_device *lo,
+		  struct dentry * lo_dentry, kdev_t lodev)
 {
-	if (S_ISREG(lo_dentry->d_inode->i_mode))
-		return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
-	if (blk_size[major(lodev)])
-		return blk_size[major(lodev)][minor(lodev)] -
-                                (lo->lo_offset >> BLOCK_SIZE_BITS);
-	return MAX_DISK_SIZE;
+	loff_t size = 0;
+
+	if (S_ISREG(lo_dentry->d_inode->i_mode)) {
+		size = lo_dentry->d_inode->i_size;
+	} else {
+		size = blkdev_size_in_bytes(lodev);
+		if (size == 0)
+			return MAX_DISK_SIZE;
+	}
+	return (size - lo->lo_offset) >> BLOCK_SIZE_BITS;
 }
 
 static void figure_loop_size(struct loop_device *lo)
diff -urN linux-2.5.8-pre2/drivers/block/rd.c linux-2.5.8-pre3/drivers/block/rd.c
--- linux-2.5.8-pre2/drivers/block/rd.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/block/rd.c	Tue Apr  9 18:35:19 2002
@@ -300,19 +300,13 @@
 			}
 			up(&inode->i_bdev->bd_sem);
 			break;
-         	case BLKGETSIZE:   /* Return device size */
-			if (!arg)
-				break;
-			error = put_user(rd_kbsize[minor] << 1, (unsigned long *) arg);
-			break;
+         	case BLKGETSIZE:
          	case BLKGETSIZE64:
-			error = put_user((u64)rd_kbsize[minor]<<10, (u64*)arg);
-			break;
 		case BLKROSET:
 		case BLKROGET:
 		case BLKSSZGET:
 			error = blk_ioctl(inode->i_bdev, cmd, arg);
-	};
+	}
 out:
 	return error;
 }
@@ -419,11 +413,10 @@
 /* This is the registration and initialization section of the RAM disk driver */
 static int __init rd_init (void)
 {
-	int		i;
+	int i;
 
 	if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
-	    (rd_blocksize & (rd_blocksize-1)))
-	{
+	    (rd_blocksize & (rd_blocksize-1))) {
 		printk("RAMDISK: wrong blocksize %d, reverting to defaults\n",
 		       rd_blocksize);
 		rd_blocksize = BLOCK_SIZE;
@@ -450,7 +443,8 @@
 			       &rd_bd_op, NULL);
 
 	for (i = 0; i < NUM_RAMDISKS; i++)
-		register_disk(NULL, mk_kdev(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1);
+		register_disk(NULL, mk_kdev(MAJOR_NR,i), 1, &rd_bd_op,
+			      rd_size<<1);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* We ought to separate initrd operations here */
@@ -459,10 +453,10 @@
 			INITRD_MINOR, S_IFBLK | S_IRUSR, &rd_bd_op, NULL);
 #endif
 
-	blksize_size[MAJOR_NR] = rd_blocksizes;		/* Avoid set_blocksize() check */
-	blk_size[MAJOR_NR] = rd_kbsize;			/* Size of the RAM disk in kB  */
+	blksize_size[MAJOR_NR] = rd_blocksizes;	/* Avoid set_blocksize() check */
+	blk_size[MAJOR_NR] = rd_kbsize;		/* Size of the RAM disk in kB  */
 
-		/* rd_size is given in kB */
+	/* rd_size is given in kB */
 	printk("RAMDISK driver initialized: "
 	       "%d RAM disks of %dK size %d blocksize\n",
 	       NUM_RAMDISKS, rd_size, rd_blocksize);
diff -urN linux-2.5.8-pre2/drivers/char/i810_rng.c linux-2.5.8-pre3/drivers/char/i810_rng.c
--- linux-2.5.8-pre2/drivers/char/i810_rng.c	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/drivers/char/i810_rng.c	Tue Apr  9 18:35:19 2002
@@ -35,7 +35,7 @@
 /*
  * core module and version information
  */
-#define RNG_VERSION "0.9.6"
+#define RNG_VERSION "0.9.7"
 #define RNG_MODULE_NAME "i810_rng"
 #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
 #define PFX RNG_MODULE_NAME ": "
@@ -334,7 +334,8 @@
 static struct pci_device_id rng_pci_tbl[] __initdata = {
 	{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
diff -urN linux-2.5.8-pre2/drivers/char/mem.c linux-2.5.8-pre3/drivers/char/mem.c
--- linux-2.5.8-pre2/drivers/char/mem.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/char/mem.c	Tue Apr  9 18:35:19 2002
@@ -173,10 +173,10 @@
 	 * caching for the high addresses through the KEN pin, but
 	 * we maintain the tradition of paranoia in this code.
 	 */
- 	return !( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ||
-		  test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ||
-		  test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ||
-		  test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) )
+ 	return !( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) ||
+		  test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) ||
+		  test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) ||
+		  test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability) )
 	  && addr >= __pa(high_memory);
 #else
 	return addr >= __pa(high_memory);
diff -urN linux-2.5.8-pre2/drivers/char/random.c linux-2.5.8-pre3/drivers/char/random.c
--- linux-2.5.8-pre2/drivers/char/random.c	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/drivers/char/random.c	Tue Apr  9 18:35:19 2002
@@ -736,7 +736,7 @@
 	int		entropy = 0;
 
 #if defined (__i386__)
-	if ( test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability) ) {
+	if ( test_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability) ) {
 		__u32 high;
 		rdtsc(time, high);
 		num ^= high;
diff -urN linux-2.5.8-pre2/drivers/char/raw.c linux-2.5.8-pre3/drivers/char/raw.c
--- linux-2.5.8-pre2/drivers/char/raw.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/char/raw.c	Tue Apr  9 18:35:19 2002
@@ -289,11 +289,10 @@
 	dev = to_kdev_t(raw_devices[minor].binding->bd_dev);
 	sector_size = raw_devices[minor].sector_size;
 	sector_bits = raw_devices[minor].sector_bits;
-	sector_mask = sector_size- 1;
-	
-	if (blk_size[major(dev)])
-		limit = (((loff_t) blk_size[major(dev)][minor(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
-	else
+	sector_mask = sector_size - 1;
+
+	limit = blkdev_size_in_bytes(dev) >> sector_bits;
+	if (!limit)
 		limit = INT_MAX;
 	dprintk ("rw_raw_dev: dev %d:%d (+%d)\n",
 		 major(dev), minor(dev), limit);
diff -urN linux-2.5.8-pre2/drivers/ide/ali14xx.c linux-2.5.8-pre3/drivers/ide/ali14xx.c
--- linux-2.5.8-pre2/drivers/ide/ali14xx.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ali14xx.c	Tue Apr  9 18:35:19 2002
@@ -212,9 +212,8 @@
 	ide_hwifs[1].chipset = ide_ali14xx;
 	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
 	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].unit = 1;
+	ide_hwifs[0].unit = ATA_PRIMARY;
+	ide_hwifs[1].unit = ATA_SECONDARY;
 
 	/* initialize controller registers */
 	if (!initRegisters()) {
diff -urN linux-2.5.8-pre2/drivers/ide/cmd640.c linux-2.5.8-pre3/drivers/ide/cmd640.c
--- linux-2.5.8-pre2/drivers/ide/cmd640.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/cmd640.c	Tue Apr  9 18:35:19 2002
@@ -689,7 +689,7 @@
 /*
  * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
  */
-int __init ide_probe_for_cmd640x (void)
+int __init ide_probe_for_cmd640x(void)
 {
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 	int second_port_toggled = 0;
@@ -793,9 +793,7 @@
 		cmd_hwif0->serialized = 1;
 		cmd_hwif1->serialized = 1;
 		cmd_hwif1->chipset = ide_cmd640;
-		cmd_hwif0->mate = cmd_hwif1;
-		cmd_hwif1->mate = cmd_hwif0;
-		cmd_hwif1->unit = 1;
+		cmd_hwif1->unit = ATA_SECONDARY;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 		cmd_hwif1->tuneproc = &cmd640_tune_drive;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -811,8 +809,8 @@
 		ide_drive_t *drive = cmd_drives[index];
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 		if (drive->autotune || ((index > 1) && second_port_toggled)) {
-	 		/*
-	 		 * Reset timing to the slowest speed and turn off prefetch.
+			/*
+			 * Reset timing to the slowest speed and turn off prefetch.
 			 * This way, the drive identify code has a better chance.
 			 */
 			setup_counts    [index] = 4;	/* max possible */
diff -urN linux-2.5.8-pre2/drivers/ide/cs5530.c linux-2.5.8-pre3/drivers/ide/cs5530.c
--- linux-2.5.8-pre2/drivers/ide/cs5530.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/cs5530.c	Tue Apr  9 18:35:19 2002
@@ -346,8 +346,7 @@
  */
 void __init ide_init_cs5530(struct ata_channel *hwif)
 {
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
+	hwif->serialized = 1;
 	if (!hwif->dma_base) {
 		hwif->autodma = 0;
 	} else {
diff -urN linux-2.5.8-pre2/drivers/ide/dtc2278.c linux-2.5.8-pre3/drivers/ide/dtc2278.c
--- linux-2.5.8-pre2/drivers/ide/dtc2278.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/dtc2278.c	Tue Apr  9 18:35:19 2002
@@ -124,7 +124,6 @@
 	ide_hwifs[0].drives[1].no_unmask = 1;
 	ide_hwifs[1].drives[0].no_unmask = 1;
 	ide_hwifs[1].drives[1].no_unmask = 1;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].unit = 1;
+	ide_hwifs[0].unit = ATA_PRIMARY;
+	ide_hwifs[1].unit = ATA_SECONDARY;
 }
diff -urN linux-2.5.8-pre2/drivers/ide/hpt366.c linux-2.5.8-pre3/drivers/ide/hpt366.c
--- linux-2.5.8-pre2/drivers/ide/hpt366.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/hpt366.c	Tue Apr  9 18:35:19 2002
@@ -1125,13 +1125,13 @@
 
 	if (n_hpt_devs < HPT366_MAX_DEVS)
 		hpt_devs[n_hpt_devs++] = dev;
-	
+
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!hpt366_proc) {
 		hpt366_proc = 1;
 		hpt366_display_info = &hpt366_get_info;
 	}
-#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+#endif
 
 	return dev->irq;
 }
@@ -1146,7 +1146,7 @@
 	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
 		ata66, (ata66 & regmask) ? "33" : "66",
 		PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
+#endif
 	return ((ata66 & regmask) ? 0 : 1);
 }
 
diff -urN linux-2.5.8-pre2/drivers/ide/ht6560b.c linux-2.5.8-pre3/drivers/ide/ht6560b.c
--- linux-2.5.8-pre2/drivers/ide/ht6560b.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ht6560b.c	Tue Apr  9 18:35:19 2002
@@ -319,10 +319,9 @@
 			ide_hwifs[1].tuneproc = &tune_ht6560b;
 			ide_hwifs[0].serialized = 1;  /* is this needed? */
 			ide_hwifs[1].serialized = 1;  /* is this needed? */
-			ide_hwifs[0].mate = &ide_hwifs[1];
-			ide_hwifs[1].mate = &ide_hwifs[0];
-			ide_hwifs[1].unit = 1;
-			
+			ide_hwifs[0].unit = ATA_PRIMARY;
+			ide_hwifs[1].unit = ATA_SECONDARY;
+
 			/*
 			 * Setting default configurations for drives
 			 */
diff -urN linux-2.5.8-pre2/drivers/ide/ide-dma.c linux-2.5.8-pre3/drivers/ide/ide-dma.c
--- linux-2.5.8-pre2/drivers/ide/ide-dma.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ide-dma.c	Tue Apr  9 18:35:19 2002
@@ -421,7 +421,7 @@
 	return 0;
 }
 
-static int report_drive_dmaing (ide_drive_t *drive)
+int report_drive_dmaing (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
 
@@ -562,8 +562,8 @@
 	switch (func) {
 		case ide_dma_off:
 			printk("%s: DMA disabled\n", drive->name);
-			set_high = 0;
 		case ide_dma_off_quietly:
+			set_high = 0;
 			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
 		case ide_dma_on:
 			ide_toggle_bounce(drive, set_high);
diff -urN linux-2.5.8-pre2/drivers/ide/ide-pci.c linux-2.5.8-pre3/drivers/ide/ide-pci.c
--- linux-2.5.8-pre2/drivers/ide/ide-pci.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ide-pci.c	Tue Apr  9 18:35:19 2002
@@ -182,7 +182,7 @@
 	unsigned short		device;
 	unsigned int		(*init_chipset)(struct pci_dev *dev);
 	unsigned int		(*ata66_check)(struct ata_channel *hwif);
-	void			(*init_hwif)(struct ata_channel *hwif);
+	void			(*init_channel)(struct ata_channel *hwif);
 	void			(*dma_init)(struct ata_channel *hwif, unsigned long dmabase);
 	ide_pci_enablebit_t	enablebits[2];
 	unsigned int		bootable;
@@ -436,24 +436,21 @@
 	unsigned long	dma_base = 0;
 	struct pci_dev	*dev = hwif->pci_dev;
 
-	/*
-	 * If we are on the second channel, the dma base address will be one
-	 * entry away from the primary interface.
-	 */
-
-	if (hwif->mate && hwif->mate->dma_base)
-		dma_base = hwif->mate->dma_base - (hwif->unit ? 0 : 8);
-	else
-		dma_base = pci_resource_start(dev, 4);
-
+	dma_base = pci_resource_start(dev, 4);
 	if (!dma_base)
 		return 0;
 
-	if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
+	/* PDC20246, PDC20262, HPT343, & HPT366 */
+	if (extra) {
 		request_region(dma_base + 16, extra, name);
+		hwif->dma_extra = extra;
+	}
 
-	dma_base += hwif->unit ? 8 : 0;
-	hwif->dma_extra = extra;
+	/* If we are on the second channel, the dma base address will be one
+	 * entry away from the primary interface.
+	 */
+	if (hwif->unit == ATA_SECONDARY)
+		dma_base += 8;
 
 	if ((dev->vendor == PCI_VENDOR_ID_AL && dev->device == PCI_DEVICE_ID_AL_M5219) ||
 			(dev->vendor == PCI_VENDOR_ID_AMD && dev->device == PCI_DEVICE_ID_AMD_VIPER_7409) ||
@@ -463,8 +460,7 @@
 			printk(KERN_INFO "%s: simplex device: DMA forced\n", name);
 	} else {
 
-		/*
-		 * If the device claims "simplex" DMA, this means only one of
+		/* If the device claims "simplex" DMA, this means only one of
 		 * the two interfaces can be trusted with DMA at any point in
 		 * time.  So we should enable DMA only on one of the two
 		 * interfaces.
@@ -472,7 +468,7 @@
 
 		if ((inb(dma_base + 2) & 0x80)) {
 			if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
-					(hwif->mate && hwif->mate->dma_base)) {
+				hwif->unit == ATA_SECONDARY) {
 				printk("%s: simplex device:  DMA disabled\n", name);
 				dma_base = 0;
 			}
@@ -489,8 +485,9 @@
 		ide_pci_device_t *d,
 		int port,
 		u8 class_rev,
-		int pciirq, struct ata_channel **mate,
-		int autodma, unsigned short *pcicmd)
+		int pciirq,
+		int autodma,
+		unsigned short *pcicmd)
 {
 	unsigned long dma_base;
 
@@ -503,8 +500,13 @@
 	if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))))
 		return;
 
-	dma_base = get_dma_base(hwif, (!*mate && d->extra) ? d->extra : 0, dev->name);
-	if (dma_base && !(*pcicmd & PCI_COMMAND_MASTER)) {
+	dma_base = get_dma_base(hwif, ((port == ATA_PRIMARY) && d->extra) ? d->extra : 0, dev->name);
+	if (!dma_base) {
+		printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
+
+		return;
+	}
+	if (!(*pcicmd & PCI_COMMAND_MASTER)) {
 
 		/*
 		 * Set up BM-DMA capability (PnP BIOS should have done this already)
@@ -517,13 +519,10 @@
 			dma_base = 0;
 		}
 	}
-	if (dma_base) {
-		if (d->dma_init)
-			d->dma_init(hwif, dma_base);
-		else
-			ide_setup_dma(hwif, dma_base, 8);
-	} else
-		printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
+	if (d->dma_init)
+		d->dma_init(hwif, dma_base);
+	else
+		ide_setup_dma(hwif, dma_base, 8);
 }
 #endif
 
@@ -537,17 +536,16 @@
 		int port,
 		u8 class_rev,
 		int pciirq,
-		struct ata_channel **mate,
 		int autodma,
 		unsigned short *pcicmd)
 {
 	unsigned long base = 0;
 	unsigned long ctl = 0;
 	ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	struct ata_channel *hwif;
+	struct ata_channel *ch;
 
 	u8 tmp;
-	if (port == 1) {
+	if (port == ATA_SECONDARY) {
 
 		/* If this is a Promise FakeRaid controller, the 2nd controller
 		 * will be marked as disabled while it is actually there and
@@ -569,7 +567,7 @@
 
 	/* Nothing to be done for the second port.
 	 */
-	if (port == 1) {
+	if (port == ATA_SECONDARY) {
 		if ((d->flags & ATA_F_HPTHACK) && (class_rev < 0x03))
 			return 0;
 	}
@@ -599,57 +597,50 @@
 	if (!base)
 		base = port ? 0x170 : 0x1f0;
 
-	if ((hwif = lookup_hwif(base, d->bootable, dev->name)) == NULL)
+	if ((ch = lookup_hwif(base, d->bootable, dev->name)) == NULL)
 		return -ENOMEM;	/* no room in ide_hwifs[] */
 
-	if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-		ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
-		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-	}
-
-	hwif->chipset = ide_pci;
-	hwif->pci_dev = dev;
-	hwif->unit = port;
-	if (!hwif->irq)
-		hwif->irq = pciirq;
-
-	/* Setup the mate interface if we have two channels.
-	 */
-	if (*mate) {
-		hwif->mate = *mate;
-		(*mate)->mate = hwif;
-		if (d->flags & ATA_F_SER) {
-			hwif->serialized = 1;
-			(*mate)->serialized = 1;
-		}
-	}
+	if (ch->io_ports[IDE_DATA_OFFSET] != base) {
+		ide_init_hwif_ports(&ch->hw, base, (ctl | 2), NULL);
+		memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->io_ports));
+		ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET];
+	}
+
+	ch->chipset = ide_pci;
+	ch->pci_dev = dev;
+	ch->unit = port;
+	if (!ch->irq)
+		ch->irq = pciirq;
+
+	/* Serialize the interfaces if requested by configuration information.
+	 */
+	if (d->flags & ATA_F_SER)
+	    ch->serialized = 1;
 
 	/* Cross wired IRQ lines on UMC chips and no DMA transfers.*/
 	if (d->flags & ATA_F_FIXIRQ) {
-		hwif->irq = port ? 15 : 14;
+		ch->irq = port ? 15 : 14;
 		goto no_dma;
 	}
 	if (d->flags & ATA_F_NODMA)
 		goto no_dma;
 
 	/* Check whatever this interface is UDMA4 mode capable. */
-	if (hwif->udma_four) {
+	if (ch->udma_four) {
 		printk("%s: warning: ATA-66/100 forced bit set!\n", dev->name);
 	} else {
 		if (d->ata66_check)
-			hwif->udma_four = d->ata66_check(hwif);
+			ch->udma_four = d->ata66_check(ch);
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	setup_channel_dma(hwif, dev, d, port, class_rev, pciirq,  mate, autodma, pcicmd);
+	setup_channel_dma(ch, dev, d, port, class_rev, pciirq, autodma, pcicmd);
 #endif
 
 no_dma:
-	if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
-		d->init_hwif(hwif);
-
-	*mate = hwif;
+	/* Call chipset-specific routine for each enabled channel. */
+	if (d->init_channel)
+		d->init_channel(ch);
 
 	return 0;
 }
@@ -671,7 +662,6 @@
 	int pciirq = 0;
 	unsigned short pcicmd = 0;
 	unsigned short tried_config = 0;
-	struct ata_channel *mate = NULL;
 	unsigned int class_rev;
 
 #ifdef CONFIG_IDEDMA_AUTO
@@ -679,9 +669,9 @@
 		autodma = 1;
 #endif
 
-	if (d->init_hwif == IDE_NO_DRIVER) {
+	if (d->init_channel == IDE_NO_DRIVER) {
 		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", dev->name);
-		d->init_hwif = NULL;
+		d->init_channel = NULL;
 	}
 
 	if (pci_enable_device(dev)) {
@@ -779,8 +769,8 @@
 	/*
 	 * Set up IDE chanells. First the primary, then the secondary.
 	 */
-	setup_host_channel(dev, d, 0, class_rev, pciirq, &mate, autodma, &pcicmd);
-	setup_host_channel(dev, d, 1, class_rev, pciirq, &mate, autodma, &pcicmd);
+	setup_host_channel(dev, d, ATA_PRIMARY, class_rev, pciirq, autodma, &pcicmd);
+	setup_host_channel(dev, d, ATA_SECONDARY, class_rev, pciirq, autodma, &pcicmd);
 }
 
 static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
@@ -856,12 +846,6 @@
 			if (hpt363_shared_pin && hpt363_shared_irq) {
 				d->bootable = ON_BOARD;
 				printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", dev->name, pin1, pin2);
-#if 0
-				/* I forgot why I did this once, but it fixed something. */
-				pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
-				printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2);
-				pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
-#endif
 			}
 			break;
 		}
@@ -894,7 +878,7 @@
 	while (d->vendor && !(d->vendor == vendor && d->device == device))
 		++d;
 
-	if (d->init_hwif == ATA_PCI_IGNORE)
+	if (d->init_channel == ATA_PCI_IGNORE)
 		printk("%s: has been ignored by PCI bus scan\n", dev->name);
 	else if ((d->vendor == PCI_VENDOR_ID_OPTI && d->device == PCI_DEVICE_ID_OPTI_82C558) && !(PCI_FUNC(dev->devfn) & 1))
 		return;
diff -urN linux-2.5.8-pre2/drivers/ide/ide-pmac.c linux-2.5.8-pre3/drivers/ide/ide-pmac.c
--- linux-2.5.8-pre2/drivers/ide/ide-pmac.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ide-pmac.c	Tue Apr  9 18:35:19 2002
@@ -15,6 +15,16 @@
  * Some code taken from drivers/ide/ide-dma.c:
  *
  *  Copyright (c) 1995-1998  Mark Lord
+ *  
+ * TODO:
+ * 
+ *  - Find a way to duplicate less code with ide-dma and use the
+ *    dma fileds in the hwif structure instead of our own
+ *  - Fix check_disk_change() call
+ *  - Make module-able (includes setting ppc_md. hooks from within
+ *    this file and not from arch code, and handling module deps with
+ *    mediabay (by having both modules do dynamic lookup of each other
+ *    symbols or by storing hooks at arch level).
  *
  */
 #include <linux/config.h>
@@ -24,26 +34,30 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
+#include <linux/pci.h>
 
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
 #include <asm/ide.h>
 #include <asm/mediabay.h>
-#include <asm/feature.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
 #ifdef CONFIG_PMAC_PBOOK
 #include <linux/adb.h>
 #include <linux/pmu.h>
-#include <asm/irq.h>
 #endif
 #include "ata-timing.h"
 
 extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+extern spinlock_t ide_lock;
 
 #undef IDE_PMAC_DEBUG
 
-#define IDE_SYSCLK_NS		30
-#define IDE_SYSCLK_ULTRA_PS	0x1d4c /* (15 * 1000 / 2)*/
+#define DMA_WAIT_TIMEOUT	500
 
 struct pmac_ide_hwif {
 	ide_ioreg_t			regbase;
@@ -53,11 +67,20 @@
 	struct device_node*		node;
 	u32				timings[2];
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* Those fields are duplicating what is in hwif. We currently
+	 * can't use the hwif ones because of some assumptions that are
+	 * beeing done by the generic code about the kind of dma controller
+	 * and format of the dma table. This will have to be fixed though.
+	 */
 	volatile struct dbdma_regs*	dma_regs;
-	struct dbdma_cmd*		dma_table;
-#endif
+	struct dbdma_cmd*		dma_table_cpu;
+	dma_addr_t			dma_table_dma;
+	struct scatterlist*		sg_table;
+	int				sg_nents;
+	int				sg_dma_direction;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 	
-} pmac_ide[MAX_HWIFS];
+} pmac_ide[MAX_HWIFS] __pmacdata;
 
 static int pmac_ide_count;
 
@@ -65,36 +88,160 @@
 	controller_ohare,	/* OHare based */
 	controller_heathrow,	/* Heathrow/Paddington */
 	controller_kl_ata3,	/* KeyLargo ATA-3 */
-	controller_kl_ata4	/* KeyLargo ATA-4 */
+	controller_kl_ata4,	/* KeyLargo ATA-4 */
+	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
 };
 
+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG	0x200
+#define IDE_INTERRUPT		0x300
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
+#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ * 
+ * 3 Values can be programmed:
+ *  - Write data setup, which appears to match the cycle time. They
+ *    also call it DIOW setup.
+ *  - Ready to pause time (from spec)
+ *  - Address setup. That one is weird. I don't see where exactly
+ *    it fits in UDMA cycles, I got it's name from an obscure piece
+ *    of commented out code in Darwin. They leave it to 0, we do as
+ *    well, despite a comment that would lead to think it has a
+ *    min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads. I can't explain that, I tried it and it broke everything
+ * here.
+ */
+#define TR_66_UDMA_MASK			0xfff00000
+#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
+#define TR_66_UDMA_ADDRSETUP_SHIFT	29
+#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT	25
+#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT	21
+#define TR_66_MDMA_MASK			0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT	15
+#define TR_66_MDMA_ACCESS_MASK		0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT		10
+#define TR_66_PIO_MASK			0x000003ff
+#define TR_66_PIO_RECOVERY_MASK		0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT	5
+#define TR_66_PIO_ACCESS_MASK		0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT		0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ * 
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK			0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT	16
+#define TR_33_MDMA_ACCESS_MASK		0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT		11
+#define TR_33_MDMA_HALFTICK		0x00200000
+#define TR_33_PIO_MASK			0x000007ff
+#define TR_33_PIO_E			0x00000400
+#define TR_33_PIO_RECOVERY_MASK		0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT	5
+#define TR_33_PIO_ACCESS_MASK		0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT		0
+
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA			0x80000000
+#define IDE_INTR_DEVICE			0x40000000
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
 # define BAD_DMA_DRIVE		0
 # define GOOD_DMA_DRIVE		1
 
-typedef struct {
+/* Rounded Multiword DMA timings
+ * 
+ * I gave up finding a generic formula for all controller
+ * types and instead, built tables based on timing values
+ * used by Apple in Darwin's implementation.
+ */
+struct mdma_timings_t {
 	int	accessTime;
+	int	recoveryTime;
 	int	cycleTime;
-} pmac_ide_timing;
+};
 
-/* Multiword DMA timings */
-static pmac_ide_timing mdma_timings[] =
+struct mdma_timings_t mdma_timings_33[] __pmacdata =
 {
-    { 215,    480 },	/* Mode 0 */
-    {  80,    150 },	/*      1 */
-    {  70,    120 }	/*      2 */
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  75,  75, 150 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
 };
 
-/* Ultra DMA timings (for use when I know how to calculate them */
-static pmac_ide_timing udma_timings[] =
+struct mdma_timings_t mdma_timings_33k[] __pmacdata =
 {
-    {   0,    114 },	/* Mode 0 */
-    {   0,     75 },	/*      1 */
-    {   0,     55 },	/*      2 */
-    {   100,   45 },	/*      3 */
-    {   100,   25 }	/*      4 */
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 150, 150, 300 },
+    { 120, 120, 240 },
+    {  90, 120, 210 },
+    {  90,  90, 180 },
+    {  90,  60, 150 },
+    {  90,  30, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_66[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  90,  75, 165 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+/* Ultra DMA timings (rounded) */
+struct {
+	int	addrSetup; /* ??? */
+	int	rdy2pause;
+	int	wrDataSetup;
+} udma_timings[] __pmacdata =
+{
+    {   0, 180,  120 },	/* Mode 0 */
+    {   0, 150,  90 },	/*      1 */
+    {   0, 120,  60 },	/*      2 */
+    {   0, 90,   45 },	/*      3 */
+    {   0, 90,   30 }	/*      4 */
 };
 
 /* allow up to 256 DBDMA commands per xfer */
@@ -124,7 +271,7 @@
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
-static int
+static int __pmac
 pmac_ide_find(ide_drive_t *drive)
 {
 	struct ata_channel *hwif = drive->channel;
@@ -143,7 +290,8 @@
  * N.B. this can't be an initfunc, because the media-bay task can
  * call ide_[un]register at any time.
  */
-void pmac_ide_init_hwif_ports(hw_regs_t *hw,
+void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw,
 			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
 			      int *irq)
 {
@@ -174,7 +322,7 @@
 	ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
 	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
 	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
-	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) {
+	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
 		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 		if (!noautodma)
@@ -201,24 +349,33 @@
 /* Setup timings for the selected drive (master/slave). I still need to verify if this
  * is enough, I beleive selectproc will be called whenever an IDE command is started,
  * but... */
-static void
+static void __pmac
 pmac_ide_selectproc(ide_drive_t *drive)
 {
 	int i = pmac_ide_find(drive);
 	if (i < 0)
 		return;
-			
-	if (drive->select.all & 0x10)
-		out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]);
+
+	if (drive->select.b.unit & 0x01)
+		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+			pmac_ide[i].timings[1]);
 	else
-		out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]);
+		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+			pmac_ide[i].timings[0]);
+	(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
 }
 
-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_UDMA(t)	(((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS)
 
-static __inline__ int
+/* Note: We don't use the generic routine here because for some
+ * yet unexplained reasons, it cause some media-bay CD-ROMs to
+ * lockup the bus. Strangely, this new version of the code is
+ * almost identical to the generic one and works, I've not yet
+ * managed to figure out what bit is causing the lockup in the
+ * generic code, possibly a timing issue...
+ * 
+ * --BenH
+ */
+static int __pmac
 wait_for_ready(ide_drive_t *drive)
 {
 	/* Timeout bumped for some powerbooks */
@@ -244,57 +401,80 @@
 	return 0;
 }
 
-/* Note: We don't use the generic routine here because some of Apple's
- * controller seem to be very sensitive about how things are done.
- * We should probably set the NIEN bit, but that's an example of thing
- * that can cause the controller to hang under some circumstances when
- * done on the media-bay CD-ROM during boot. We do get occasional
- * spurrious interrupts because of that.
- * --BenH
- */
-static int
+static int __pmac
 pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
 {
-	unsigned long flags;
 	int result = 1;
-
-	save_flags(flags);
-	cli();
+	unsigned long flags;
+	struct ata_channel *hwif = HWIF(drive);
+	
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
 	udelay(1);
 	SELECT_DRIVE(drive->channel, drive);
 	SELECT_MASK(drive->channel, drive, 0);
 	udelay(1);
+	(void)GET_STAT(); /* Get rid of pending error state */
 	if(wait_for_ready(drive)) {
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
 		goto out;
 	}
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+	udelay(10);
+	OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
 	OUT_BYTE(command, IDE_NSECTOR_REG);
+	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
 	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
 	udelay(1);
+	__save_flags(flags);	/* local CPU only */
+	ide__sti();		/* local CPU only -- for jiffies */
 	result = wait_for_ready(drive);
+	__restore_flags(flags); /* local CPU only */
+	OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
 	if (result)
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
 out:
-	restore_flags(flags);
+	SELECT_MASK(HWIF(drive), drive, 0);
+	if (result == 0) {
+		drive->id->dma_ultra &= ~0xFF00;
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
+		switch(command) {
+			case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+			case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+			case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+			case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+			case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+			case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+			case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+			case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+			case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+			case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+			case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+			case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+			case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+			case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+			default: break;
+		}
+	}
+	enable_irq(hwif->irq);
 
 	return result;
 }
 
 /* Calculate PIO timings */
-static void
+static void __pmac
 pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
 {
 	struct ata_timing *t;
 	int i;
 	u32 *timings;
-	int accessTicks, recTicks;
+	unsigned accessTicks, recTicks;
+	unsigned accessTime, recTime;
 
 	i = pmac_ide_find(drive);
 	if (i < 0)
 		return;
 
-	if (pio = 255)
+	if (pio == 255)
 		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
 	else
 		pio = XFER_PIO_0 + min_t(byte, pio, 4);
@@ -302,27 +482,40 @@
 	t = ata_timing_data(pio);
 
 	accessTicks = SYSCLK_TICKS(t->active);
-	if (drive->select.all & 0x10)
-		timings = &pmac_ide[i].timings[1];
-	else
-		timings = &pmac_ide[i].timings[0];
-
-	if (pmac_ide[i].kind == controller_kl_ata4) {
-		/* The "ata-4" IDE controller of Core99 machines */
-		accessTicks = SYSCLK_TICKS_UDMA(t->active * 1000);
-		recTicks = SYSCLK_TICKS_UDMA(t->cycle * 1000) - accessTicks;
+	timings = &pmac_ide[i].timings[drive->select.b.unit & 0x01];
 
-		*timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5);
+	recTime = t->cycle - t->active - t->setup;
+	recTime = max(recTime, 150U);
+	accessTime = t->active;
+	accessTime = max(accessTime, 150U);
+	if (pmac_ide[i].kind == controller_kl_ata4 ||
+		pmac_ide[i].kind == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_66_PIO_MASK) |
+				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
 	} else {
-		/* The old "ata-3" IDE controller */
-		accessTicks = SYSCLK_TICKS(t->active);
-		if (accessTicks < 4)
-			accessTicks = 4;
-		recTicks = SYSCLK_TICKS(t->cycle) - accessTicks - 4;
-		if (recTicks < 1)
-			recTicks = 1;
-	
-		*timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);
+		/* 33Mhz cell */
+		int ebit = 0;
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 4U);
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 5U) - 4;
+		if (recTicks > 9) {
+			recTicks--; /* guess, but it's only for PIO0, so... */
+			ebit = 1;
+		}
+		*timings = ((*timings) & ~TR_33_PIO_MASK) |
+				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
+		if (ebit)
+			*timings |= TR_33_PIO_E;
 	}
 
 #ifdef IDE_PMAC_DEBUG
@@ -335,70 +528,134 @@
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-static int
-set_timings_udma(int intf, u32 *timings, byte speed)
+static int __pmac
+set_timings_udma(u32 *timings, byte speed)
 {
-	int cycleTime, accessTime;
-	int rdyToPauseTicks, cycleTicks;
-
-	if (pmac_ide[intf].kind != controller_kl_ata4)
-		return 1;
-		
-	cycleTime = udma_timings[speed & 0xf].cycleTime;
-	accessTime = udma_timings[speed & 0xf].accessTime;
+	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
 
-	rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
-	cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
-
-	*timings = ((*timings) & 0xe00fffff) |
-			((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
+	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
+	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
+
+	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
+			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
+			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
+			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
+			TR_66_UDMA_EN;
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
 
 	return 0;
 }
 
-static int
-set_timings_mdma(int intf, u32 *timings, byte speed)
+static int __pmac
+set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time)
 {
-	int cycleTime, accessTime;
-	int accessTicks, recTicks;
+	int cycleTime, accessTime, recTime;
+	unsigned accessTicks, recTicks;
+	struct mdma_timings_t* tm;
+	int i;
 
-	/* Calculate accesstime and cycle time */
-	cycleTime = mdma_timings[speed & 0xf].cycleTime;
-	accessTime = mdma_timings[speed & 0xf].accessTime;
-	if ((pmac_ide[intf].kind == controller_ohare) && (cycleTime < 150))
+	/* Get default cycle time for mode */
+	switch(speed & 0xf) {
+		case 0: cycleTime = 480; break;
+		case 1: cycleTime = 150; break;
+		case 2: cycleTime = 120; break;
+		default:
+			return -1;
+	}
+	/* Adjust for drive */
+	if (drive_cycle_time && drive_cycle_time > cycleTime)
+		cycleTime = drive_cycle_time;
+	/* OHare limits according to some old Apple sources */	
+	if ((intf_type == controller_ohare) && (cycleTime < 150))
 		cycleTime = 150;
+	/* Get the proper timing array for this controller */
+	switch(intf_type) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			tm = mdma_timings_66;
+			break;
+		case controller_kl_ata3:
+			tm = mdma_timings_33k;
+			break;
+		default:
+			tm = mdma_timings_33;
+			break;
+	}
+	/* Lookup matching access & recovery times */
+	i = -1;
+	for (;;) {
+		if (tm[i+1].cycleTime < cycleTime)
+			break;
+		i++;
+	}
+	if (i < 0)
+		return -1;
+	cycleTime = tm[i].cycleTime;
+	accessTime = tm[i].accessTime;
+	recTime = tm[i].recoveryTime;
 
-	/* For ata-4 controller */
-	if (pmac_ide[intf].kind == controller_kl_ata4) {
-		accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
-		recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
-		*timings = ((*timings) & 0xffe003ff) |
-			(accessTicks | (recTicks << 5)) << 10;
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
+		cycleTime, accessTime, recTime);
+#endif	
+	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 0x1U);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 0x3U);
+		/* Clear out mdma bits and disable udma */
+		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
+			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
+			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
+	} else if (intf_type == controller_kl_ata3) {
+		/* 33Mhz cell on KeyLargo */
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 1U);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
 	} else {
+		/* 33Mhz cell on others */
 		int halfTick = 0;
 		int origAccessTime = accessTime;
-		int origCycleTime = cycleTime;
+		int origRecTime = recTime;
 		
 		accessTicks = SYSCLK_TICKS(accessTime);
-		if (accessTicks < 1)
-			accessTicks = 1;
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
 		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1;
-		if (recTicks < 1)
-			recTicks = 1;
-		cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
-
-		/* KeyLargo ata-3 don't support the half-tick stuff */
-		if ((pmac_ide[intf].kind != controller_kl_ata3) &&
-			(accessTicks > 1) &&
-			((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
-			((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
-            			halfTick    = 1;
-				accessTicks--;
-		}
-		*timings = ((*timings) & 0x7FF) |
-			(accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 2U) - 1;
+		recTicks = min(recTicks, 0x1fU);
+		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
+		if ((accessTicks > 1) &&
+		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
+            		halfTick = 1;
+			accessTicks--;
+		}
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+		if (halfTick)
+			*timings |= TR_33_MDMA_HALFTICK;
 	}
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
 	return 0;
 }
 #endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
@@ -406,11 +663,11 @@
 /* You may notice we don't use this function on normal operation,
  * our, normal mdma function is supposed to be more precise
  */
-static int
+static int __pmac
 pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	int intf		= pmac_ide_find(drive);
-	int unit		= (drive->select.all & 0x10) ? 1:0;
+	int unit		= (drive->select.b.unit & 0x01);
 	int ret			= 0;
 	u32 *timings;
 
@@ -423,19 +680,25 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 		case XFER_UDMA_4:
 		case XFER_UDMA_3:
+			if (pmac_ide[intf].kind != controller_kl_ata4_80)
+				return 1;		
 		case XFER_UDMA_2:
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
-			ret = set_timings_udma(intf, timings, speed);
+			if (pmac_ide[intf].kind != controller_kl_ata4 &&
+				pmac_ide[intf].kind != controller_kl_ata4_80)
+				return 1;		
+			ret = set_timings_udma(timings, speed);
 			break;
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_MW_DMA_0:
+			ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0);
+			break;
 		case XFER_SW_DMA_2:
 		case XFER_SW_DMA_1:
 		case XFER_SW_DMA_0:
-			ret = set_timings_mdma(intf, timings, speed);
-			break;
+			return 1;
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 		case XFER_PIO_4:
 		case XFER_PIO_3:
@@ -460,13 +723,46 @@
 	return 0;
 }
 
-ide_ioreg_t
+static void __pmac
+sanitize_timings(int i)
+{
+	unsigned value;
+	
+	switch(pmac_ide[i].kind) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			value = 0x0008438c;
+			break;
+		case controller_kl_ata3:
+			value = 0x00084526;
+			break;
+		case controller_heathrow:
+		case controller_ohare:
+		default:
+			value = 0x00074526;
+			break;
+	}
+	pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value;
+}
+
+ide_ioreg_t __pmac
 pmac_ide_get_base(int index)
 {
 	return pmac_ide[index].regbase;
 }
 
-int
+int __pmac
+pmac_ide_check_base(ide_ioreg_t base)
+{
+	int ix;
+	
+ 	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return ix;
+	return -1;
+}
+
+int __pmac
 pmac_ide_get_irq(ide_ioreg_t base)
 {
 	int ix;
@@ -477,7 +773,7 @@
 	return 0;
 }
 
-static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
 
 kdev_t __init
 pmac_find_ide_boot(char *bootdevice, int n)
@@ -494,11 +790,11 @@
 		name = pmac_ide[i].node->full_name;
 		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
 			/* XXX should cope with the 2nd drive as well... */
-			return MKDEV(ide_majors[i], 0);
+			return mk_kdev(ide_majors[i], 0);
 		}
 	}
 
-	return 0;
+	return NODEV;
 }
 
 void __init
@@ -541,9 +837,12 @@
 
 	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
 		struct device_node *tp;
+		struct pmac_ide_hwif *pmif;
 		int *bidp;
 		int in_bay = 0;
-
+		u8 pbus, pid;
+		struct pci_dev *pdev = NULL;
+		
 		/*
 		 * If this node is not under a mac-io or dbdma node,
 		 * leave it to the generic PCI driver.
@@ -561,6 +860,15 @@
 			continue;
 		}
 
+		/* We need to find the pci_dev of the mac-io holding the
+		 * IDE interface
+		 */
+		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
+			pdev = pci_find_slot(pbus, pid);
+		if (pdev == NULL)
+			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
+			       np->full_name);
+		
 		/*
 		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
 		 */
@@ -569,8 +877,23 @@
 			++i;
 		if (i >= MAX_HWIFS)
 			break;
+		pmif = &pmac_ide[i];
 
-		base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE;
+		/*
+		 * Some older OFs have bogus sizes, causing request_OF_resource
+		 * to fail. We fix them up here
+		 */
+		if (np->addrs[0].size > 0x1000)
+			np->addrs[0].size = 0x1000;
+		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
+			np->addrs[1].size = 0x100;
+
+		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
+			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
+			continue;
+		}
+
+		base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE;
 
 		/* XXX This is bogus. Should be fixed in the registry by checking
 		   the kind of host interrupt controller, a bit like gatwick
@@ -583,21 +906,30 @@
 		} else {
 			irq = np->intrs[0].line;
 		}
-		pmac_ide[i].regbase = base;
-		pmac_ide[i].irq = irq;
-		pmac_ide[i].node = np;
+		pmif->regbase = base;
+		pmif->irq = irq;
+		pmif->node = np;
 		if (device_is_compatible(np, "keylargo-ata")) {
 			if (strcmp(np->name, "ata-4") == 0)
-				pmac_ide[i].kind = controller_kl_ata4;
+				pmif->kind = controller_kl_ata4;
 			else
-				pmac_ide[i].kind = controller_kl_ata3;
+				pmif->kind = controller_kl_ata3;
 		} else if (device_is_compatible(np, "heathrow-ata"))
-			pmac_ide[i].kind = controller_heathrow;
+			pmif->kind = controller_heathrow;
 		else
-			pmac_ide[i].kind = controller_ohare;
+			pmif->kind = controller_ohare;
 
 		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
-		pmac_ide[i].aapl_bus_id =  bidp ? *bidp : 0;
+		pmif->aapl_bus_id =  bidp ? *bidp : 0;
+
+		if (pmif->kind == controller_kl_ata4) {
+			char* cable = get_property(np, "cable-type", NULL);
+			if (cable && !strncmp(cable, "80-", 3))
+				pmif->kind = controller_kl_ata4_80;
+		}
+
+		/* Make sure we have sane timings */
+		sanitize_timings(i);
 
 		if (np->parent && np->parent->name
 		    && strcasecmp(np->parent->name, "media-bay") == 0) {
@@ -605,39 +937,22 @@
 			media_bay_set_ide_infos(np->parent,base,irq,i);
 #endif /* CONFIG_PMAC_PBOOK */
 			in_bay = 1;
-		} else if (pmac_ide[i].kind == controller_ohare) {
+			if (!bidp)
+				pmif->aapl_bus_id = 1;
+		} else if (pmif->kind == controller_ohare) {
 			/* The code below is having trouble on some ohare machines
 			 * (timing related ?). Until I can put my hand on one of these
 			 * units, I keep the old way
 			 */
-			 feature_set(np, FEATURE_IDE0_enable);
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
 		} else {
  			/* This is necessary to enable IDE when net-booting */
 			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
-				pmac_ide[i].aapl_bus_id);
-			switch(pmac_ide[i].aapl_bus_id) {
-			    case 0:
-				feature_set(np, FEATURE_IDE0_reset);
-				mdelay(10);
- 				feature_set(np, FEATURE_IDE0_enable);
-				mdelay(10);
-				feature_clear(np, FEATURE_IDE0_reset);
-				break;
-			    case 1:
-				feature_set(np, FEATURE_IDE1_reset);
-				mdelay(10);
- 				feature_set(np, FEATURE_IDE1_enable);
-				mdelay(10);
-				feature_clear(np, FEATURE_IDE1_reset);
-				break;
-			    case 2:
-			    	/* This one exists only for KL, I don't know
-				   about any enable bit */
-				feature_set(np, FEATURE_IDE2_reset);
-				mdelay(10);
-				feature_clear(np, FEATURE_IDE2_reset);
-				break;
-			}
+				pmif->aapl_bus_id);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+			mdelay(10);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
 			big_delay = 1;
 		}
 
@@ -646,13 +961,15 @@
 		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
 		hwif->chipset = ide_pmac;
 		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+		hwif->udma_four = (pmif->kind == controller_kl_ata4_80);
+		hwif->pci_dev = pdev;
 #ifdef CONFIG_PMAC_PBOOK
 		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
 			hwif->noprobe = 0;
 #endif /* CONFIG_PMAC_PBOOK */
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		if (np->n_addrs >= 2) {
+		if (pdev && np->n_addrs >= 2) {
 			/* has a DBDMA controller channel */
 			pmac_ide_setup_dma(np, i);
 		}
@@ -674,7 +991,15 @@
 static void __init 
 pmac_ide_setup_dma(struct device_node *np, int ix)
 {
-	pmac_ide[ix].dma_regs =
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+
+	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
+		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n",
+			np->name);
+		return;
+	}
+
+	pmif->dma_regs =
 		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
 
 	/*
@@ -682,14 +1007,24 @@
 	 * The +2 is +1 for the stop command and +1 to allow for
 	 * aligning the start address to a multiple of 16 bytes.
 	 */
-	pmac_ide[ix].dma_table = (struct dbdma_cmd*)
-	       kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL);
-	if (pmac_ide[ix].dma_table == 0) {
+	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+		ide_hwifs[ix].pci_dev,
+		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+		&pmif->dma_table_dma);
+	if (pmif->dma_table_cpu == NULL) {
 		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
 		       ide_hwifs[ix].name);
 		return;
 	}
 
+	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
+				 GFP_KERNEL);
+	if (pmif->sg_table == NULL) {
+		pci_free_consistent(	ide_hwifs[ix].pci_dev,
+					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+				    	pmif->dma_table_cpu, pmif->dma_table_dma);
+		return;
+	}
 	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
 	if (!noautodma)
@@ -697,6 +1032,62 @@
 #endif
 }
 
+static int
+pmac_ide_build_sglist (int ix, struct request *rq)
+{
+	struct ata_channel *hwif = &ide_hwifs[ix];
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+	request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents;
+
+	nents = blk_rq_map_sg(q, rq, pmif->sg_table);
+
+	if (rq->q && nents > rq->nr_phys_segments)
+		printk("ide-pmac: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
+
+	if (rq_data_dir(rq) == READ)
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+static int
+pmac_ide_raw_build_sglist (int ix, struct request *rq)
+{
+	struct ata_channel *hwif = &ide_hwifs[ix];
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].page = virt_to_page(virt_addr);
+		sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].page = virt_to_page(virt_addr);
+	sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
 /*
  * pmac_ide_build_dmatable builds the DBDMA command list
  * for a transfer and sets the DBDMA channel to point to it.
@@ -704,47 +1095,40 @@
 static int
 pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
 {
-	struct dbdma_cmd *table, *tstart;
-	int count = 0;
+	struct dbdma_cmd *table;
+	int i, count = 0;
 	struct request *rq = HWGROUP(drive)->rq;
-	struct buffer_head *bh = rq->bh;
-	unsigned int size, addr;
 	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
+	struct scatterlist *sg;
+
+	/* DMA table is already aligned */
+	table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;
 
-	table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table);
+	/* Make sure DMA controller is stopped (necessary ?) */
 	out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
 	while (in_le32(&dma->status) & RUN)
 		udelay(1);
 
-	do {
-		/*
-		 * Determine addr and size of next buffer area.  We assume that
-		 * individual virtual buffers are always composed linearly in
-		 * physical memory.  For example, we assume that any 8kB buffer
-		 * is always composed of two adjacent physical 4kB pages rather
-		 * than two possibly non-adjacent physical 4kB pages.
-		 */
-		if (bh == NULL) {  /* paging requests have (rq->bh == NULL) */
-			addr = virt_to_bus(rq->buffer);
-			size = rq->nr_sectors << 9;
-		} else {
-			/* group sequential buffers into one large buffer */
-			addr = virt_to_bus(bh->b_data);
-			size = bh->b_size;
-			while ((bh = bh->b_reqnext) != NULL) {
-				if ((addr + size) != virt_to_bus(bh->b_data))
-					break;
-				size += bh->b_size;
-			}
-		}
+	/* Build sglist */
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
+	} else {
+		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
+	}
+	if (!i)
+		return 0;
 
-		/*
-		 * Fill in the next DBDMA command block.
-		 * Note that one DBDMA command can transfer
-		 * at most 65535 bytes.
-		 */
-		while (size) {
-			unsigned int tc = (size < 0xfe00)? size: 0xfe00;
+	/* Build DBDMA commands list */
+	sg = pmac_ide[ix].sg_table;
+	while (i) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
 
 			if (++count >= MAX_DCMDS) {
 				printk(KERN_WARNING "%s: DMA table too small\n",
@@ -753,15 +1137,17 @@
 			}
 			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
 			st_le16(&table->req_count, tc);
-			st_le32(&table->phy_addr, addr);
+			st_le32(&table->phy_addr, cur_addr);
 			table->cmd_dep = 0;
 			table->xfer_status = 0;
 			table->res_count = 0;
-			addr += tc;
-			size -= tc;
+			cur_addr += tc;
+			cur_len -= tc;
 			++table;
 		}
-	} while (bh != NULL);
+		sg++;
+		i--;
+	}
 
 	/* convert the last command to an input/output last command */
 	if (count)
@@ -773,10 +1159,24 @@
 	memset(table, 0, sizeof(struct dbdma_cmd));
 	out_le16(&table->command, DBDMA_STOP);
 
-	out_le32(&dma->cmdptr, virt_to_bus(tstart));
+	out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
 	return 1;
 }
 
+/* Teardown mappings after DMA has completed.  */
+static void
+pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	struct scatterlist *sg = pmac_ide[ix].sg_table;
+	int nents = pmac_ide[ix].sg_nents;
+
+	if (nents) {
+		pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
+		pmac_ide[ix].sg_nents = 0;
+	}
+}
+
 
 static __inline__ unsigned char
 dma_bits_to_command(unsigned char bits)
@@ -791,12 +1191,14 @@
 }
 
 static __inline__ unsigned char
-udma_bits_to_command(unsigned char bits)
+udma_bits_to_command(unsigned char bits, int high_speed)
 {
-	if(bits & 0x10)
-		return XFER_UDMA_4;
-	if(bits & 0x08)
-		return XFER_UDMA_3;
+	if (high_speed) {
+		if(bits & 0x10)
+			return XFER_UDMA_4;
+		if(bits & 0x08)
+			return XFER_UDMA_3;
+	}
 	if(bits & 0x04)
 		return XFER_UDMA_2;
 	if(bits & 0x02)
@@ -807,14 +1209,13 @@
 }
 
 /* Calculate MultiWord DMA timings */
-static int
+static int __pmac
 pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
 {
 	byte bits = drive->id->dma_mword & 0x07;
 	byte feature = dma_bits_to_command(bits);
 	u32 *timings;
-	int cycleTime, accessTime;
-	int accessTicks, recTicks;
+	int drive_cycle_time;
 	struct hd_driveid *id = drive->id;
 	int ret;
 
@@ -830,66 +1231,30 @@
 		drive->init_speed = feature;
 	
 	/* which drive is it ? */
-	if (drive->select.all & 0x10)
+	if (drive->select.b.unit & 0x01)
 		timings = &pmac_ide[idx].timings[1];
 	else
 		timings = &pmac_ide[idx].timings[0];
 
-	/* Calculate accesstime and cycle time */
-	cycleTime = mdma_timings[feature & 0xf].cycleTime;
-	accessTime = mdma_timings[feature & 0xf].accessTime;
+	/* Check if drive provide explicit cycle time */
 	if ((id->field_valid & 2) && (id->eide_dma_time))
-		cycleTime = id->eide_dma_time;
-	if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150))
-		cycleTime = 150;
+		drive_cycle_time = id->eide_dma_time;
+	else
+		drive_cycle_time = 0;
+
+	/* Calculate controller timings */
+	set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);
 
-	/* For ata-4 controller */
-	if (pmac_ide[idx].kind == controller_kl_ata4) {
-		accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
-		recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
-		*timings = ((*timings) & 0xffe003ff) |
-			(accessTicks | (recTicks << 5)) << 10;
-	} else {
-		int halfTick = 0;
-		int origAccessTime = accessTime;
-		int origCycleTime = cycleTime;
-		
-		accessTicks = SYSCLK_TICKS(accessTime);
-		if (accessTicks < 1)
-			accessTicks = 1;
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1;
-		if (recTicks < 1)
-			recTicks = 1;
-		cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
-
-		/* KeyLargo ata-3 don't support the half-tick stuff */
-		if ((pmac_ide[idx].kind != controller_kl_ata3) &&
-			(accessTicks > 1) &&
-			((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
-			((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
-            			halfTick    = 1;
-				accessTicks--;
-		}
-		*timings = ((*timings) & 0x7FF) |
-			(accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
-	}
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_INFO "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
-		feature & 0xf, *timings);
-#endif
 	drive->current_speed = feature;	
 	return 1;
 }
 
 /* Calculate Ultra DMA timings */
-static int
-pmac_ide_udma_enable(ide_drive_t *drive, int idx)
+static int __pmac
+pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed)
 {
 	byte bits = drive->id->dma_ultra & 0x1f;
-	byte feature = udma_bits_to_command(bits);
-	int cycleTime, accessTime;
-	int rdyToPauseTicks, cycleTicks;
+	byte feature = udma_bits_to_command(bits, high_speed);
 	u32 *timings;
 	int ret;
 
@@ -905,25 +1270,18 @@
 		drive->init_speed = feature;
 
 	/* which drive is it ? */
-	if (drive->select.all & 0x10)
+	if (drive->select.b.unit & 0x01)
 		timings = &pmac_ide[idx].timings[1];
 	else
 		timings = &pmac_ide[idx].timings[0];
 
-	cycleTime = udma_timings[feature & 0xf].cycleTime;
-	accessTime = udma_timings[feature & 0xf].accessTime;
-
-	rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
-	cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
-
-	*timings = ((*timings) & 0xe00fffff) |
-			((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+	set_timings_udma(timings, feature);
 
 	drive->current_speed = feature;	
 	return 1;
 }
 
-static int
+static int __pmac
 pmac_ide_check_dma(ide_drive_t *drive)
 {
 	int ata4, udma, idx;
@@ -944,21 +1302,20 @@
 		enable = 0;
 
 	udma = 0;
-	ata4 = (pmac_ide[idx].kind == controller_kl_ata4);
+	ata4 = (pmac_ide[idx].kind == controller_kl_ata4 ||
+		pmac_ide[idx].kind == controller_kl_ata4_80);
 
 	if(enable) {
 		if (ata4 && (drive->type == ATA_DISK) &&
-		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {
+		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
 			/* UltraDMA modes. */
-			drive->using_dma = pmac_ide_udma_enable(drive, idx);
+			drive->using_dma = pmac_ide_udma_enable(drive, idx,
+				pmac_ide[idx].kind == controller_kl_ata4_80);
 		}
 		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
 			/* Normal MultiWord DMA modes. */
 			drive->using_dma = pmac_ide_mdma_enable(drive, idx);
 		}
-		/* Without this, strange things will happen on Keylargo-based
-		 * machines
-		 */
 		OUT_BYTE(0, IDE_CONTROL_REG);
 		/* Apply settings to controller */
 		pmac_ide_selectproc(drive);
@@ -966,11 +1323,26 @@
 	return 0;
 }
 
+static void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+
+	if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
 int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	int ix, dstat, i;
+	int ix, dstat, reading, ata4;
 	volatile struct dbdma_regs *dma;
-
+	byte unit = (drive->select.b.unit & 0x01);
+	
 	/* Can we stuff a pointer to our intf structure in config_data
 	 * or select_data in hwif ?
 	 */
@@ -978,59 +1350,106 @@
 	if (ix < 0)
 		return 0;		
 	dma = pmac_ide[ix].dma_regs;
-
+	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
+		pmac_ide[ix].kind == controller_kl_ata4_80);
+	
 	switch (func) {
 	case ide_dma_off:
 		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
 	case ide_dma_off_quietly:
 		drive->using_dma = 0;
+		ide_toggle_bounce(drive, 0);
 		break;
 	case ide_dma_on:
 	case ide_dma_check:
+		/* Change this to better match ide-dma.c */
 		pmac_ide_check_dma(drive);
+		ide_toggle_bounce(drive, drive->using_dma);
 		break;
 	case ide_dma_read:
 	case ide_dma_write:
-		if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
+		/* this almost certainly isn't needed since we don't
+		   appear to have a rwproc */
+		if (HWIF(drive)->rwproc)
+			HWIF(drive)->rwproc(drive, func);
+		reading = (func == ide_dma_read);
+		if (!pmac_ide_build_dmatable(drive, ix, !reading))
 			return 1;
+		/* Apple adds 60ns to wrDataSetup on reads */
+		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
+			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
+				pmac_ide[ix].timings[unit] + 
+				((func == ide_dma_read) ? 0x00800000UL : 0));
+			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
+		}
 		drive->waiting_for_dma = 1;
 		if (drive->type != ATA_DISK)
 			return 0;
 		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
-			 IDE_COMMAND_REG);
+		if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
+		    (drive->addressing == 1)) {
+			ide_task_t *args = HWGROUP(drive)->rq->special;
+			OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
+		} else if (drive->addressing) {
+			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+		} else {
+			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+		}
+		/* fall through */
 	case ide_dma_begin:
 		out_le32(&dma->control, (RUN << 16) | RUN);
+		/* Make sure it gets to the controller right now */
+		(void)in_le32(&dma->control);
 		break;
-	case ide_dma_end:
+	case ide_dma_end: /* returns 1 on error, 0 otherwise */
 		drive->waiting_for_dma = 0;
 		dstat = in_le32(&dma->status);
 		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
+		pmac_ide_destroy_dmatable(drive, ix);
 		/* verify good dma status */
 		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
-	case ide_dma_test_irq:
-		if ((in_le32(&dma->status) & (RUN|ACTIVE)) == RUN)
-			return 1;
-		/* That's a bit ugly and dangerous, but works in our case
-		 * to workaround a problem with the channel status staying
-		 * active if the drive returns an error
+	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
+		/* We have to things to deal with here:
+		 * 
+		 * - The dbdma won't stop if the command was started
+		 * but completed with an error without transfering all
+		 * datas. This happens when bad blocks are met during
+		 * a multi-block transfer.
+		 * 
+		 * - The dbdma fifo hasn't yet finished flushing to
+		 * to system memory when the disk interrupt occurs.
+		 * 
+		 * The trick here is to increment drive->waiting_for_dma,
+		 * and return as if no interrupt occured. If the counter
+		 * reach a certain timeout value, we then return 1. If
+		 * we really got the interrupt, it will happen right away
+		 * again.
+		 * Apple's solution here may be more elegant. They issue
+		 * a DMA channel interrupt (a separate irq line) via a DBDMA
+		 * NOP command just before the STOP, and wait for both the
+		 * disk and DBDMA interrupts to have completed.
 		 */
-		if (IDE_CONTROL_REG) {
-			byte stat;
-			stat = GET_ALTSTAT();
-			if (stat & ERR_STAT)
-				return 1;
-		}
-		/* In some edge cases, some datas may still be in the dbdma
-		 * engine fifo, we wait a bit for dbdma to complete
+		 
+		/* If ACTIVE is cleared, the STOP command have passed and
+		 * transfer is complete.
 		 */
-		while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) {
-			if (++i > 100)
-				return 0;
-			udelay(1);
+		if (!(in_le32(&dma->status) & ACTIVE))
+			return 1;
+		if (!drive->waiting_for_dma)
+			printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+				called while not waiting\n", ix);
+
+		/* If dbdma didn't execute the STOP command yet, the
+		 * active bit is still set */
+		drive->waiting_for_dma++;
+		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+			printk(KERN_WARNING "ide%d, timeout waiting \
+				for dbdma command stop\n", ix);
+			return 1;
 		}
-		return 1;
+		udelay(1);
+		return 0;
 
 		/* Let's implement tose just in case someone wants them */
 	case ide_dma_bad_drive:
@@ -1051,7 +1470,6 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
-#ifdef CONFIG_PMAC_PBOOK
 static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
 {
 	int j;
@@ -1062,7 +1480,9 @@
 	switch (drive->type) {
 	case ATA_DISK:
 		/* Spin down the drive */
-		outb(0xa0, base+0x60);
+		outb(drive->select.all, base+0x60);
+		(void)inb(base+0x60);
+		udelay(100);
 		outb(0x0, base+0x30);
 		outb(0x0, base+0x20);
 		outb(0x0, base+0x40);
@@ -1086,19 +1506,21 @@
 	}
 }
 
-static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
- {
+#ifdef CONFIG_PMAC_PBOOK
+static void __pmac
+idepmac_wake_device(ide_drive_t *drive, int used_dma)
+{
 	/* We force the IDE subdriver to check for a media change
 	 * This must be done first or we may lost the condition
 	 *
 	 * Problem: This can schedule. I moved the block device
 	 * wakeup almost late by priority because of that.
 	 */
-	if (DRIVER(drive) && DRIVER(drive)->media_change)
-		DRIVER(drive)->media_change(drive);
+	if (drive->driver != NULL && ata_ops(drive)->check_media_change)
+		ata_ops(drive)->check_media_change(drive);
 
 	/* We kick the VFS too (see fix in ide.c revalidate) */
-	check_disk_change(MKDEV(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));
+	check_disk_change(mk_kdev(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));
 	
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* We re-enable DMA on the drive if it was active. */
@@ -1108,15 +1530,16 @@
 	 */
 	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
 		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
+		set_bit(IDE_BUSY, &HWGROUP(drive)->flags);
 		pmac_ide_check_dma(drive);
-		HWGROUP(drive)->busy = 0;
+		clear_bit(IDE_BUSY, &HWGROUP(drive)->flags);
 		spin_unlock_irq(&ide_lock);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 }
 
-static void idepmac_sleep_interface(int i, unsigned base, int mediabay)
+static void __pmac
+idepmac_sleep_interface(int i, unsigned base, int mediabay)
 {
 	struct device_node* np = pmac_ide[i].node;
 
@@ -1128,73 +1551,81 @@
 	if (mediabay)
 		return;
 	
-	/* Disable and reset the bus */
-	feature_set(np, FEATURE_IDE0_reset);
-	feature_clear(np, FEATURE_IDE0_enable);
-	switch(pmac_ide[i].aapl_bus_id) {
-	    case 0:
-		feature_set(np, FEATURE_IDE0_reset);
-		feature_clear(np, FEATURE_IDE0_enable);
-		break;
-	    case 1:
-		feature_set(np, FEATURE_IDE1_reset);
-		feature_clear(np, FEATURE_IDE1_enable);
-		break;
-	    case 2:
-		feature_set(np, FEATURE_IDE2_reset);
-		break;
-	}
+	/* Disable the bus */
+	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);
 }
 
-static void idepmac_wake_interface(int i, unsigned long base, int mediabay)
+static void __pmac
+idepmac_wake_interface(int i, unsigned long base, int mediabay)
 {
 	struct device_node* np = pmac_ide[i].node;
 
 	if (!mediabay) {
 		/* Revive IDE disk and controller */
-		switch(pmac_ide[i].aapl_bus_id) {
-		    case 0:
-			feature_set(np, FEATURE_IDE0_reset);
-			feature_set(np, FEATURE_IOBUS_enable);
-			mdelay(10);
-	 		feature_set(np, FEATURE_IDE0_enable);
-			mdelay(10);
-			feature_clear(np, FEATURE_IDE0_reset);
-			break;
-		    case 1:
-			feature_set(np, FEATURE_IDE1_reset);
-			feature_set(np, FEATURE_IOBUS_enable);
-			mdelay(10);
-	 		feature_set(np, FEATURE_IDE1_enable);
-			mdelay(10);
-			feature_clear(np, FEATURE_IDE1_reset);
-			break;
-		    case 2:
-		    	/* This one exists only for KL, I don't know
-			   about any enable bit */
-			feature_set(np, FEATURE_IDE2_reset);
-			mdelay(10);
-			feature_clear(np, FEATURE_IDE2_reset);
-			break;
-		}
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1);
+		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1);
+		mdelay(10);
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0);
 	}
+}
+
+static void
+idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base)
+{
+	/* Wait for HW group to complete operations */
+	if (ide_spin_wait_hwgroup(drive))
+		// What can we do here ? Wake drive we had already
+		// put to sleep and return an error ?
+		return;
+	else {
+		/* Lock HW group */
+		set_bit(IDE_BUSY, &HWGROUP(drive)->flags);
+		/* Stop the device */
+		idepmac_sleep_device(drive, idx, base);
+		spin_unlock_irq(&ide_lock);
+	}
+}
+
+static void
+idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
+{
+	int j;
 	
 	/* Reset timings */
-	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
+	pmac_ide_selectproc(drive);
 	mdelay(10);
+	
+	/* Wait up to 20 seconds for the drive to be ready */
+	for (j = 0; j < 200; j++) {
+		int status;
+		mdelay(100);
+		outb(drive->select.all, base + 0x60);
+		if (inb(base + 0x60) != drive->select.all)
+			continue;
+		status = inb(base + 0x70);
+		if (!(status & BUSY_STAT))
+			break;
+	}
+
+	/* We resume processing on the HW group */
+	spin_lock_irq(&ide_lock);
+	clear_bit(IDE_BUSY, &HWGROUP(drive)->flags);
+	if (!list_empty(&drive->queue.queue_head))
+		do_ide_request(&drive->queue);
+	spin_unlock_irq(&ide_lock);
 }
 
 /* Note: We support only master drives for now. This will have to be
  * improved if we want to handle sleep on the iMacDV where the CD-ROM
  * is a slave
  */
-static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
+static int __pmac
+idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
 	int i, ret;
 	unsigned long base;
-	unsigned long flags;
 	int big_delay;
-
+ 
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 		break;
@@ -1203,34 +1634,19 @@
 	case PBOOK_SLEEP_NOW:
 		for (i = 0; i < pmac_ide_count; ++i) {
 			struct ata_channel *hwif;
-			ide_drive_t *drive;
-			int unlock = 0;
+			int dn;
 
 			if ((base = pmac_ide[i].regbase) == 0)
-				continue;	
+				continue;
 
 			hwif = &ide_hwifs[i];
-			drive = &hwif->drives[0];
-			
-			if (drive->present) {
-				/* Wait for HW group to complete operations */
-				if (ide_spin_wait_hwgroup(drive)) {
-					// What can we do here ? Wake drive we had already
-					// put to sleep and return an error ?
-				} else {
-					unlock = 1;
-					/* Lock HW group */
-					HWGROUP(drive)->busy = 1;
-
-					/* Stop the device */
-					idepmac_sleep_device(drive, i, base);
-				
-				}
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				if (!hwif->drives[dn].present)
+					continue;
+				idepmac_sleep_drive(&hwif->drives[dn], i, base);
 			}
 			/* Disable irq during sleep */
 			disable_irq(pmac_ide[i].irq);
-			if (unlock)
-				spin_unlock_irq(&ide_lock);
 			
 			/* Check if this is a media bay with an IDE device or not
 			 * a media bay.
@@ -1247,6 +1663,9 @@
 			if ((base = pmac_ide[i].regbase) == 0)
 				continue;
 				
+			/* Make sure we have sane timings */		
+			sanitize_timings(i);
+
 			/* Check if this is a media bay with an IDE device or not
 			 * a media bay
 			 */
@@ -1263,43 +1682,29 @@
 	
 		for (i = 0; i < pmac_ide_count; ++i) {
 			struct ata_channel *hwif;
-			ide_drive_t *drive;
-			int j, used_dma;
+			int used_dma, dn;
+			int irq_on = 0;
 			
 			if ((base = pmac_ide[i].regbase) == 0)
 				continue;
 				
 			hwif = &ide_hwifs[i];
-			drive = &hwif->drives[0];
-
-			/* Wait for the drive to come up and set it's DMA */
-			if (drive->present) {
-				/* Wait up to 20 seconds */
-				for (j = 0; j < 200; j++) {
-					int status;
-					mdelay(100);
-					status = inb(base + 0x70);
-					if (!(status & BUSY_STAT))
-						break;
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				ide_drive_t *drive = &hwif->drives[dn];
+				if (!drive->present)
+					continue;
+				/* We don't have re-configured DMA yet */
+				used_dma = drive->using_dma;
+				drive->using_dma = 0;
+				idepmac_wake_drive(drive, base);
+				if (!irq_on) {
+					enable_irq(pmac_ide[i].irq);
+					irq_on = 1;
 				}
-			}
-			
-			/* We don't have re-configured DMA yet */
-			used_dma = drive->using_dma;
-			drive->using_dma = 0;
-
-			/* We resume processing on the HW group */
-			spin_lock_irqsave(&ide_lock, flags);
-			enable_irq(pmac_ide[i].irq);
-			if (drive->present)
-				HWGROUP(drive)->busy = 0;
-			spin_unlock_irqrestore(&ide_lock, flags);
-			
-			/* Wake the device
-			 * We could handle the slave here
-			 */
-			if (drive->present)
 				idepmac_wake_device(drive, used_dma);
+			}
+			if (!irq_on)
+				enable_irq(pmac_ide[i].irq);
 		}
 		break;
 	}
diff -urN linux-2.5.8-pre2/drivers/ide/ide-pnp.c linux-2.5.8-pre3/drivers/ide/ide-pnp.c
--- linux-2.5.8-pre2/drivers/ide/ide-pnp.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ide-pnp.c	Tue Apr  9 18:35:19 2002
@@ -16,6 +16,7 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/types.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
diff -urN linux-2.5.8-pre2/drivers/ide/ide-probe.c linux-2.5.8-pre3/drivers/ide/ide-probe.c
--- linux-2.5.8-pre2/drivers/ide/ide-probe.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ide-probe.c	Tue Apr  9 18:35:19 2002
@@ -140,7 +140,7 @@
 				/* kludge for Apple PowerBook internal zip */
 				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
 					printk ("FLOPPY");
-					type = ide_floppy;
+					type = ATA_FLOPPY;
 					break;
 				}
 #endif
@@ -666,13 +666,12 @@
 				hwif->sharing_irq = h->sharing_irq = 1;
 				if (hwif->chipset != ide_pci || h->chipset != ide_pci)
 					save_match(hwif, h, &match);
-			}
-			if (hwif->serialized) {
-				if (hwif->mate && hwif->mate->irq == h->irq)
-					save_match(hwif, h, &match);
-			}
-			if (h->serialized) {
-				if (h->mate && hwif->irq == h->mate->irq)
+
+				/* FIXME: This is still confusing. What would
+				 * happen if we match-ed two times?
+				 */
+
+				if (hwif->serialized || h->serialized)
 					save_match(hwif, h, &match);
 			}
 		}
@@ -823,12 +822,11 @@
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		char name[80];
+
 		ide_add_generic_settings(hwif->drives + unit);
 		hwif->drives[unit].dn = ((hwif->unit ? 2 : 0) + unit);
 		sprintf (name, "host%d/bus%d/target%d/lun%d",
-			(hwif->unit && hwif->mate) ?
-			hwif->mate->index : hwif->index,
-			hwif->unit, unit, hwif->drives[unit].lun);
+			hwif->index, hwif->unit, unit, hwif->drives[unit].lun);
 		if (hwif->drives[unit].present)
 			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
 	}
diff -urN linux-2.5.8-pre2/drivers/ide/ide-proc.c linux-2.5.8-pre3/drivers/ide/ide-proc.c
--- linux-2.5.8-pre2/drivers/ide/ide-proc.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ide-proc.c	Tue Apr  9 18:35:19 2002
@@ -164,19 +164,6 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_mate
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct ata_channel *hwif = data;
-	int		len;
-
-	if (hwif && hwif->mate && hwif->mate->present)
-		len = sprintf(page, "%s\n", hwif->mate->name);
-	else
-		len = sprintf(page, "(none)\n");
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
 static int proc_ide_read_channel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -493,7 +480,6 @@
 
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
-	{ "mate",	S_IFREG|S_IRUGO,	proc_ide_read_mate,	NULL },
 	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_imodel,	NULL },
 	{ NULL,	0, NULL, NULL }
 };
diff -urN linux-2.5.8-pre2/drivers/ide/ide.c linux-2.5.8-pre3/drivers/ide/ide.c
--- linux-2.5.8-pre2/drivers/ide/ide.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ide.c	Tue Apr  9 18:35:19 2002
@@ -2177,7 +2177,7 @@
 		}
 		for (h = 0; h < MAX_HWIFS; ++h) {
 			hwif = &ide_hwifs[h];
-			if ((!hwif->present && !hwif->mate && !initializing) ||
+			if ((!hwif->present && (hwif->unit == ATA_PRIMARY) && !initializing) ||
 			    (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
 				goto found;
 		}
@@ -3052,9 +3052,13 @@
 				goto done;
 			case -2: /* "serialize" */
 			do_serialize:
-				hwif->mate = &ide_hwifs[hw^1];
-				hwif->mate->mate = hwif;
-				hwif->serialized = hwif->mate->serialized = 1;
+				{
+					struct ata_channel *mate;
+
+					mate = &ide_hwifs[hw ^ 1];
+					hwif->serialized = 1;
+					mate->serialized = 1;
+				}
 				goto done;
 
 			case -1: /* "noprobe" */
diff -urN linux-2.5.8-pre2/drivers/ide/ns87415.c linux-2.5.8-pre3/drivers/ide/ns87415.c
--- linux-2.5.8-pre2/drivers/ide/ns87415.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/ns87415.c	Tue Apr  9 18:35:19 2002
@@ -141,11 +141,21 @@
 	using_inta = progif & (1 << (hwif->unit << 1));
 	if (!using_inta)
 		using_inta = ctrl & (1 << (4 + hwif->unit));
-	if (hwif->mate) {
-		hwif->select_data = hwif->mate->select_data;
+	if (hwif->unit == ATA_SECONDARY) {
+
+		/* FIXME: If we are initializing the secondary channel, let us
+		 * assume that the primary channel got initialized just a tad
+		 * bit before now.  It would be much cleaner if the data in
+		 * ns87415_control just got duplicated.
+		 */
+
+		if (!hwif->select_data)
+		    hwif->select_data = (unsigned long)
+			&ns87415_control[ns87415_count - 1];
 	} else {
-		hwif->select_data = (unsigned long)
-					&ns87415_control[ns87415_count++];
+		if (!hwif->select_data)
+		    hwif->select_data = (unsigned long)
+			&ns87415_control[ns87415_count++];
 		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
 		if (using_inta)
 			ctrl &= ~(1 << 6);	/* unmask INTA */
@@ -170,9 +180,9 @@
 		do {
 			udelay(50);
 			stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]);
-                	if (stat == 0xff)
-                        	break;
-        	} while ((stat & BUSY_STAT) && --timeout);
+			if (stat == 0xff)
+				break;
+		} while ((stat & BUSY_STAT) && --timeout);
 #endif
 	}
 
@@ -181,13 +191,23 @@
 
 	if (!using_inta)
 		hwif->irq = hwif->unit ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
+	else {
+		static int primary_irq = 0;
+
+		/* Ugly way to let the primary and secondary channel on the
+		 * chip use the same IRQ line.
+		 */
+
+		if (hwif->unit == ATA_PRIMARY)
+			primary_irq = hwif->irq;
+		else if (!hwif->irq)
+			hwif->irq = primary_irq;
+	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base)
 		hwif->dmaproc = &ns87415_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+#endif
 
 	hwif->selectproc = &ns87415_selectproc;
 }
diff -urN linux-2.5.8-pre2/drivers/ide/pdc4030.c linux-2.5.8-pre3/drivers/ide/pdc4030.c
--- linux-2.5.8-pre2/drivers/ide/pdc4030.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/pdc4030.c	Tue Apr  9 18:35:19 2002
@@ -162,7 +162,7 @@
 	struct dc_ident ident;
 	int i;
 	ide_startstop_t startstop;
-	
+
 	if (!hwif) return 0;
 
 	drive = &hwif->drives[0];
@@ -224,9 +224,8 @@
 	 */
 
 	hwif->chipset	= hwif2->chipset = ide_pdc4030;
-	hwif->mate	= hwif2;
-	hwif2->mate	= hwif;
-	hwif2->unit	= 1;
+	hwif->unit	= ATA_PRIMARY;
+	hwif2->unit	= ATA_SECONDARY;
 	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
 	hwif->serialized = hwif2->serialized = 1;
 
diff -urN linux-2.5.8-pre2/drivers/ide/piix.c linux-2.5.8-pre3/drivers/ide/piix.c
--- linux-2.5.8-pre2/drivers/ide/piix.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/piix.c	Tue Apr  9 18:35:19 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: piix.c,v 1.2 2002/03/13 22:50:43 vojtech Exp $
+ * $Id: piix.c,v 1.3 2002/03/29 16:06:06 vojtech Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik
  *
@@ -128,7 +128,7 @@
 
 	piix_print("----------PIIX BusMastering IDE Configuration---------------");
 
-	piix_print("Driver Version:                     1.2");
+	piix_print("Driver Version:                     1.3");
 	piix_print("South Bridge:                       %s", bmide_dev->name);
 
 	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
@@ -331,7 +331,7 @@
 		umul = 2;
 
 	T = 1000000000 / piix_clock;
-	UT = T / umul;
+	UT = umul ? (T / umul) : 0;
 
 	ata_timing_compute(drive, speed, &t, T, UT);
 
diff -urN linux-2.5.8-pre2/drivers/ide/qd65xx.c linux-2.5.8-pre3/drivers/ide/qd65xx.c
--- linux-2.5.8-pre2/drivers/ide/qd65xx.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/qd65xx.c	Tue Apr  9 18:35:19 2002
@@ -411,22 +411,23 @@
 
 			return 1;
 		} else {
-			int i,j;
+			int i;
+
 			/* secondary enabled */
 			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
 					ide_hwifs[0].name,ide_hwifs[1].name);
 
-			for (i=0;i<2;i++) {
+			for (i = 0; i < 2; i++) {
+				int j;
 
 				ide_hwifs[i].chipset = ide_qd65xx;
-				ide_hwifs[i].mate = &ide_hwifs[i^1];
 				ide_hwifs[i].unit = i;
 
 				ide_hwifs[i].select_data = base;
 				ide_hwifs[i].config_data = config | (control <<8);
 				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
 
-				for (j=0;j<2;j++) {
+				for (j = 0; j < 2; j++) {
 					ide_hwifs[i].drives[j].drive_data =
 					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
 					ide_hwifs[i].drives[j].io_32bit = 1;
diff -urN linux-2.5.8-pre2/drivers/ide/sis5513.c linux-2.5.8-pre3/drivers/ide/sis5513.c
--- linux-2.5.8-pre2/drivers/ide/sis5513.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/sis5513.c	Tue Apr  9 18:35:19 2002
@@ -1,17 +1,17 @@
 /*
- * linux/drivers/ide/sis5513.c		Version 0.13	March 4, 2002
+ * linux/drivers/ide/sis5513.c		Version 0.13	March 6, 2002
  *
  * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
  * May be copied or modified under the terms of the GNU General Public License
  *
-*/
-
-/* Thanks :
- * For direct support and hardware : SiS Taiwan.
- * For ATA100 support advice       : Daniela Engert.
- * For checking code correctness, providing patches :
- * John Fremlin, Manfred Spraul
+ *
+ * Thanks :
+ *
+ * SiS Taiwan		: for direct support and hardware.
+ * Daniela Engert	: for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul :
+ *			  for checking code correctness, providing patches.
  */
 
 /*
@@ -52,59 +52,40 @@
 
 #include "ata-timing.h"
 
+/* When DEBUG is defined it outputs initial PCI config register
+   values and changes made to them by the driver */
 // #define DEBUG
-/* if BROKEN_LEVEL is defined it limits the DMA mode
+/* When BROKEN_LEVEL is defined it limits the DMA mode
    at boot time to its value */
 // #define BROKEN_LEVEL XFER_SW_DMA_0
 #define DISPLAY_SIS_TIMINGS
 
 /* Miscellaneaous flags */
 #define SIS5513_LATENCY		0x01
-/* ATA transfer mode capabilities */
+
+/* registers layout and init values are chipset family dependant */
+/* 1/ define families */
 #define ATA_00		0x00
 #define ATA_16		0x01
 #define ATA_33		0x02
 #define ATA_66		0x03
-#define ATA_100a	0x04
+#define ATA_100a	0x04	// SiS730 is ATA100 with ATA66 layout
 #define ATA_100		0x05
 #define ATA_133		0x06
 
-static unsigned char dma_capability = 0x00;
-
+/* 2/ variable holding the controller chipset family value */
+static unsigned char chipset_family;
 
 /*
  * Debug code: following IDE config registers' changes
  */
 #ifdef DEBUG
-/* Copy of IDE Config registers 0x00 -> 0x58
+/* Copy of IDE Config registers 0x00 -> 0x57
    Fewer might be used depending on the actual chipset */
-static unsigned char ide_regs_copy[] = {
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0,
-	0x0, 0x0, 0x0, 0x0
-};
+static unsigned char ide_regs_copy[0x58];
 
 static byte sis5513_max_config_register(void) {
-	switch(dma_capability) {
+	switch(chipset_family) {
 		case ATA_00:
 		case ATA_16:	return 0x4f;
 		case ATA_33:	return 0x52;
@@ -185,7 +166,7 @@
 static const struct {
 	const char *name;
 	unsigned short host_id;
-	unsigned char dma_capability;
+	unsigned char chipset_family;
 	unsigned char flags;
 } SiSHostChipInfo[] = {
 	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_100,	SIS5513_LATENCY },
@@ -211,7 +192,7 @@
 
 /* Cycle time bits and values vary accross chip dma capabilities
    These three arrays hold the register layout and the values to set.
-   Indexed by dma_capability and (dma_mode - XFER_UDMA_0) */
+   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
 static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
 static byte cycle_time_range[] = {0,0,2,3,3,4,4};
 static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
@@ -293,13 +274,13 @@
 	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
 
 /* UDMA */
-	if (dma_capability >= ATA_33) {
+	if (chipset_family >= ATA_33) {
 		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
 			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
 			     (reg11 & 0x80) ? "Enabled" : "Disabled");
 
 		p += sprintf(p, "                UDMA Cycle Time    ");
-		switch(dma_capability) {
+		switch(chipset_family) {
 			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
 			case ATA_66:
 			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
@@ -308,7 +289,7 @@
 			default:	p += sprintf(p, "133+ ?"); break;
 		}
 		p += sprintf(p, " \t UDMA Cycle Time    ");
-		switch(dma_capability) {
+		switch(chipset_family) {
 			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
 			case ATA_66:
 			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
@@ -321,7 +302,7 @@
 
 /* Data Active */
 	p += sprintf(p, "                Data Active Time   ");
-	switch(dma_capability) {
+	switch(chipset_family) {
 		case ATA_00:
 		case ATA_16: /* confirmed */
 		case ATA_33:
@@ -332,7 +313,7 @@
 		default: p += sprintf(p, "133+ ?"); break;
 	}
 	p += sprintf(p, " \t Data Active Time   ");
-	switch(dma_capability) {
+	switch(chipset_family) {
 		case ATA_00:
 		case ATA_16:
 		case ATA_33:
@@ -370,7 +351,7 @@
 	u16 reg2, reg3;
 
 	p += sprintf(p, "\nSiS 5513 ");
-	switch(dma_capability) {
+	switch(chipset_family) {
 		case ATA_00: p += sprintf(p, "Unknown???"); break;
 		case ATA_16: p += sprintf(p, "DMA 16"); break;
 		case ATA_33: p += sprintf(p, "Ultra 33"); break;
@@ -386,7 +367,7 @@
 /* Status */
 	pci_read_config_byte(bmide_dev, 0x4a, &reg);
 	p += sprintf(p, "Channel Status: ");
-	if (dma_capability < ATA_66) {
+	if (chipset_family < ATA_66) {
 		p += sprintf(p, "%s \t \t \t \t %s\n",
 			     (reg & 0x04) ? "On" : "Off",
 			     (reg & 0x02) ? "On" : "Off");
@@ -403,7 +384,7 @@
 		     (reg & 0x04) ? "Native" : "Compatible");
 
 /* 80-pin cable ? */
-	if (dma_capability > ATA_33) {
+	if (chipset_family > ATA_33) {
 		pci_read_config_byte(bmide_dev, 0x48, &reg);
 		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
 			     (reg & 0x10) ? cable_type[1] : cable_type[0],
@@ -507,7 +488,7 @@
 	}
 
 	/* register layout changed with newer ATA100 chips */
-	if (dma_capability < ATA_100) {
+	if (chipset_family < ATA_100) {
 		pci_read_config_byte(dev, drive_pci, &test1);
 		pci_read_config_byte(dev, drive_pci+1, &test2);
 
@@ -587,7 +568,7 @@
 
 	pci_read_config_byte(dev, drive_pci+1, &reg);
 	/* Disable UDMA bit for non UDMA modes on UDMA chips */
-	if ((speed < XFER_UDMA_0) && (dma_capability > ATA_16)) {
+	if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
 		reg &= 0x7F;
 		pci_write_config_byte(dev, drive_pci+1, reg);
 	}
@@ -604,11 +585,11 @@
 			/* Force the UDMA bit on if we want to use UDMA */
 			reg |= 0x80;
 			/* clean reg cycle time bits */
-			reg &= ~((0xFF >> (8 - cycle_time_range[dma_capability]))
-				 << cycle_time_offset[dma_capability]);
+			reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+				 << cycle_time_offset[chipset_family]);
 			/* set reg cycle time bits */
-			reg |= cycle_time_value[dma_capability-ATA_00][speed-XFER_UDMA_0]
-				<< cycle_time_offset[dma_capability];
+			reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
+				<< cycle_time_offset[chipset_family];
 			pci_write_config_byte(dev, drive_pci+1, reg);
 			break;
 		case XFER_MW_DMA_2:
@@ -624,7 +605,7 @@
 		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
 		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
 		case XFER_PIO_0:
-		default:	 return((int) config_chipset_for_pio(drive, 0));	
+		default:	 return((int) config_chipset_for_pio(drive, 0));
 	}
 	drive->current_speed = speed;
 #ifdef DEBUG
@@ -657,17 +638,17 @@
 	       drive->dn, ultra);
 #endif
 
-	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (dma_capability >= ATA_100a))
+	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a))
 		speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (dma_capability >= ATA_66))
+	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66))
 		speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (dma_capability >= ATA_66))
+	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66))
 		speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && ultra && (dma_capability >= ATA_33))
+	else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33))
 		speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && ultra && (dma_capability >= ATA_33))
+	else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33))
 		speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && ultra && (dma_capability >= ATA_33))
+	else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_33))
 		speed = XFER_UDMA_0;
 	else if (id->dma_mword & 0x0004)
 		speed = XFER_MW_DMA_2;
@@ -700,6 +681,8 @@
 	struct hd_driveid *id		= drive->id;
 	ide_dma_action_t dma_func	= ide_dma_off_quietly;
 
+	config_chipset_for_pio(drive, 5);
+
 	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
@@ -764,10 +747,6 @@
 	struct pci_dev *host;
 	int i = 0;
 
-#ifdef DEBUG
-	sis5513_print_registers(dev, "pci_init_sis5513 start");
-#endif
-
 	/* Find the chip */
 	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
 		host = pci_find_device (PCI_VENDOR_ID_SI,
@@ -777,12 +756,16 @@
 			continue;
 
 		host_dev = host;
-		dma_capability = SiSHostChipInfo[i].dma_capability;
+		chipset_family = SiSHostChipInfo[i].chipset_family;
 		printk(SiSHostChipInfo[i].name);
 		printk("\n");
 
+#ifdef DEBUG
+		sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
+
 		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
-			byte latency = (dma_capability == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
 			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
 		}
 	}
@@ -792,7 +775,7 @@
 	   2/ tell old chips to allow per drive IDE timings */
 	if (host_dev) {
 		byte reg;
-		switch(dma_capability) {
+		switch(chipset_family) {
 			case ATA_133:
 			case ATA_100:
 				/* Set compatibility bit */
@@ -847,7 +830,7 @@
 	byte mask = hwif->unit ? 0x20 : 0x10;
 	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
 
-	if (dma_capability >= ATA_66) {
+	if (chipset_family >= ATA_66) {
 		ata66 = (reg48h & mask) ? 0 : 1;
 	}
         return ata66;
@@ -866,7 +849,7 @@
 
 	if (host_dev) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (dma_capability > ATA_16) {
+		if (chipset_family > ATA_16) {
 			hwif->autodma = noautodma ? 0 : 1;
 			hwif->highmem = 1;
 			hwif->dmaproc = &sis5513_dmaproc;
diff -urN linux-2.5.8-pre2/drivers/ide/trm290.c linux-2.5.8-pre3/drivers/ide/trm290.c
--- linux-2.5.8-pre2/drivers/ide/trm290.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/trm290.c	Tue Apr  9 18:35:19 2002
@@ -248,8 +248,19 @@
 
 	if ((reg & 0x10))
 		hwif->irq = hwif->unit ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
+	else {
+		static int primary_irq = 0;
+
+		/* Ugly way to let the primary and secondary channel on the
+		 * chip use the same IRQ line.
+		 */
+
+		if (hwif->unit == ATA_PRIMARY)
+			primary_irq = hwif->irq;
+		else if (!hwif->irq)
+			hwif->irq = primary_irq;
+	}
+
 	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
diff -urN linux-2.5.8-pre2/drivers/ide/umc8672.c linux-2.5.8-pre3/drivers/ide/umc8672.c
--- linux-2.5.8-pre2/drivers/ide/umc8672.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ide/umc8672.c	Tue Apr  9 18:35:19 2002
@@ -146,7 +146,7 @@
 	{
 		__restore_flags(flags);	/* local CPU only */
 		printk ("umc8672: not found\n");
-		return;  
+		return;
 	}
 	outb_p (0xa5,0x108); /* disable umc */
 
@@ -158,7 +158,6 @@
 	ide_hwifs[1].chipset = ide_umc8672;
 	ide_hwifs[0].tuneproc = &tune_umc;
 	ide_hwifs[1].tuneproc = &tune_umc;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].unit = 1;
+	ide_hwifs[0].unit = ATA_PRIMARY;
+	ide_hwifs[1].unit = ATA_SECONDARY;
 }
diff -urN linux-2.5.8-pre2/drivers/ieee1394/Config.help linux-2.5.8-pre3/drivers/ieee1394/Config.help
--- linux-2.5.8-pre2/drivers/ieee1394/Config.help	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/Config.help	Tue Apr  9 18:35:19 2002
@@ -90,6 +90,31 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called raw1394.o.
 
+CONFIG_IEEE1394_ETH1394
+  Extremely Experimental! This driver is a Linux specific way to use your
+  IEEE1394 Host as an Ethernet type device. This is _NOT_ IP1394.
+
+CONFIG_IEEE1394_AMDTP
+  This option enables the Audio & Music Data Transmission Protocol
+  (IEC61883-6) driver, which implements audio transmission over
+  IEEE1394.
+
+  The userspace interface is documented in amdtp.h.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called amdtp.o.
+
+CONFIG_IEEE1394_CMP
+  This option enables the Connection Management Procedures
+  (IEC61883-1) driver, which implements input and output plugs.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called amdtp.o.
+
 CONFIG_IEEE1394_VERBOSEDEBUG
   If you say Y here, you will get very verbose debugging logs from the
   subsystem which includes a dump of the header of every sent and
@@ -99,4 +124,3 @@
 
   Say Y if you really want or need the debugging output, everyone else
   says N.
-
diff -urN linux-2.5.8-pre2/drivers/ieee1394/Config.in linux-2.5.8-pre3/drivers/ieee1394/Config.in
--- linux-2.5.8-pre2/drivers/ieee1394/Config.in	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/Config.in	Tue Apr  9 18:35:19 2002
@@ -19,8 +19,14 @@
 	comment "Protocol Drivers"
 	dep_tristate '  OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
+	dep_tristate '  Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394
 	dep_tristate '  OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
 	dep_tristate '  Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
+	dep_tristate '  IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394
+
+	if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
+	    dep_tristate '    IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP
+	fi
 
 	bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
     fi
diff -urN linux-2.5.8-pre2/drivers/ieee1394/Makefile linux-2.5.8-pre3/drivers/ieee1394/Makefile
--- linux-2.5.8-pre2/drivers/ieee1394/Makefile	Mon Mar 18 12:37:19 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/Makefile	Tue Apr  9 18:35:19 2002
@@ -4,7 +4,7 @@
 
 O_TARGET := ieee1394drv.o
 
-export-objs := ieee1394_core.o ohci1394.o
+export-objs := ieee1394_core.o ohci1394.o cmp.o
 
 list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
@@ -17,6 +17,9 @@
 obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
 obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
 obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
+obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
+obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o
+obj-$(CONFIG_IEEE1394_CMP) += cmp.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.5.8-pre2/drivers/ieee1394/amdtp.c linux-2.5.8-pre3/drivers/ieee1394/amdtp.c
--- linux-2.5.8-pre2/drivers/ieee1394/amdtp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/ieee1394/amdtp.c	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,1141 @@
+/* -*- c-basic-offset: 8 -*-
+ *
+ * amdtp.c - Audio and Music Data Transmission Protocol Driver
+ * Copyright (C) 2001 Kristian Høgsberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* OVERVIEW
+ * --------
+ *
+ * The AMDTP driver is designed to expose the IEEE1394 bus as a
+ * regular OSS soundcard, i.e. you can link /dev/dsp to /dev/amdtp and
+ * then your favourite MP3 player, game or whatever sound program will
+ * output to an IEEE1394 isochronous channel.  The signal destination
+ * could be a set of IEEE1394 loudspeakers (if and when such things
+ * become available) or an amplifier with IEEE1394 input (like the
+ * Sony STR-LSA1).  The driver only handles the actual streaming, some
+ * connection management is also required for this to actually work.
+ * That is outside the scope of this driver, and furthermore it is not
+ * really standardized yet.
+ *
+ * The Audio and Music Data Tranmission Protocol is avaiable at
+ *
+ *     http://www.1394ta.org/Download/Technology/Specifications/2001/AM20Final-jf2.pdf
+ *
+ *
+ * TODO
+ * ----
+ *
+ * - We should be able to change input sample format between LE/BE, as
+ *   we already shift the bytes around when we construct the iso
+ *   packets.
+ *
+ * - Fix DMA stop after bus reset!
+ *
+ * - Implement poll.
+ *
+ * - Clean up iso context handling in ohci1394.
+ *
+ *
+ * MAYBE TODO
+ * ----------
+ *
+ * - Receive data for local playback or recording.  Playback requires
+ *   soft syncing with the sound card.
+ *
+ * - Signal processing, i.e. receive packets, do some processing, and
+ *   transmit them again using the same packet structure and timestamps
+ *   offset by processing time.
+ *
+ * - Maybe make an ALSA interface, that is, create a file_ops
+ *   implementation that recognizes ALSA ioctls and uses defaults for
+ *   things that can't be controlled through ALSA (iso channel).
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include "hosts.h"
+#include "highlevel.h"
+#include "ieee1394.h"
+#include "ieee1394_core.h"
+#include "ohci1394.h"
+
+#include "amdtp.h"
+#include "cmp.h"
+
+#define FMT_AMDTP 0x10
+#define FDF_AM824 0x00
+#define FDF_SFC_32KHZ  0x00 /* 32kHz */
+#define FDF_SFC_44K1HZ 0x01 /* 44.1kHz */
+#define FDF_SFC_48KHZ  0x02 /* 44.1kHz */
+
+struct descriptor_block {
+	struct output_more_immediate {
+		u32 control;
+		u32 pad0;
+		u32 skip;
+		u32 pad1;
+		u32 header[4];
+	} header_desc;
+
+	struct output_last {
+		u32 control;
+		u32 data_address;
+		u32 branch;
+		u32 status;
+	} payload_desc;
+};
+
+struct packet {
+	struct descriptor_block *db;
+	dma_addr_t db_bus;
+	quadlet_t *payload;
+	dma_addr_t payload_bus;
+};
+
+struct fraction {
+	int integer;
+	int numerator;
+	int denominator;
+	int counter;
+};
+
+#define PACKET_LIST_SIZE 256
+#define MAX_PACKET_LISTS 4
+
+struct packet_list {
+	struct list_head link;
+	int last_cycle_count;
+	struct packet packets[PACKET_LIST_SIZE];
+};
+
+#define BUFFER_SIZE 128
+
+/* This implements a circular buffer for incoming samples. */
+
+struct buffer {
+	int head, tail, length, size;
+	unsigned char data[0];
+};
+
+struct stream {
+	int iso_channel;
+	int format;
+	int rate;
+	int dimension;
+	int fdf;
+	struct cmp_pcr *opcr;
+
+	/* Input samples are copied here. */
+	struct buffer *input;
+
+	/* ISO Packer state */
+	unsigned char dbc;
+	struct packet_list *current_packet_list;
+	int current_packet;
+	struct fraction packet_size_fraction;
+
+	/* We use these to generate control bits when we are packing
+	 * iec958 data.
+	 */
+	int iec958_frame_count;
+	int iec958_rate_code;
+
+	/* The cycle_count and cycle_offset fields are used for the
+	 * synchronization timestamps (syt) in the cip header.  They
+	 * are incremented by at least a cycle every time we put a
+	 * time stamp in a packet.  As we dont time stamp all
+	 * packages, cycle_count isn't updated in every cycle, and
+	 * sometimes it's incremented by 2.  Thus, we have
+	 * cycle_count2, which is simply incremented by one with each
+	 * packet, so we can compare it to the transmission time
+	 * written back in the dma programs.
+	 */
+	atomic_t cycle_count, cycle_count2;
+	int cycle_offset;
+	struct fraction syt_fraction;
+	int syt_interval;
+	int stale_count;
+
+	/* Theses fields control the sample output to the DMA engine.
+	 * The dma_packet_lists list holds packet lists currently
+	 * queued for dma; the head of the list is currently being
+	 * processed.  The last program in a packet list generates an
+	 * interrupt, which removes the head from dma_packet_lists and
+	 * puts it back on the free list.
+	 */
+	struct list_head dma_packet_lists;
+	struct list_head free_packet_lists;
+        wait_queue_head_t packet_list_wait;
+	spinlock_t packet_list_lock;
+	int iso_context;
+	struct pci_pool *descriptor_pool, *packet_pool;
+
+	/* Streams at a host controller are chained through this field. */
+	struct list_head link;
+	struct amdtp_host *host;
+};
+
+struct amdtp_host {
+	struct hpsb_host *host;
+	struct ti_ohci *ohci;
+	struct list_head stream_list;
+	spinlock_t stream_list_lock;
+	struct list_head link;
+};
+
+static struct hpsb_highlevel *amdtp_highlevel;
+static LIST_HEAD(host_list);
+static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
+
+/* FIXME: This doesn't belong here... */
+
+#define OHCI1394_CONTEXT_CYCLE_MATCH 0x80000000
+#define OHCI1394_CONTEXT_RUN         0x00008000
+#define OHCI1394_CONTEXT_WAKE        0x00001000
+#define OHCI1394_CONTEXT_DEAD        0x00000800
+#define OHCI1394_CONTEXT_ACTIVE      0x00000400
+
+static inline int ohci1394_alloc_it_ctx(struct ti_ohci *ohci)
+{
+	int i;
+
+	for (i = 0; i < ohci->nb_iso_xmit_ctx; i++)
+		if (!test_and_set_bit(i, &ohci->it_ctx_usage))
+			return i;
+
+	return -EBUSY;
+}
+	
+static inline void ohci1394_free_it_ctx(struct ti_ohci *ohci, int ctx)
+{
+	clear_bit(ctx, &ohci->it_ctx_usage);
+}
+
+
+void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx,
+			   dma_addr_t first_cmd, int z, int cycle_match)
+{
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx);
+	reg_write(ohci, OHCI1394_IsoXmitCommandPtr + ctx * 16, first_cmd | z);
+	reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16, ~0);
+	wmb();
+	reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16,
+		  OHCI1394_CONTEXT_CYCLE_MATCH | (cycle_match << 16) |
+		  OHCI1394_CONTEXT_RUN);
+}
+
+void ohci1394_wake_it_ctx(struct ti_ohci *ohci, int ctx)
+{
+	reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16,
+		  OHCI1394_CONTEXT_WAKE);
+}
+
+void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx)
+{
+	u32 control;
+	int wait;
+
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << ctx);
+	reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16,
+		  OHCI1394_CONTEXT_RUN);
+	wmb();
+
+	for (wait = 0; wait < 5; wait++) {
+		control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16);
+		if ((control & OHCI1394_CONTEXT_ACTIVE) == 0)
+			break;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+}
+
+/* Note: we can test if free_packet_lists is empty without aquiring
+ * the packet_list_lock.  The interrupt handler only adds to the free
+ * list, there is no race condition between testing the list non-empty
+ * and acquiring the lock.
+ */
+
+static struct packet_list *stream_get_free_packet_list(struct stream *s)
+{
+	struct packet_list *pl;
+	unsigned long flags;
+
+	if (list_empty(&s->free_packet_lists))
+		return NULL;
+
+	spin_lock_irqsave(&s->packet_list_lock, flags);
+	pl = list_entry(s->free_packet_lists.next, struct packet_list, link);
+	list_del(&pl->link);
+	spin_unlock_irqrestore(&s->packet_list_lock, flags);
+
+	return pl;
+}
+
+static void stream_put_dma_packet_list(struct stream *s,
+				       struct packet_list *pl)
+{
+	unsigned long flags;
+	struct packet_list *prev;
+
+	/* Remember the cycle_count used for timestamping the last packet. */
+	pl->last_cycle_count = atomic_read(&s->cycle_count2) - 1;
+	pl->packets[PACKET_LIST_SIZE - 1].db->payload_desc.branch = 0;
+
+	spin_lock_irqsave(&s->packet_list_lock, flags);
+	list_add_tail(&pl->link, &s->dma_packet_lists);
+	spin_unlock_irqrestore(&s->packet_list_lock, flags);
+
+	prev = list_entry(pl->link.prev, struct packet_list, link);
+	if (pl->link.prev != &s->dma_packet_lists) {
+		struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1];
+		last->db->payload_desc.branch = pl->packets[0].db_bus | 3;
+		ohci1394_wake_it_ctx(s->host->ohci, s->iso_context);
+	}
+	else {
+		u32 syt, cycle_count;
+
+		cycle_count = reg_read(s->host->host->hostdata,
+				       OHCI1394_IsochronousCycleTimer) >> 12;
+		syt = (pl->packets[0].payload[1] >> 12) & 0x0f;
+		cycle_count = (cycle_count & ~0x0f) + 32 + syt;
+		if ((cycle_count & 0x1fff) >= 8000)
+			cycle_count = cycle_count - 8000 + 0x2000;
+
+		ohci1394_start_it_ctx(s->host->ohci, s->iso_context,
+				      pl->packets[0].db_bus, 3,
+				      cycle_count & 0x7fff);
+	}
+}
+
+static void stream_shift_packet_lists(struct stream *s)
+{
+	struct packet_list *pl;
+	struct packet *last;
+	int diff;
+
+	if (list_empty(&s->dma_packet_lists)) {
+		HPSB_ERR("empty dma_packet_lists in %s", __FUNCTION__);
+		return;
+	}
+
+	/* Now that we know the list is non-empty, we can get the head
+	 * of the list without locking, because the process context
+	 * only adds to the tail.  
+	 */
+	pl = list_entry(s->dma_packet_lists.next, struct packet_list, link);
+	last = &pl->packets[PACKET_LIST_SIZE - 1];
+
+	/* This is weird... if we stop dma processing in the middle of
+	 * a packet list, the dma context immediately generates an
+	 * interrupt if we enable it again later.  This only happens
+	 * when amdtp_release is interrupted while waiting for dma to
+	 * complete, though.  Anyway, we detect this by seeing that
+	 * the status of the dma descriptor that we expected an
+	 * interrupt from is still 0.
+	 */
+	if (last->db->payload_desc.status == 0) {
+		HPSB_INFO("weird interrupt...");
+		return;
+	}		
+
+	/* If the last descriptor block does not specify a branch
+	 * address, we have a sample underflow.
+	 */
+	if (last->db->payload_desc.branch == 0)
+		HPSB_INFO("FIXME: sample underflow...");
+
+	/* Here we check when (which cycle) the last packet was sent
+	 * and compare it to what the iso packer was using at the
+	 * time.  If there is a mismatch, we adjust the cycle count in
+	 * the iso packer.  However, there are still up to
+	 * MAX_PACKET_LISTS packet lists queued with bad time stamps,
+	 * so we disable time stamp monitoring for the next
+	 * MAX_PACKET_LISTS packet lists.
+	 */
+	diff = (last->db->payload_desc.status - pl->last_cycle_count) & 0xf;
+	if (diff > 0 && s->stale_count == 0) {
+		atomic_add(diff, &s->cycle_count);
+		atomic_add(diff, &s->cycle_count2);
+		s->stale_count = MAX_PACKET_LISTS;
+	}
+
+	if (s->stale_count > 0)
+		s->stale_count--;
+
+	/* Finally, we move the packet list that was just processed
+	 * back to the free list, and notify any waiters.
+	 */
+	spin_lock(&s->packet_list_lock);
+	list_del(&pl->link);
+	list_add_tail(&pl->link, &s->free_packet_lists);
+	spin_unlock(&s->packet_list_lock);
+
+	wake_up_interruptible(&s->packet_list_wait);
+}
+
+static struct packet *stream_current_packet(struct stream *s)
+{
+	if (s->current_packet_list == NULL &&
+	    (s->current_packet_list = stream_get_free_packet_list(s)) == NULL)
+		return NULL;
+
+	return &s->current_packet_list->packets[s->current_packet];
+}
+	
+static void stream_queue_packet(struct stream *s)
+{
+	s->current_packet++;
+	if (s->current_packet == PACKET_LIST_SIZE) {
+		stream_put_dma_packet_list(s, s->current_packet_list);
+		s->current_packet_list = NULL;
+		s->current_packet = 0;
+	}
+}
+
+/* Integer fractional math.  When we transmit a 44k1Hz signal we must
+ * send 5 41/80 samples per isochronous cycle, as these occur 8000
+ * times a second.  Of course, we must send an integral number of
+ * samples in a packet, so we use the integer math to alternate
+ * between sending 5 and 6 samples per packet.
+ */
+
+static void fraction_init(struct fraction *f, int numerator, int denominator)
+{
+	f->integer = numerator / denominator;
+	f->numerator = numerator % denominator;
+	f->denominator = denominator;
+	f->counter = 0;
+}
+
+static int fraction_next_size(struct fraction *f)
+{
+	return f->integer + ((f->counter + f->numerator) / f->denominator);
+}
+
+static void fraction_inc(struct fraction *f)
+{
+	f->counter = (f->counter + f->numerator) % f->denominator;
+}
+
+static void amdtp_irq_handler(int card, quadlet_t isoRecvIntEvent,
+			      quadlet_t isoXmitIntEvent, void *data)
+{
+	struct amdtp_host *host = data;
+	struct list_head *lh;
+	struct stream *s = NULL;
+
+	spin_lock(&host->stream_list_lock);
+	list_for_each(lh, &host->stream_list) {
+		s = list_entry(lh, struct stream, link);
+		if (isoXmitIntEvent & (1 << s->iso_context))
+			break;
+	}
+	spin_unlock(&host->stream_list_lock);
+
+	if (s != NULL)
+		stream_shift_packet_lists(s);
+}
+
+void packet_initialize(struct packet *p, struct packet *next)
+{
+	/* Here we initialize the dma descriptor block for
+	 * transferring one iso packet.  We use two descriptors per
+	 * packet: an OUTPUT_MORE_IMMMEDIATE descriptor for the
+	 * IEEE1394 iso packet header and an OUTPUT_LAST descriptor
+	 * for the payload.
+	 */
+
+	p->db->header_desc.control =
+		DMA_CTL_OUTPUT_MORE | DMA_CTL_IMMEDIATE | 8;
+	p->db->header_desc.skip = 0;
+
+	if (next) {
+		p->db->payload_desc.control = 
+			DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH;
+		p->db->payload_desc.branch = next->db_bus | 3;
+	}
+	else {
+		p->db->payload_desc.control = 
+			DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH |
+			DMA_CTL_UPDATE | DMA_CTL_IRQ;
+		p->db->payload_desc.branch = 0;
+	}
+	p->db->payload_desc.data_address = p->payload_bus;
+	p->db->payload_desc.status = 0;
+}
+
+struct packet_list *packet_list_alloc(struct stream *s)
+{
+	int i;
+	struct packet_list *pl;
+	struct packet *next;
+
+	pl = kmalloc(sizeof *pl, SLAB_KERNEL);
+	if (pl == NULL)
+		return NULL;
+
+	for (i = 0; i < PACKET_LIST_SIZE; i++) {
+		struct packet *p = &pl->packets[i];
+		p->db = pci_pool_alloc(s->descriptor_pool, SLAB_KERNEL,
+				       &p->db_bus);
+		p->payload = pci_pool_alloc(s->packet_pool, SLAB_KERNEL,
+					    &p->payload_bus);
+	}
+
+	for (i = 0; i < PACKET_LIST_SIZE; i++) {
+		if (i < PACKET_LIST_SIZE - 1)
+			next = &pl->packets[i + 1];
+		else 
+			next = NULL;
+		packet_initialize(&pl->packets[i], next);
+	}
+
+	return pl;
+}
+
+void packet_list_free(struct packet_list *pl, struct stream *s)
+{
+	int i;
+
+	for (i = 0; i < PACKET_LIST_SIZE; i++) {
+		struct packet *p = &pl->packets[i];
+		pci_pool_free(s->descriptor_pool, p->db, p->db_bus);
+		pci_pool_free(s->packet_pool, p->payload, p->payload_bus);
+	}
+	kfree(pl);
+}
+
+static struct buffer *buffer_alloc(int size)
+{
+	struct buffer *b;
+
+	b = kmalloc(sizeof *b + size, SLAB_KERNEL);
+	b->head = 0;
+	b->tail = 0;
+	b->length = 0;
+	b->size = size;
+
+	return b;
+}
+
+static unsigned char *buffer_get_bytes(struct buffer *buffer, int size)
+{
+	unsigned char *p;
+
+	if (buffer->head + size > buffer->size)
+		BUG();
+
+	p = &buffer->data[buffer->head];
+	buffer->head += size;
+	if (buffer->head == buffer->size)
+		buffer->head = 0;
+	buffer->length -= size;
+
+	return p;
+}
+
+static unsigned char *buffer_put_bytes(struct buffer *buffer,
+				       int max, int *actual)
+{
+	int length;
+	unsigned char *p;
+
+	p = &buffer->data[buffer->tail];
+	length = min(buffer->size - buffer->length, max);
+	if (buffer->tail + length < buffer->size) {
+		*actual = length;
+		buffer->tail += length;
+	}
+	else {
+		*actual = buffer->size - buffer->tail;
+		 buffer->tail = 0;
+	}
+
+	buffer->length += *actual;
+	return p;
+}
+
+static u32 get_iec958_header_bits(struct stream *s, int sub_frame, u32 sample)
+{
+	int csi, parity, shift;
+	int block_start;
+	u32 bits;
+
+	switch (s->iec958_frame_count) {
+	case 1:
+		csi = s->format == AMDTP_FORMAT_IEC958_AC3;
+		break;
+	case 2:
+	case 9:
+		csi = 1;
+		break;
+	case 24 ... 27:
+		csi = (s->iec958_rate_code >> (27 - s->iec958_frame_count)) & 0x01;
+		break;
+	default:
+		csi = 0;
+		break;
+	}
+
+	block_start = (s->iec958_frame_count == 0 && sub_frame == 0);
+
+	/* The parity bit is the xor of the sample bits and the
+	 * channel status info bit. */
+	for (shift = 16, parity = sample ^ csi; shift > 0; shift >>= 1)
+		parity ^= (parity >> shift);
+
+	bits =  (block_start << 5) |		/* Block start bit */
+		((sub_frame == 0) << 4) |	/* Subframe bit */
+		((parity & 1) << 3) |		/* Parity bit */
+		(csi << 2);			/* Channel status info bit */
+
+	return bits;
+}
+
+static u32 get_header_bits(struct stream *s, int sub_frame, u32 sample)
+{
+	switch (s->format) {
+	case AMDTP_FORMAT_IEC958_PCM:
+	case AMDTP_FORMAT_IEC958_AC3:
+		return get_iec958_header_bits(s, sub_frame, sample);
+		
+	case AMDTP_FORMAT_RAW:
+		return 0x40000000;
+
+	default:
+		return 0;
+	}
+}
+
+
+static void fill_packet(struct stream *s, struct packet *packet, int nevents)
+{
+	int size, node_id, i, j;
+	quadlet_t *event;
+	unsigned char *p;
+	u32 control, sample, bits;
+	int syt_index, syt, next;
+
+	size = (nevents * s->dimension + 2) * sizeof(quadlet_t);
+	node_id = s->host->host->node_id & 0x3f;
+
+	/* Update DMA descriptors */
+	packet->db->payload_desc.status = 0;
+	control = packet->db->payload_desc.control & 0xffff0000;
+	packet->db->payload_desc.control = control | size;
+
+	/* Fill IEEE1394 headers */
+	packet->db->header_desc.header[0] =
+		(SPEED_100 << 16) | (0x01 << 14) | 
+		(s->iso_channel << 8) | (TCODE_ISO_DATA << 4);
+	packet->db->header_desc.header[1] = size << 16;
+	
+	/* Fill cip header */
+	syt_index = s->dbc & (s->syt_interval - 1);
+	if (syt_index == 0 || syt_index + nevents > s->syt_interval) {
+		syt = ((atomic_read(&s->cycle_count) << 12) | 
+		       s->cycle_offset) & 0xffff;
+		next = fraction_next_size(&s->syt_fraction) + s->cycle_offset;
+		/* This next addition should be modulo 8000 (0x1f40),
+		 * but we only use the lower 4 bits of cycle_count, so
+		 * we dont need the modulo. */
+		atomic_add(next / 3072, &s->cycle_count);
+		s->cycle_offset = next % 3072;
+		fraction_inc(&s->syt_fraction);
+	}
+	else {
+		syt = 0xffff;
+		next = 0;
+	}
+	atomic_inc(&s->cycle_count2);
+
+	packet->payload[0] = cpu_to_be32((node_id << 24) | (s->dimension << 16) | s->dbc);
+	packet->payload[1] = cpu_to_be32((1 << 31) | (FMT_AMDTP << 24) | (s->fdf << 16) | syt);
+
+	/* Fill payload */
+	for (i = 0, event = &packet->payload[2]; i < nevents; i++) {
+
+		for (j = 0; j < s->dimension; j++) {
+			p = buffer_get_bytes(s->input, 2);
+			sample = (p[1] << 16) | (p[0] << 8);
+			bits = get_header_bits(s, j, sample);
+			event[j] = cpu_to_be32((bits << 24) | sample);
+		}
+
+		event += s->dimension;
+		if (++s->iec958_frame_count == 192)
+			s->iec958_frame_count = 0;
+	}
+
+	s->dbc += nevents;
+}
+
+static void stream_flush(struct stream *s)
+{
+	struct packet *p;
+	int nevents;
+
+	while (nevents = fraction_next_size(&s->packet_size_fraction),
+	       p = stream_current_packet(s),
+	       nevents * s->dimension * 2 <= s->input->length && p != NULL) {
+		fill_packet(s, p, nevents);
+		fraction_inc(&s->packet_size_fraction);
+		stream_queue_packet(s);
+	}
+}
+
+static int stream_alloc_packet_lists(struct stream *s)
+{
+	int max_nevents, max_packet_size, i;
+
+	max_nevents = s->packet_size_fraction.integer;
+	if (s->packet_size_fraction.numerator > 0)
+		max_nevents++;
+
+	max_packet_size = max_nevents * s->dimension * 4 + 8;
+	s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev,
+					 max_packet_size, 0, 0, SLAB_KERNEL);
+	if (s->packet_pool == NULL)
+		return -1;
+
+	INIT_LIST_HEAD(&s->free_packet_lists);
+	INIT_LIST_HEAD(&s->dma_packet_lists);
+	for (i = 0; i < MAX_PACKET_LISTS; i++) {
+		struct packet_list *pl = packet_list_alloc(s);
+		if (pl == NULL)
+			break;
+		list_add_tail(&pl->link, &s->free_packet_lists);
+	}
+
+	return i < MAX_PACKET_LISTS ? -1 : 0;
+}
+
+static void stream_free_packet_lists(struct stream *s)
+{
+	struct list_head *lh, *next;
+
+	if (s->current_packet_list != NULL)
+		packet_list_free(s->current_packet_list, s);
+	list_for_each_safe(lh, next, &s->dma_packet_lists)
+		packet_list_free(list_entry(lh, struct packet_list, link), s);
+	list_for_each_safe(lh, next, &s->free_packet_lists)
+		packet_list_free(list_entry(lh, struct packet_list, link), s);
+	if (s->packet_pool != NULL)
+		pci_pool_destroy(s->packet_pool);
+
+	s->current_packet_list = NULL;
+	INIT_LIST_HEAD(&s->free_packet_lists);
+	INIT_LIST_HEAD(&s->dma_packet_lists);
+	s->packet_pool = NULL;
+}
+
+static void plug_update(struct cmp_pcr *plug, void *data)
+{
+	struct stream *s = data;
+
+	HPSB_INFO("plug update: p2p_count=%d, channel=%d",
+		  plug->p2p_count, plug->channel);
+	s->iso_channel = plug->channel;
+	if (plug->p2p_count > 0) {
+		/* start streaming */
+	}
+	else {
+		/* stop streaming */
+	}
+}
+
+static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg)
+{
+	if (cfg->format <= AMDTP_FORMAT_IEC958_AC3)
+		s->format = cfg->format;
+	else
+		return -EINVAL;
+
+	switch (cfg->rate) {
+	case 32000:
+		s->syt_interval = 8;
+		s->fdf = FDF_SFC_32KHZ;
+		s->iec958_rate_code = 0x0c;
+		s->rate = cfg->rate;
+		break;
+	case 44100:
+		s->syt_interval = 8;
+		s->fdf = FDF_SFC_44K1HZ;
+		s->iec958_rate_code = 0x00;
+		s->rate = cfg->rate;
+		break;
+	case 48000:
+		s->syt_interval = 8;
+		s->fdf = FDF_SFC_48KHZ;
+		s->iec958_rate_code = 0x04;
+		s->rate = cfg->rate;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	fraction_init(&s->packet_size_fraction, s->rate, 8000);
+
+	/* The syt_fraction is initialized to the number of ticks
+	 * between syt_interval events.  The number of ticks per
+	 * second is 24.576e6, so the number of ticks between
+	 * syt_interval events is 24.576e6 * syt_interval / rate.
+	 */
+	fraction_init(&s->syt_fraction, 24576000 * s->syt_interval, s->rate);
+
+	/* When using the AM824 raw subformat we can stream signals of
+	 * any dimension.  The IEC958 subformat, however, only
+	 * supports 2 channels.
+	 */
+	if (s->format == AMDTP_FORMAT_RAW || cfg->dimension == 2)
+		s->dimension = cfg->dimension;
+	else
+		return -EINVAL;
+
+	if (s->opcr != NULL) {
+		cmp_unregister_opcr(s->host->host, s->opcr);
+		s->opcr = NULL;
+	}
+
+	switch(cmd) {
+	case AMDTP_IOC_PLUG:
+		s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug,
+					   /*payload*/ 12, plug_update, s);
+		if (s->opcr == NULL)
+			return -EINVAL;
+		s->iso_channel = s->opcr->channel;
+		break;
+
+	case AMDTP_IOC_CHANNEL:
+		if (cfg->u.channel >= 0 && cfg->u.channel < 64)
+			s->iso_channel = cfg->u.channel;
+		else
+			return -EINVAL;
+		break;
+	}
+
+	/* The ioctl settings were all valid, so we realloc the packet
+	 * lists to make sure the packet size is big enough.
+	 */
+	if (s->packet_pool != NULL)
+		stream_free_packet_lists(s);
+
+	if (stream_alloc_packet_lists(s) < 0) {
+		stream_free_packet_lists(s);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+struct stream *stream_alloc(struct amdtp_host *host)
+{
+	struct stream *s;
+	unsigned long flags;
+	const int transfer_delay = 8651; /* approx 352 us */
+
+        s = kmalloc(sizeof(struct stream), SLAB_KERNEL);
+        if (s == NULL)
+                return NULL;
+
+        memset(s, 0, sizeof(struct stream));
+	s->host = host;
+
+	s->input = buffer_alloc(BUFFER_SIZE);
+	if (s->input == NULL) {
+		kfree(s);
+		return NULL;
+	}
+
+	s->cycle_offset = transfer_delay % 3072;
+	atomic_set(&s->cycle_count, transfer_delay / 3072);
+	atomic_set(&s->cycle_count2, 0);
+
+	s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev,
+					     sizeof(struct descriptor_block),
+					     16, 0, SLAB_KERNEL);
+	if (s->descriptor_pool == NULL) {
+		kfree(s->input);
+		kfree(s);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&s->free_packet_lists);
+	INIT_LIST_HEAD(&s->dma_packet_lists);
+
+        init_waitqueue_head(&s->packet_list_wait);
+        spin_lock_init(&s->packet_list_lock);
+
+	s->iso_context = ohci1394_alloc_it_ctx(host->ohci);
+	if (s->iso_context < 0) {
+		pci_pool_destroy(s->descriptor_pool);
+		kfree(s->input);
+		kfree(s);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&host->stream_list_lock, flags);
+	list_add_tail(&s->link, &host->stream_list);
+	spin_unlock_irqrestore(&host->stream_list_lock, flags);
+
+	return s;
+}
+
+void stream_free(struct stream *s)
+{
+	unsigned long flags;
+
+	/* Stop the DMA.  We wait for the dma packet list to become
+	 * empty and let the dma controller run out of programs.  This
+	 * seems to be more reliable than stopping it directly, since
+	 * that sometimes generates an it transmit interrupt if we
+	 * later re-enable the context.
+	 */
+	wait_event_interruptible(s->packet_list_wait, 
+				 list_empty(&s->dma_packet_lists));
+
+	ohci1394_stop_it_ctx(s->host->ohci, s->iso_context);
+	ohci1394_free_it_ctx(s->host->ohci, s->iso_context);
+
+	if (s->opcr != NULL)
+		cmp_unregister_opcr(s->host->host, s->opcr);
+
+	spin_lock_irqsave(&s->host->stream_list_lock, flags);
+	list_del(&s->link);
+	spin_unlock_irqrestore(&s->host->stream_list_lock, flags);
+
+	kfree(s->input);
+
+	stream_free_packet_lists(s);
+	pci_pool_destroy(s->descriptor_pool);
+
+	kfree(s);
+}
+
+/* File operations */
+
+static ssize_t amdtp_write(struct file *file, const char *buffer, size_t count,
+			   loff_t *offset_is_ignored)
+{
+	struct stream *s = file->private_data;
+	unsigned char *p;
+	int i, length;
+	
+	if (s->packet_pool == NULL)
+		return -EBADFD;
+
+	/* Fill the circular buffer from the input buffer and call the
+	 * iso packer when the buffer is full.  The iso packer may
+	 * leave bytes in the buffer for two reasons: either the
+	 * remaining bytes wasn't enough to build a new packet, or
+	 * there were no free packet lists.  In the first case we
+	 * re-fill the buffer and call the iso packer again or return
+	 * if we used all the data from userspace.  In the second
+	 * case, the wait_event_interruptible will block until the irq
+	 * handler frees a packet list.
+	 */
+
+	for (i = 0; i < count; i += length) {
+		p = buffer_put_bytes(s->input, count, &length);
+		copy_from_user(p, buffer + i, length);
+		if (s->input->length < s->input->size)
+			continue;
+		
+		stream_flush(s);
+		
+		if (s->current_packet_list == NULL &&
+		    wait_event_interruptible(s->packet_list_wait, 
+					     !list_empty(&s->free_packet_lists)))
+			return -EINTR;
+	}
+
+	return count;
+}
+
+static int amdtp_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct stream *s = file->private_data;
+	struct amdtp_ioctl cfg;
+	int new;
+
+	switch(cmd)
+	{
+	case AMDTP_IOC_PLUG:
+	case AMDTP_IOC_CHANNEL:
+		if (copy_from_user(&cfg, (struct amdtp_ioctl *) arg, sizeof cfg))
+			return -EFAULT;
+		else 
+			return stream_configure(s, cmd, &cfg);
+
+	case AMDTP_IOC_PING:
+		HPSB_INFO("ping: offsetting timpestamps %ld ticks", arg);
+		new = s->cycle_offset + arg;
+		s->cycle_offset = new % 3072;
+		atomic_add(new / 3072, &s->cycle_count);
+		return 0;
+
+	case AMDTP_IOC_ZAP:
+		while (MOD_IN_USE)
+			MOD_DEC_USE_COUNT;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int amdtp_open(struct inode *inode, struct file *file)
+{
+	struct amdtp_host *host;
+
+	/* FIXME: We just grab the first registered host */
+	spin_lock(&host_list_lock);
+	if (!list_empty(&host_list))
+		host = list_entry(host_list.next, struct amdtp_host, link);
+	else
+		host = NULL;
+	spin_unlock(&host_list_lock);
+
+	if (host == NULL)
+		return -ENODEV;
+
+	file->private_data = stream_alloc(host);
+	if (file->private_data == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int amdtp_release(struct inode *inode, struct file *file)
+{
+	struct stream *s = file->private_data;
+
+	stream_free(s);
+
+	return 0;
+}
+
+static struct file_operations amdtp_fops =
+{
+	owner:		THIS_MODULE,
+	write:		amdtp_write,
+	ioctl:		amdtp_ioctl,
+	open:		amdtp_open,
+	release:	amdtp_release
+};
+
+/* IEEE1394 Subsystem functions */
+
+static void amdtp_add_host(struct hpsb_host *host)
+{
+	struct amdtp_host *ah;
+
+	/* FIXME: check it's an ohci host. */
+
+	ah = kmalloc(sizeof *ah, SLAB_KERNEL);
+	ah->host = host;
+	ah->ohci = host->hostdata;
+	INIT_LIST_HEAD(&ah->stream_list);
+	spin_lock_init(&ah->stream_list_lock);
+
+	spin_lock_irq(&host_list_lock);
+	list_add_tail(&ah->link, &host_list);
+	spin_unlock_irq(&host_list_lock);
+
+	ohci1394_hook_irq(ah->ohci, amdtp_irq_handler, ah);
+}
+
+static void amdtp_remove_host(struct hpsb_host *host)
+{
+	struct list_head *lh;
+	struct amdtp_host *ah;
+
+	spin_lock_irq(&host_list_lock);
+	list_for_each(lh, &host_list) {
+		if (list_entry(lh, struct amdtp_host, link)->host == host) {
+			list_del(lh);
+			break;
+		}
+	}
+	spin_unlock_irq(&host_list_lock);
+	
+	if (lh != &host_list) {
+		ah = list_entry(lh, struct amdtp_host, link);
+		ohci1394_unhook_irq(ah->ohci, amdtp_irq_handler, ah);
+		kfree(ah);
+	}
+	else
+		HPSB_ERR("remove_host: bogus ohci host: %p", host);
+}
+
+static struct hpsb_highlevel_ops amdtp_highlevel_ops = {
+	add_host:	amdtp_add_host,
+	remove_host:	amdtp_remove_host,
+};
+
+/* Module interface */
+
+MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
+MODULE_DESCRIPTION("Driver for Audio & Music Data Transmission Protocol "
+		   "on OHCI boards.");
+MODULE_SUPPORTED_DEVICE("amdtp");
+MODULE_LICENSE("GPL");
+
+static int __init amdtp_init_module (void)
+{
+	if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL,
+				      THIS_MODULE, &amdtp_fops)) {
+		HPSB_ERR("amdtp: unable to get minor device block");
+ 		return -EIO;
+ 	}
+
+	amdtp_highlevel = hpsb_register_highlevel ("amdtp",
+						   &amdtp_highlevel_ops);
+	if (amdtp_highlevel == NULL) {
+		HPSB_ERR("amdtp: unable to register highlevel ops");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
+		return -EIO;
+	}
+
+	HPSB_INFO("Loaded AMDTP driver");
+
+	return 0;
+}
+
+static void __exit amdtp_exit_module (void)
+{
+        hpsb_unregister_highlevel(amdtp_highlevel);
+        ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_EXPERIMENTAL);
+
+	HPSB_INFO("Unloaded AMDTP driver");
+}
+
+module_init(amdtp_init_module);
+module_exit(amdtp_exit_module);
diff -urN linux-2.5.8-pre2/drivers/ieee1394/amdtp.h linux-2.5.8-pre3/drivers/ieee1394/amdtp.h
--- linux-2.5.8-pre2/drivers/ieee1394/amdtp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/ieee1394/amdtp.h	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,75 @@
+/* -*- c-basic-offset: 8 -*- */
+
+#ifndef __AMDTP_H
+#define __AMDTP_H
+
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
+/* The userspace interface for the Audio & Music Data Transmission
+ * Protocol driver is really simple. First, open /dev/amdtp, use the
+ * ioctl to configure format, rate, dimension and either plug or
+ * channel, then start writing samples.
+ *
+ * The formats supported by the driver are listed below.
+ * AMDTP_FORMAT_RAW corresponds to the AM824 raw format, which can
+ * carry any number of channels, so use this if you're streaming
+ * multichannel audio.  The AMDTP_FORMAT_IEC958_PCM corresponds to the
+ * AM824 IEC958 encapsulation without the IEC958 data bit set, using
+ * AMDTP_FORMAT_IEC958_AC3 will transmit the samples with the data bit
+ * set, suitable for transmitting compressed AC-3 audio.
+ *
+ * The rate field specifies the transmission rate; supported values are
+ * AMDTP_RATE_32KHZ, AMDTP_RATE_44K1HZ and AMDTP_RATE_48KHZ.
+ *
+ * The dimension field specifies the dimension of the signal, that is,
+ * the number of audio channels.  Only AMDTP_FORMAT_RAW supports
+ * settings greater than 2.  
+ *
+ * The last thing to specify is either the isochronous channel to use
+ * or the output plug to connect to.  If you know what channel the
+ * destination device will listen on, you can specify the channel
+ * directly and use the AMDTP_IOC_CHANNEL ioctl.  However, if the
+ * destination device chooses the channel and uses the IEC61883-1 plug
+ * mechanism, you can specify an output plug to connect to.  The
+ * driver will pick up the channel number from the plug once the
+ * destination device locks the output plug control register.  In this
+ * case set the plug field and use the AMDTP_IOC_PLUG ioctl.
+ *
+ * Having configured the interface, the driver now accepts writes of
+ * regular 16 bit signed little endian samples, with the channels
+ * interleaved.  For example, 4 channels would look like:
+ *
+ *   | sample 0                                      | sample 1    ...
+ *   | ch. 0     | ch. 1     | ch. 2     | ch. 3     | ch. 0     | ...
+ *   | lsb | msb | lsb | msb | lsb | msb | lsb | msb | lsb | msb | ...
+ *
+ */
+
+/* We use '#' for our ioctl magic number because it's cool. */
+
+#define AMDTP_IOC_CHANNEL _IOW('#', 0, sizeof (struct amdtp_ioctl))
+#define AMDTP_IOC_PLUG    _IOW('#', 1, sizeof (struct amdtp_ioctl))
+#define AMDTP_IOC_PING    _IOW('#', 2, sizeof (struct amdtp_ioctl))
+#define AMDTP_IOC_ZAP     _IO('#', 3)
+
+enum {
+	AMDTP_FORMAT_RAW,
+	AMDTP_FORMAT_IEC958_PCM,
+	AMDTP_FORMAT_IEC958_AC3
+};
+
+enum {
+	AMDTP_RATE_32KHZ,
+	AMDTP_RATE_44K1HZ,
+	AMDTP_RATE_48KHZ,
+};
+
+struct amdtp_ioctl {
+	__u32 format;
+	__u32 rate;
+	__u32 dimension;
+	union { __u32 channel; __u32 plug; } u;
+};
+
+#endif /* __AMDTP_H */
diff -urN linux-2.5.8-pre2/drivers/ieee1394/cmp.c linux-2.5.8-pre3/drivers/ieee1394/cmp.c
--- linux-2.5.8-pre2/drivers/ieee1394/cmp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/ieee1394/cmp.c	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,348 @@
+/* -*- c-basic-offset: 8 -*-
+ *
+ * cmp.c - Connection Management Procedures
+ * Copyright (C) 2001 Kristian Høgsberg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* TODO
+ * ----
+ *
+ * - Implement IEC61883-1 output plugs and connection management.
+ *   This should probably be part of the general subsystem, as it could
+ *   be shared with dv1394.
+ *
+ * - Add IEC61883 unit directory when loading this module.  This
+ *   requires a run-time changeable config rom.
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include "hosts.h"
+#include "highlevel.h"
+#include "ieee1394.h"
+#include "ieee1394_core.h"
+#include "cmp.h"
+
+struct plug {
+	union {
+		struct cmp_pcr pcr;
+		quadlet_t quadlet;
+	} u;
+	void (*update)(struct cmp_pcr *plug, void *data);
+	void *data;
+};
+
+struct cmp_host {
+	struct hpsb_host *host;
+
+	union {
+		struct cmp_mpr ompr;
+		quadlet_t ompr_quadlet;
+	} u;
+	struct plug opcr[2];
+
+	union {
+		struct cmp_mpr impr;
+		quadlet_t impr_quadlet;
+	} v;
+	struct plug ipcr[2];
+
+	struct list_head link;
+};
+
+enum {
+	CMP_P2P_CONNECTION,
+	CMP_BC_CONNECTION
+};
+
+#define CSR_PCR_MAP      0x900
+#define CSR_PCR_MAP_END  0x9fc
+
+static struct hpsb_highlevel *cmp_highlevel;
+
+static LIST_HEAD(host_list);
+static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
+
+static struct cmp_host *
+lookup_cmp_host(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+	struct list_head *lh;
+	unsigned long flags;
+
+	ch = NULL;
+	spin_lock_irqsave(&host_list_lock, flags);
+	list_for_each(lh, &host_list) {
+		ch = list_entry(lh, struct cmp_host, link);
+		if (ch->host == host)
+			break;
+	}
+	spin_unlock_irqrestore(&host_list_lock, flags);
+
+	if (lh == &host_list)
+		return NULL;
+	else
+		return ch;
+}
+
+struct cmp_pcr *
+cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
+		  void (*update)(struct cmp_pcr *pcr, void *data),
+		  void *data)
+{
+	struct cmp_host *ch;
+	struct plug *plug;
+
+	ch = lookup_cmp_host(host);
+
+	if (opcr_number >= ch->u.ompr.nplugs ||
+	    ch->opcr[opcr_number].update != NULL)
+		return NULL;
+
+	plug = &ch->opcr[opcr_number];
+	plug->u.pcr.online = 1;
+	plug->u.pcr.bcast_count = 0;
+	plug->u.pcr.p2p_count = 0;
+	plug->u.pcr.overhead = 0;
+	plug->u.pcr.payload = payload;
+	plug->update = update;
+	plug->data = data;
+
+	return &plug->u.pcr;
+}
+
+void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr)
+{
+	struct cmp_host *ch;
+	struct plug *plug;
+
+	ch = lookup_cmp_host(host);
+	plug = (struct plug *)opcr;
+	if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
+
+	plug->u.pcr.online = 0;
+	plug->update = NULL;
+}
+
+static void reset_plugs(struct cmp_host *ch)
+{
+	int i;
+
+	ch->u.ompr.non_persistent_ext = 0xff;
+	for (i = 0; i < ch->u.ompr.nplugs; i++) {
+		ch->opcr[i].u.pcr.bcast_count = 0;
+		ch->opcr[i].u.pcr.p2p_count = 0;
+		ch->opcr[i].u.pcr.overhead = 0;
+	}
+}
+
+static void cmp_add_host(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+
+	ch = kmalloc(sizeof *ch, SLAB_KERNEL);
+	if (ch == NULL) {
+		HPSB_ERR("Failed to allocate cmp_host");
+		return;
+	}
+	memset(ch, 0, sizeof *ch);
+	ch->host = host;
+	ch->u.ompr.rate = SPEED_100;
+	ch->u.ompr.bcast_channel_base = 63;
+	ch->u.ompr.nplugs = 2;
+	reset_plugs(ch);
+
+	spin_lock_irq(&host_list_lock);
+	list_add_tail(&ch->link, &host_list);
+	spin_unlock_irq(&host_list_lock);
+}
+
+static void cmp_host_reset(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+
+	ch = lookup_cmp_host(host);
+	if (ch == NULL) BUG();
+	reset_plugs(ch);
+}
+
+static void cmp_remove_host(struct hpsb_host *host)
+{
+	struct cmp_host *ch;
+
+	ch = lookup_cmp_host(host);
+	if (ch == NULL) BUG();
+
+	spin_lock_irq(&host_list_lock);
+	list_del(&ch->link);
+	spin_unlock_irq(&host_list_lock);
+
+	kfree(ch);
+}
+
+static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
+		    u64 addr, unsigned int length)
+{
+	int csraddr = addr - CSR_REGISTER_BASE;
+	int plug;
+	struct cmp_host *ch;
+	
+	if (length != 4)
+		return RCODE_TYPE_ERROR;
+
+	ch = lookup_cmp_host(host);
+	if (csraddr == 0x900) {
+		*buf = cpu_to_be32(ch->u.ompr_quadlet);
+		return RCODE_COMPLETE;   
+	}
+	else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
+		plug = (csraddr - 0x904) / 4;
+		*buf = cpu_to_be32(ch->opcr[plug].u.quadlet);
+		return RCODE_COMPLETE;
+	}
+	else if (csraddr < 0x980) {
+		return RCODE_ADDRESS_ERROR;
+	}
+	else if (csraddr == 0x980) {
+		*buf = cpu_to_be32(ch->v.impr_quadlet);
+		return RCODE_COMPLETE;   
+	}
+	else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
+		plug = (csraddr - 0x984) / 4;
+		*buf = cpu_to_be32(ch->ipcr[plug].u.quadlet);
+		return RCODE_COMPLETE;
+	}
+	else
+		return RCODE_ADDRESS_ERROR;
+}
+
+static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+		    u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+{
+	int csraddr = addr - CSR_REGISTER_BASE;
+	int plug;
+	struct cmp_host *ch;
+
+	ch = lookup_cmp_host(host);
+	
+	if (extcode != EXTCODE_COMPARE_SWAP) 
+		return RCODE_TYPE_ERROR;
+	
+	if (csraddr == 0x900) {
+		/* FIXME: Ignore writes to bits 30-31 and 0-7 */
+		*store = cpu_to_be32(ch->u.ompr_quadlet);
+		if (arg == cpu_to_be32(ch->u.ompr_quadlet))
+			ch->u.ompr_quadlet = be32_to_cpu(data);
+
+		return RCODE_COMPLETE;
+	}
+	if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
+		plug = (csraddr - 0x904) / 4;
+		*store = cpu_to_be32(ch->opcr[plug].u.quadlet);
+
+		if (arg == *store)
+			ch->opcr[plug].u.quadlet = be32_to_cpu(data);
+
+		if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet &&
+		    ch->opcr[plug].update != NULL)
+			ch->opcr[plug].update(&ch->opcr[plug].u.pcr,
+					      ch->opcr[plug].data);
+
+		return RCODE_COMPLETE;
+	}
+	else if (csraddr < 0x980) {
+		return RCODE_ADDRESS_ERROR;
+	}
+	else if (csraddr == 0x980) {
+		/* FIXME: Ignore writes to bits 24-31 and 0-7 */
+		*store = cpu_to_be32(ch->u.ompr_quadlet);
+		if (arg == cpu_to_be32(ch->u.ompr_quadlet))
+			ch->u.ompr_quadlet = be32_to_cpu(data);
+
+		return RCODE_COMPLETE;
+	}
+	else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
+		plug = (csraddr - 0x984) / 4;
+		*store = cpu_to_be32(ch->ipcr[plug].u.quadlet);
+
+		if (arg == *store)
+			ch->ipcr[plug].u.quadlet = be32_to_cpu(data);
+
+		if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet &&
+		    ch->ipcr[plug].update != NULL)
+			ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr,
+					      ch->ipcr[plug].data);
+
+		return RCODE_COMPLETE;
+	}
+	else
+		return RCODE_ADDRESS_ERROR;
+}
+
+
+static struct hpsb_highlevel_ops cmp_highlevel_ops = {
+	add_host:	cmp_add_host,
+	remove_host:	cmp_remove_host,
+        host_reset:	cmp_host_reset,
+};
+
+static struct hpsb_address_ops pcr_ops = {
+        read: pcr_read,
+        lock: pcr_lock,
+};
+
+/* Module interface */
+
+MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
+MODULE_DESCRIPTION("Connection Management Procedures (CMP)");
+MODULE_SUPPORTED_DEVICE("cmp");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(cmp_register_opcr);
+EXPORT_SYMBOL(cmp_unregister_opcr);
+
+static int __init cmp_init_module (void)
+{
+	cmp_highlevel = hpsb_register_highlevel ("cmp",
+						 &cmp_highlevel_ops);
+	if (cmp_highlevel == NULL) {
+		HPSB_ERR("cmp: unable to register highlevel ops");
+		return -EIO;
+	}
+
+	hpsb_register_addrspace(cmp_highlevel, &pcr_ops,
+				CSR_REGISTER_BASE + CSR_PCR_MAP,
+				CSR_REGISTER_BASE + CSR_PCR_MAP_END);
+
+	HPSB_INFO("Loaded CMP driver");
+
+	return 0;
+}
+
+static void __exit cmp_exit_module (void)
+{
+        hpsb_unregister_highlevel(cmp_highlevel);
+
+	HPSB_INFO("Unloaded CMP driver");
+}
+
+module_init(cmp_init_module);
+module_exit(cmp_exit_module);
diff -urN linux-2.5.8-pre2/drivers/ieee1394/cmp.h linux-2.5.8-pre3/drivers/ieee1394/cmp.h
--- linux-2.5.8-pre2/drivers/ieee1394/cmp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/ieee1394/cmp.h	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,31 @@
+#ifndef __CMP_H
+#define __CMP_H
+
+struct cmp_mpr {
+	u32 nplugs:5;
+	u32 reserved:3;
+	u32 persistent_ext:8;
+	u32 non_persistent_ext:8;
+	u32 bcast_channel_base:6;
+	u32 rate:2;
+} __attribute__((packed));
+
+struct cmp_pcr {
+	u32 payload:10;
+	u32 overhead:4;
+	u32 speed:2;
+	u32 channel:6;
+	u32 reserved:2;
+	u32 p2p_count:6;
+	u32 bcast_count:1;
+	u32 online:1;
+} __attribute__((packed));
+
+struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug,
+				  int payload,
+				  void (*update)(struct cmp_pcr *plug,
+						 void *data),
+				  void *data);
+void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *plug);
+
+#endif /* __CMP_H */
diff -urN linux-2.5.8-pre2/drivers/ieee1394/dv1394-private.h linux-2.5.8-pre3/drivers/ieee1394/dv1394-private.h
--- linux-2.5.8-pre2/drivers/ieee1394/dv1394-private.h	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/dv1394-private.h	Tue Apr  9 18:35:19 2002
@@ -412,6 +412,10 @@
 /* struct video_card contains all data associated with one instance
    of the dv1394 driver 
 */
+enum modes {
+	MODE_RECEIVE,
+	MODE_TRANSMIT
+};
 
 struct video_card {
 
@@ -574,6 +578,7 @@
 	
 	unsigned int current_packet;
 	int first_frame; 	/* received first start frame marker? */
+	enum modes mode;
 };
 
 /* 
diff -urN linux-2.5.8-pre2/drivers/ieee1394/dv1394.c linux-2.5.8-pre3/drivers/ieee1394/dv1394.c
--- linux-2.5.8-pre2/drivers/ieee1394/dv1394.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/dv1394.c	Tue Apr  9 18:35:19 2002
@@ -46,8 +46,6 @@
 /*
   TODO:
 
-  - expose xmit and recv as separate devices
-
   - tunable frame-drop behavior: either loop last frame, or halt transmission
   
   - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
@@ -73,6 +71,9 @@
   - keep all video_cards in a list (for open() via chardev), set file->private_data = video
   - dv1394_poll should indicate POLLIN when receiving buffers are available
   - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
+  - expose xmit and recv as separate devices (not exclusive)
+  - expose NTSC and PAL as separate devices (can be overridden)
+  - read/edit channel in procfs
 
 */
      
@@ -169,7 +170,14 @@
 
 static struct hpsb_highlevel *hl_handle; /* = NULL; */
 
-static devfs_handle_t dv1394_devfs_handle;
+static LIST_HEAD(dv1394_devfs);
+struct dv1394_devfs_entry {
+	struct list_head list;
+    devfs_handle_t devfs;
+	char name[32];
+	struct dv1394_devfs_entry *parent;
+};
+static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED;
 
 /* translate from a struct file* to the corresponding struct video_card* */
 
@@ -184,19 +192,71 @@
 /* Memory management functions */
 /*******************************/
 
+#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ *    out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed.  We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline struct page *uvirt_to_page(pgd_t *pgd, unsigned long adr)
+{
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+	struct page *ret = NULL;
+	
+	if (!pgd_none(*pgd)) {
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset_kernel(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte))
+				ret = pte_page(pte);
+                }
+        }
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved, and for
+ * handling page faults on the rvmalloc()ed buffer
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
+{
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+	kva = (unsigned long) page_address(uvirt_to_page(pgd_offset_k(va), va));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
+        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+        return ret;
+}
+
 static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr;
-
-	size=PAGE_ALIGN(size);
+	unsigned long adr, page;
+        
 	mem=vmalloc_32(size);
 	if (mem) {
 		memset(mem, 0, size); /* Clear the ram out, 
 					 no junk to the user */
 	        adr=(unsigned long) mem;
 		while (size > 0) {
-			mem_map_reserve(vmalloc_to_page((void *)adr));
+	                page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -206,12 +266,13 @@
 
 static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr;
-
+        unsigned long adr, page;
+        
 	if (mem) {
 	        adr=(unsigned long) mem;
-		while ((long) size > 0) {
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
+		while (size > 0) {
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -1105,9 +1166,9 @@
 		
 		/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
 		for(i = 0; i < video->user_dma.n_pages; i++) {
-			unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE;
+			unsigned long va = VMALLOC_VMADDR( (unsigned long) video->user_buf + i * PAGE_SIZE );
 			
-			video->user_dma.sglist[i].page = vmalloc_to_page((void *)va);
+			video->user_dma.sglist[i].page = uvirt_to_page(pgd_offset_k(va), va);
 			video->user_dma.sglist[i].length = PAGE_SIZE;
 		}
 		
@@ -1238,9 +1299,9 @@
 	struct dv1394_init init;
 
 	init.api_version = DV1394_API_VERSION;
-	init.channel = 63;
 	init.n_frames = 2;
-	/* the following are now set via proc_fs */
+	/* the following are now set via proc_fs or devfs */
+	init.channel = video->channel;
 	init.format = video->pal_or_ntsc;
 	init.cip_n = video->cip_n; 
 	init.cip_d = video->cip_d;
@@ -1431,7 +1492,7 @@
 static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
 {
 	unsigned long offset;
-	unsigned long kernel_virt_addr;
+	unsigned long page, kernel_virt_addr;
 	struct page *ret = NOPAGE_SIGBUS;
 
 	struct video_card *video = (struct video_card*) area->vm_private_data;
@@ -1449,7 +1510,10 @@
 
 	offset = address - area->vm_start;
 	kernel_virt_addr = (unsigned long) video->user_buf + offset;
-	ret = vmalloc_to_page((void *)kernel_virt_addr);
+
+	page = kvirt_to_pa(kernel_virt_addr);
+	
+	ret = virt_to_page(__va(page));
 	get_page(ret);
 
  out:
@@ -2021,7 +2085,7 @@
 			struct video_card *p;
 			list_for_each(lh, &dv1394_cards) {
 				p = list_entry(lh, struct video_card, list);
-				if(p->id == ieee1394_file_to_instance(file)) {
+				if((p->id >> 2) == ieee1394_file_to_instance(file)) {
 					video = p;
 					break;
 				}
@@ -2046,7 +2110,6 @@
 
 #endif
 
-	V22_COMPAT_MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -2064,36 +2127,38 @@
 	/* give someone else a turn */
 	clear_bit(0, &video->open);
 
-	V22_COMPAT_MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 
 /*** PROC_FS INTERFACE ******************************************************/
 #ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *dv1394_procfs_entry;
+static LIST_HEAD(dv1394_procfs);
+struct dv1394_procfs_entry {
+	struct list_head list;
+    struct proc_dir_entry *procfs;
+	char name[32];
+	struct dv1394_procfs_entry *parent;
+};
+static spinlock_t dv1394_procfs_lock = SPIN_LOCK_UNLOCKED;
 
 static int dv1394_procfs_read( char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
 	struct video_card *video = (struct video_card*) data;
 
-	V22_COMPAT_MOD_INC_USE_COUNT;
 	snprintf( page, count, 
 		"\
-dv1394 settings for host %d:\n\
-----------------------------\n\
 format=%s\n\
+channel=%d\n\
 cip_n=%lu\n\
 cip_d=%lu\n\
 syt_offset=%u\n",
-		video->id,
 		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
+		video->channel,
 		video->cip_n, video->cip_d, video->syt_offset );
-	V22_COMPAT_MOD_DEC_USE_COUNT;
 	return strlen(page);
 }
-#endif /* CONFIG_PROC_FS */
 
 /* lifted from the stallion.c driver */
 #undef  TOLOWER
@@ -2128,7 +2193,6 @@
 	return(val);
 }
 
-#ifdef CONFIG_PROC_FS
 static int dv1394_procfs_write( struct file *file,
 			const char *buffer, unsigned long count, void *data)
 {
@@ -2137,17 +2201,13 @@
 	char *pos;
 	struct video_card *video = (struct video_card*) data;
 	
-	V22_COMPAT_MOD_INC_USE_COUNT;
-	
 	if (count > 64)
 		len = 64;
 	else
 		len = count;
 				
-	if (copy_from_user( new_value, buffer, len)) {
-		V22_COMPAT_MOD_DEC_USE_COUNT;
+	if (copy_from_user( new_value, buffer, len))
 		return -EFAULT;
-	}
 	
 	pos = strchr(new_value, '=');
 	if (pos != NULL) {
@@ -2169,31 +2229,142 @@
 			video->cip_d = atol(buf);
 		} else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) {
 			video->syt_offset = atol(buf);
+		} else if (strnicmp( new_value, "channel", (pos-new_value)) == 0) {
+			video->channel = atol(buf);
 		}
 	}
 	
-	V22_COMPAT_MOD_DEC_USE_COUNT;
 	return len;
 }
 
+struct dv1394_procfs_entry *
+dv1394_procfs_find( char *name)
+{
+	struct list_head *lh;
+	struct dv1394_procfs_entry *p;
+		
+	spin_lock( &dv1394_procfs_lock);
+	if(!list_empty(&dv1394_procfs)) {
+		list_for_each(lh, &dv1394_procfs) {
+			p = list_entry(lh, struct dv1394_procfs_entry, list);
+			if(!strncmp(p->name, name, sizeof(p->name))) {
+				spin_unlock( &dv1394_procfs_lock);
+				return p;
+			}
+		}
+	}
+	spin_unlock( &dv1394_procfs_lock);
+	return NULL;
+}
+
 static int dv1394_procfs_add_entry(struct video_card *video)
 {
-	struct proc_dir_entry *procfs_entry = NULL;
-	char buf[16];
+	char buf[32];
+	struct dv1394_procfs_entry *p;
+	struct dv1394_procfs_entry *parent;
+
+	p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n");
+		goto err;
+	}
+	memset(p, 0, sizeof(struct dv1394_procfs_entry));
+	
+	snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2),
+						(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"));
+		
+	parent = dv1394_procfs_find(buf);
+	if (parent == NULL) {
+		printk(KERN_ERR "dv1394: unable to locate parent procfs of %s\n", buf);
+		goto err_free;
+	}
 	
-	snprintf(buf, sizeof(buf), "%d", video->id);
+	p->procfs = create_proc_entry( 
+						(video->mode == MODE_RECEIVE ? "in" : "out"),
+						0666, parent->procfs);
+
+	if (p->procfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s/%s\n",
+			parent->name,
+			(video->mode == MODE_RECEIVE ? "in" : "out"));
+		goto err_free;
+	}
+	
+	p->procfs->owner = THIS_MODULE;
+	p->procfs->data = video;
+	p->procfs->read_proc = dv1394_procfs_read;
+	p->procfs->write_proc = dv1394_procfs_write;
+
+	spin_lock( &dv1394_procfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_procfs);
+	spin_unlock( &dv1394_procfs_lock);
+	
+	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
 
-	procfs_entry = create_proc_entry( buf, 0666, dv1394_procfs_entry);
-	if (procfs_entry == NULL) {
-		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv/X\n");
-		return -ENOMEM;
+static int
+dv1394_procfs_add_dir( char *name,
+					struct dv1394_procfs_entry *parent, 
+					struct dv1394_procfs_entry **out)
+{
+	struct dv1394_procfs_entry *p;
+
+	p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n");
+		goto err;
 	}
-	procfs_entry->owner = THIS_MODULE;
-	procfs_entry->data = video;
-	procfs_entry->read_proc = dv1394_procfs_read;
-	procfs_entry->write_proc = dv1394_procfs_write;
+	memset(p, 0, sizeof(struct dv1394_procfs_entry));
 	
+	if (parent == NULL) {
+		snprintf(p->name, sizeof(p->name), "%s", name);
+		p->procfs = proc_mkdir( name, ieee1394_procfs_entry);
+	} else {
+		snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name);
+		p->procfs = proc_mkdir( name, parent->procfs);
+	}
+	if (p->procfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s\n", p->name);
+		goto err_free;
+	}
+
+	p->procfs->owner = THIS_MODULE;
+	p->parent = parent;
+	if (out != NULL) *out = p;
+
+	spin_lock( &dv1394_procfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_procfs);
+	spin_unlock( &dv1394_procfs_lock);
+
 	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
+
+void dv1394_procfs_del( char *name)
+{
+	struct dv1394_procfs_entry *p = dv1394_procfs_find(name);
+	if (p != NULL) {
+		if (p->parent == NULL)
+			remove_proc_entry(p->name, ieee1394_procfs_entry);
+		else
+			remove_proc_entry(p->name, p->parent->procfs);
+		
+		spin_lock( &dv1394_procfs_lock);
+		list_del(&p->list);
+		spin_unlock( &dv1394_procfs_lock);
+		kfree(p);
+	}
 }
 #endif /* CONFIG_PROC_FS */
 
@@ -2431,7 +2602,7 @@
 
 static struct file_operations dv1394_fops=
 {
-        OWNER_THIS_MODULE
+	owner:		THIS_MODULE,
 	poll:           dv1394_poll,
 	ioctl:		dv1394_ioctl,
 	mmap:		dv1394_mmap,
@@ -2443,11 +2614,141 @@
 };
 
 
-static int dv1394_init(struct ti_ohci *ohci)
+/*** DEVFS HELPERS *********************************************************/
+
+struct dv1394_devfs_entry *
+dv1394_devfs_find( char *name)
+{
+	struct list_head *lh;
+	struct dv1394_devfs_entry *p;
+
+	spin_lock( &dv1394_devfs_lock);
+	if(!list_empty(&dv1394_devfs)) {
+		list_for_each(lh, &dv1394_devfs) {
+			p = list_entry(lh, struct dv1394_devfs_entry, list);
+			if(!strncmp(p->name, name, sizeof(p->name))) {
+				spin_unlock( &dv1394_devfs_lock);
+				return p;
+			}
+		}
+	}
+	return NULL;
+}
+
+static int dv1394_devfs_add_entry(struct video_card *video)
+{
+	char buf[32];
+	struct dv1394_devfs_entry *p;
+	struct dv1394_devfs_entry *parent;
+
+	p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n");
+		goto err;
+	}
+	memset(p, 0, sizeof(struct dv1394_devfs_entry));
+	
+	snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2),
+						(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"));
+		
+	parent = dv1394_devfs_find(buf);
+	if (parent == NULL) {
+		printk(KERN_ERR "dv1394: unable to locate parent devfs of %s\n", buf);
+		goto err_free;
+	}
+	
+	video->devfs_handle = devfs_register(
+						 parent->devfs,
+					     (video->mode == MODE_RECEIVE ? "in" : "out"),
+						 DEVFS_FL_NONE,
+					     IEEE1394_MAJOR,
+					     IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
+					     S_IFCHR | S_IRUGO | S_IWUGO,
+					     &dv1394_fops,
+					     (void*) video);
+	p->devfs = video->devfs_handle;
+
+	if (p->devfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s/%s\n",
+			parent->name,
+			(video->mode == MODE_RECEIVE ? "in" : "out"));
+		goto err_free;
+	}
+	
+	spin_lock( &dv1394_devfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_devfs);
+	spin_unlock( &dv1394_devfs_lock);
+	
+	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
+
+static int
+dv1394_devfs_add_dir( char *name,
+					struct dv1394_devfs_entry *parent, 
+					struct dv1394_devfs_entry **out)
+{
+	struct dv1394_devfs_entry *p;
+
+	p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL);
+	if(!p) {
+		printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n");
+		goto err;
+	}
+	memset(p, 0, sizeof(struct dv1394_devfs_entry));
+	
+	if (parent == NULL) {
+		snprintf(p->name, sizeof(p->name), "%s", name);
+		p->devfs = devfs_mk_dir(ieee1394_devfs_handle, name, NULL);
+	} else {
+		snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name);
+		p->devfs = devfs_mk_dir(parent->devfs, name, NULL);
+	}
+	if (p->devfs == NULL) {
+		printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s\n", p->name);
+		goto err_free;
+	}
+
+	p->parent = parent;
+	if (out != NULL) *out = p;
+
+	spin_lock( &dv1394_devfs_lock);
+	INIT_LIST_HEAD(&p->list);
+	list_add_tail(&p->list, &dv1394_devfs);
+	spin_unlock( &dv1394_devfs_lock);
+
+	return 0;
+	
+ err_free:
+	kfree(p);
+ err:
+	return -ENOMEM;
+}
+
+void dv1394_devfs_del( char *name)
+{
+	struct dv1394_devfs_entry *p = dv1394_devfs_find(name);
+	if (p != NULL) {
+		devfs_unregister(p->devfs);
+		
+		spin_lock( &dv1394_devfs_lock);
+		list_del(&p->list);
+		spin_unlock( &dv1394_devfs_lock);
+		kfree(p);
+	}
+}
+
+/*** IEEE1394 HPSB CALLBACKS ***********************************************/
+
+static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
 {
 	struct video_card *video;
 	unsigned long flags;
-	char buf[16];
 	int i;
 
 	video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
@@ -2465,10 +2766,9 @@
 
 	
 	video->ohci = ohci;
-	video->id = ohci->id;
-
-	if ( dv1394_procfs_add_entry(video) < 0 )
-		goto err_free;
+	/* lower 2 bits of id indicate which of four "plugs"
+	   per host */
+	video->id = ohci->id << 2; 
 
 	video->ohci_it_ctx = -1;
 	video->ohci_ir_ctx = -1;
@@ -2483,14 +2783,20 @@
 	video->ohci_IsoRcvContextMatch = 0;
 		
 	video->n_frames = 0; /* flag that video is not initialized */
-	video->channel = -1;
+	video->channel = 63; /* default to broadcast channel */
 	video->active_frame = -1;
 	
 	/* initialize the following for proc_fs */
-	video->pal_or_ntsc = DV1394_NTSC;
+	video->pal_or_ntsc = format;
 	video->cip_n = 0; /* 0 = use builtin default */
 	video->cip_d = 0;
 	video->syt_offset = 0;
+	video->mode = mode;
+
+#ifdef CONFIG_PROC_FS
+	if ( dv1394_procfs_add_entry(video) < 0 )
+		goto err_free;
+#endif
 
 	for(i = 0; i < DV1394_MAX_FRAMES; i++)
 		video->frames[i] = NULL;
@@ -2509,17 +2815,14 @@
 	list_add_tail(&video->list, &dv1394_cards);
 	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
 	
-	snprintf(buf, sizeof(buf), "%d", video->id);
+	if (format == DV1394_NTSC)
+		video->id |= mode;
+	else video->id |= 2 + mode;
 	
-	video->devfs_handle = devfs_register(dv1394_devfs_handle,
-					     buf, DEVFS_FL_NONE,
-					     IEEE1394_MAJOR,
-					     IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
-					     S_IFCHR | S_IRUGO | S_IWUGO,
-					     &dv1394_fops,
-					     (void*) video);
+	if (dv1394_devfs_add_entry(video) < 0)
+			goto err_free;
 
-	debug_printk("dv1394: dv1394_init() OK on ID %d\n", ohci->id);
+	debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
 	
 	return 0;
 
@@ -2531,18 +2834,20 @@
 
 static void dv1394_un_init(struct video_card *video)
 {
-	unsigned long flags;
+	char buf[32];
 	
 	/* obviously nobody has the driver open at this point */
 	do_dv1394_shutdown(video, 1);
 	ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
-	if(video->devfs_handle)
-		devfs_unregister(video->devfs_handle);
-
-	spin_lock_irqsave(&dv1394_cards_lock, flags);
+	snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2),
+		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
+		(video->mode == MODE_RECEIVE ? "in" : "out")
+		);
+	dv1394_devfs_del(buf);
+#ifdef CONFIG_PROC_FS
+	dv1394_procfs_del(buf);
+#endif
 	list_del(&video->list);
-	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-	
 	kfree(video);
 }
 
@@ -2553,6 +2858,8 @@
 	struct video_card *video = NULL;
 	unsigned long flags;
 	struct list_head *lh;
+	char buf[32];
+	int	n;
 	
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2561,33 +2868,40 @@
 	ohci = (struct ti_ohci *)host->hostdata;
 
 
-	/* find the corresponding video_card */
+	/* find the corresponding video_cards */
 	spin_lock_irqsave(&dv1394_cards_lock, flags);
 	if(!list_empty(&dv1394_cards)) {
-		struct video_card *p;
 		list_for_each(lh, &dv1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if(p->id == ohci->id) {
-				video = p;
-				break;
-			}
+			video = list_entry(lh, struct video_card, list);
+			if((video->id >> 2) == ohci->id)
+				dv1394_un_init(video);
 		}
 	}
 	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
 
-	if(video) {
-		char buf[16];
-		dv1394_un_init(video);
-		snprintf( buf, sizeof(buf), "%i", video->id);
+	n = (video->id >> 2);
+	snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n);
+	dv1394_devfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d/PAL", n);
+	dv1394_devfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d", n);
+	dv1394_devfs_del(buf);
+
 #ifdef CONFIG_PROC_FS
-		remove_proc_entry( buf, dv1394_procfs_entry);
-#endif
-	}
+	snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n);
+	dv1394_procfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d/PAL", n);
+	dv1394_procfs_del(buf);
+	snprintf(buf, sizeof(buf), "dv/host%d", n);
+	dv1394_procfs_del(buf);
+#endif	
 }
 
 static void dv1394_add_host (struct hpsb_host *host)
 {
 	struct ti_ohci *ohci;
+	char buf[16];
+	struct dv1394_devfs_entry *devfs_entry;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2595,7 +2909,31 @@
 
 	ohci = (struct ti_ohci *)host->hostdata;
 
-	dv1394_init(ohci);
+#ifdef CONFIG_PROC_FS
+{
+	struct dv1394_procfs_entry *p;
+	p = dv1394_procfs_find("dv");
+	if (p != NULL) {
+		snprintf(buf, sizeof(buf), "host%d", ohci->id);
+		dv1394_procfs_add_dir(buf, p, &p);
+		dv1394_procfs_add_dir("NTSC", p, NULL);
+		dv1394_procfs_add_dir("PAL", p, NULL);
+	}
+}
+#endif
+
+	devfs_entry = dv1394_devfs_find("dv");
+	if (devfs_entry != NULL) {
+		snprintf(buf, sizeof(buf), "host%d", ohci->id);
+		dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
+		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
+		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
+	}
+	
+	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
+	dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
+	dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE);
+	dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
 }
 
 static struct hpsb_highlevel_ops hl_ops = {
@@ -2615,9 +2953,9 @@
 {
 	hpsb_unregister_highlevel (hl_handle);
 	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-	devfs_unregister(dv1394_devfs_handle);
+	dv1394_devfs_del("dv");
 #ifdef CONFIG_PROC_FS
-	remove_proc_entry( "dv", ieee1394_procfs_entry);
+	dv1394_procfs_del("dv");
 #endif
 }
 
@@ -2629,26 +2967,28 @@
 		return -EIO;
 	}
 
-	dv1394_devfs_handle = devfs_mk_dir(ieee1394_devfs_handle, "dv", NULL);
+	if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) {
+		printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n");
+		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+		return -ENOMEM;
+	}
 
 #ifdef CONFIG_PROC_FS
-	dv1394_procfs_entry = proc_mkdir( "dv", ieee1394_procfs_entry);
-	if (dv1394_procfs_entry == NULL) {
-		printk(KERN_ERR "dv1394: unable to create /proc/ieee1394/dv\n");
+	if (dv1394_procfs_add_dir("dv",NULL,NULL) < 0) {
+		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n");
 		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-		devfs_unregister(dv1394_devfs_handle);
+		dv1394_devfs_del("dv");
 		return -ENOMEM;
 	}
-	dv1394_procfs_entry->owner = THIS_MODULE;
 #endif
 
 	hl_handle = hpsb_register_highlevel ("dv1394", &hl_ops);
 	if (hl_handle == NULL) {
 		printk(KERN_ERR "dv1394: hpsb_register_highlevel failed\n");
 		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-		devfs_unregister(dv1394_devfs_handle);
+		dv1394_devfs_del("dv");
 #ifdef CONFIG_PROC_FS
-		remove_proc_entry( "dv", ieee1394_procfs_entry);
+		dv1394_procfs_del("dv");
 #endif
 		return -ENOMEM;
 	}
diff -urN linux-2.5.8-pre2/drivers/ieee1394/eth1394.c linux-2.5.8-pre3/drivers/ieee1394/eth1394.c
--- linux-2.5.8-pre2/drivers/ieee1394/eth1394.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/ieee1394/eth1394.c	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,741 @@
+/*
+ * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem
+ * 
+ * Copyright (C) 2001 Ben Collins <bcollins@debian.org>
+ *               2000 Bonin Franck <boninf@free.fr>
+ *
+ * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* State of this driver:
+ *
+ * This driver intends to support RFC 2734, which describes a method for
+ * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver
+ * will ultimately support that method, but currently falls short in
+ * several areas. A few issues are:
+ *
+ *   - Does not support send/recv over Async streams using GASP
+ *     packet formats, as per the RFC for ARP requests.
+ *   - Does not yet support fragmented packets.
+ *   - Relies on hardware address being equal to the nodeid for some things.
+ *   - Does not support multicast
+ *   - Hardcoded address for sending packets, instead of using discovery
+ *     (ARP, see first item)
+ */
+
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <asm/delay.h>
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <net/arp.h>
+
+#include "ieee1394_types.h"
+#include "ieee1394_core.h"
+#include "ieee1394_transactions.h"
+#include "ieee1394.h"
+#include "highlevel.h"
+#include "eth1394.h"
+
+#define ETH1394_PRINT_G(level, fmt, args...) \
+	printk(level ETHER1394_DRIVER_NAME": "fmt, ## args)
+
+#define ETH1394_PRINT(level, dev_name, fmt, args...) \
+	printk(level ETHER1394_DRIVER_NAME": %s: " fmt, dev_name, ## args)
+
+#define DEBUG(fmt, args...) \
+	printk(KERN_ERR fmt, ## args)
+
+static char version[] __devinitdata =
+	"eth1394.c:v0.50 15/Jul/01 Ben Collins <bcollins@debian.org>";
+
+/* Our ieee1394 highlevel driver */
+#define ETHER1394_DRIVER_NAME "ether1394"
+
+static kmem_cache_t *packet_task_cache;
+static struct hpsb_highlevel *hl_handle = NULL;
+
+/* Card handling */
+static LIST_HEAD (host_info_list);
+static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
+
+/* Use common.lf to determine header len */
+static int hdr_type_len[] = {
+	sizeof (struct eth1394_uf_hdr),
+	sizeof (struct eth1394_ff_hdr),
+	sizeof (struct eth1394_sf_hdr),
+	sizeof (struct eth1394_sf_hdr)
+};
+
+MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
+MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
+
+/* Find our host_info struct for a given host pointer. Must be called
+ * under spinlock.  */
+static inline struct host_info *find_host_info (struct hpsb_host *host)
+{
+	struct list_head *lh;
+	struct host_info *hi;
+
+	lh = host_info_list.next;
+	while (lh != &host_info_list) {
+		hi = list_entry (lh, struct host_info, list);
+
+		if (hi->host == host)
+			return hi;
+
+		lh = lh->next;
+	}
+	return NULL;
+}
+
+/* Find the network device for our host */
+static inline struct net_device *ether1394_find_dev (struct hpsb_host *host)
+{
+	struct host_info *hi;
+
+	spin_lock_irq (&host_info_lock);
+	hi = find_host_info (host);
+	spin_unlock_irq (&host_info_lock);
+
+	if (hi == NULL)
+		return NULL;
+
+	return hi->dev;
+}
+
+/* This is called after an "ifup" */
+static int ether1394_open (struct net_device *dev)
+{
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+
+	/* Set the spinlock before grabbing IRQ! */
+	priv->lock = SPIN_LOCK_UNLOCKED;
+
+	netif_start_queue (dev);
+	return 0;
+}
+
+/* This is called after an "ifdown" */
+static int ether1394_stop (struct net_device *dev)
+{
+	netif_stop_queue (dev);
+	return 0;
+}
+
+/* Return statistics to the caller */
+static struct net_device_stats *ether1394_stats (struct net_device *dev)
+{
+	return &(((struct eth1394_priv *)dev->priv)->stats);
+}
+
+/* What to do if we timeout. I think a host reset is probably in order, so
+ * that's what we do. Should we increment the stat counters too?  */
+static void ether1394_tx_timeout (struct net_device *dev)
+{
+	ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n",
+		       ((struct eth1394_priv *)(dev->priv))->host->driver->name);
+
+	highlevel_host_reset (((struct eth1394_priv *)(dev->priv))->host);
+
+	netif_wake_queue (dev);
+}
+
+/* We need to encapsulate the standard header with our own. We use the
+ * ethernet header's proto for our own.
+ *
+ * XXX: This is where we need to create a list of skb's for fragmented
+ * packets.  */
+static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev,
+			    int proto)
+{
+	union eth1394_hdr *hdr =
+		(union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]);
+
+	hdr->common.lf = ETH1394_HDR_LF_UF;
+	hdr->words.word1 = htons(hdr->words.word1);
+	hdr->uf.ether_type = proto;
+
+	return;
+}
+
+/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the
+ * entire arphdr) is the same format as the ip1394 header, so they
+ * overlap. The rest needs to be munged a bit. The remainder of the
+ * arphdr is formatted based on hwaddr len and ipaddr len. We know what
+ * they'll be, so it's easy to judge.  */
+static inline void ether1394_arp_to_1394arp (struct sk_buff *skb, struct net_device *dev)
+{
+	struct eth1394_priv *priv =
+		(struct eth1394_priv *)(dev->priv);
+	u16 phy_id = priv->host->node_id & NODE_MASK;
+
+	unsigned char *arp_ptr = (unsigned char *)skb->data;
+	struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
+	unsigned char arp_data[2*(dev->addr_len+4)];
+
+	/* Copy the main data that we need */
+	arp_ptr = memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data));
+
+	/* Extend the buffer enough for our new header */
+	skb_put (skb, sizeof (struct eth1394_arp) -
+		 (sizeof (arp_data) + sizeof (struct arphdr)));
+
+#define PROCESS_MEMBER(ptr,val,len) \
+  memcpy (val, ptr, len); ptr += len
+	arp_ptr += arp1394->hw_addr_len;
+	PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len);
+	arp_ptr += arp1394->hw_addr_len;
+	PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len);
+#undef PROCESS_MEMBER
+
+	/* Now add our own flavor of arp header fields to the orig one */
+	arp1394->hw_addr_len	= IP1394_HW_ADDR_LEN;
+	arp1394->hw_type	= __constant_htons (ARPHRD_IEEE1394);
+	arp1394->s_uniq_id	= cpu_to_le64 (priv->eui[phy_id]);
+	arp1394->max_rec	= priv->max_rec[phy_id];
+	arp1394->sspd		= priv->sspd[phy_id];
+	arp1394->fifo_hi	= htons (priv->fifo_hi[phy_id]);
+	arp1394->fifo_lo	= htonl (priv->fifo_lo[phy_id]);
+
+	return;
+}
+
+static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > ETHER1394_REGION_ADDR_LEN))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static inline void ether1394_register_limits (int nodeid, unsigned char max_rec,
+				       unsigned char sspd, u64 eui, u16 fifo_hi,
+				       u32 fifo_lo, struct eth1394_priv *priv)
+{
+	int i;
+
+	if (nodeid < 0 || nodeid >= ALL_NODES) {
+		ETH1394_PRINT_G (KERN_ERR, "Cannot register invalid nodeid %d\n", nodeid);
+		return;
+	}
+
+	priv->max_rec[nodeid]	= max_rec;
+	priv->sspd[nodeid]	= sspd;
+	priv->fifo_hi[nodeid]	= fifo_hi;
+	priv->fifo_lo[nodeid]	= fifo_lo;
+	priv->eui[nodeid]	= eui;
+
+	/* 63 is used for broadcasts to all hosts. It is equal to the
+	 * minimum of all registered nodes. A registered node is one with
+	 * a nonzero offset. Set the values rediculously high to start. We
+	 * know we have atleast one to change the default to.  */
+	sspd = 0xff;
+	max_rec = 0xff;
+	for (i = 0; i < ALL_NODES; i++) {
+		if (!priv->fifo_hi && !priv->fifo_lo) continue; /* Unregistered */
+		if (priv->max_rec[i] < max_rec) max_rec = priv->max_rec[i];
+		if (priv->sspd[i] < sspd) sspd = priv->sspd[i];
+	}
+
+	priv->max_rec[ALL_NODES] = max_rec;
+	priv->sspd[ALL_NODES] = sspd;
+
+	return;
+}
+
+static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
+{
+	int flags;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	int phy_id = priv->host->node_id & NODE_MASK;
+
+	spin_lock_irqsave (&priv->lock, flags);
+
+	/* Clear the speed/payload/offset tables */
+	memset (priv->max_rec, 0, sizeof (priv->max_rec));
+	memset (priv->sspd, 0, sizeof (priv->sspd));
+	memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi));
+	memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo));
+
+	/* Register our limits now */
+	ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf,
+				   priv->host->speed_map[(phy_id << 6) + phy_id],
+				   (u64)(((u64)be32_to_cpu(priv->host->csr.rom[3]) << 32) |
+				   be32_to_cpu(priv->host->csr.rom[4])),
+				   ETHER1394_REGION_ADDR >> 32,
+				   ETHER1394_REGION_ADDR & 0xffffffff, priv);
+
+	/* We'll use our max_rec as the default mtu */
+	if (set_mtu)
+		dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr);
+
+	/* Set our hardware address while we're at it */
+	*(nodeid_t *)dev->dev_addr = htons (priv->host->node_id);
+
+	spin_unlock_irqrestore (&priv->lock, flags);
+}
+
+static int ether1394_tx (struct sk_buff *skb, struct net_device *dev);
+
+/* This function is called by register_netdev */
+static int ether1394_init_dev (struct net_device *dev)
+{
+	/* Our functions */
+	dev->open		= ether1394_open;
+	dev->stop		= ether1394_stop;
+	dev->hard_start_xmit	= ether1394_tx;
+	dev->get_stats		= ether1394_stats;
+	dev->tx_timeout		= ether1394_tx_timeout;
+	dev->change_mtu		= ether1394_change_mtu;
+
+	/* Some constants */
+	dev->watchdog_timeo	= ETHER1394_TIMEOUT;
+	dev->flags		= IFF_BROADCAST; /* TODO: Support MCAP */
+	dev->features		= NETIF_F_NO_CSUM|NETIF_F_SG|NETIF_F_HIGHDMA|NETIF_F_FRAGLIST;
+	dev->addr_len		= 2;
+
+	ether1394_reset_priv (dev, 1);
+
+	return 0;
+}
+
+/*
+ * This function is called every time a card is found. It is generally called
+ * when the module is installed. This is where we add all of our ethernet
+ * devices. One for each host.
+ */
+static void ether1394_add_host (struct hpsb_host *host)
+{
+	struct host_info *hi = NULL;
+	struct net_device *dev = NULL;
+	struct eth1394_priv *priv;
+	static int version_printed = 0;
+
+	if (version_printed++ == 0)
+		ETH1394_PRINT_G (KERN_INFO, "%s\n", version);
+
+	dev = alloc_etherdev(sizeof (struct eth1394_priv));
+
+	if (dev == NULL)
+		goto out;
+
+	SET_MODULE_OWNER(dev);
+
+	dev->init = ether1394_init_dev;
+
+	priv = (struct eth1394_priv *)dev->priv;
+
+	priv->host = host;
+
+	hi = (struct host_info *)kmalloc (sizeof (struct host_info),
+					  GFP_KERNEL);
+
+	if (hi == NULL)
+		goto out;
+
+	if (register_netdev (dev)) {
+		ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
+		kfree (dev);
+		return;
+	}
+
+	ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n",
+		       host->driver->name);
+
+	INIT_LIST_HEAD (&hi->list);
+	hi->host = host;
+	hi->dev = dev;
+
+	spin_lock_irq (&host_info_lock);
+	list_add_tail (&hi->list, &host_info_list);
+	spin_unlock_irq (&host_info_lock);
+
+	return;
+
+out:
+	if (dev != NULL)
+		kfree (dev);
+	ETH1394_PRINT_G (KERN_ERR, "Out of memory\n");
+
+	return;
+}
+
+/* Remove a card from our list */
+static void ether1394_remove_host (struct hpsb_host *host)
+{
+	struct host_info *hi;
+
+	spin_lock_irq (&host_info_lock);
+	hi = find_host_info (host);
+	if (hi != NULL) {
+		unregister_netdev (hi->dev);
+		kfree (hi->dev);
+		list_del (&hi->list);
+		kfree (hi);
+	}
+	spin_unlock_irq (&host_info_lock);
+
+	return;
+}
+
+/* A reset has just arisen */
+static void ether1394_host_reset (struct hpsb_host *host)
+{
+	struct net_device *dev = ether1394_find_dev(host);
+
+	/* This can happen for hosts that we don't use */
+	if (dev == NULL)
+		return;
+
+	/* Reset our private host data, but not our mtu */
+	netif_stop_queue (dev);
+	ether1394_reset_priv (dev, 0);
+	netif_wake_queue (dev);
+}
+
+/* Copied from net/ethernet/eth.c */
+static inline unsigned short ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ethhdr *eth;
+	unsigned char *rawp;
+
+	skb->mac.raw = skb->data;
+	skb_pull (skb, ETH_HLEN);
+	eth = skb->mac.ethernet;
+#if 0
+	if(*eth->h_dest & 1) {
+		if(memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	} else {
+		if(memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
+			skb->pkt_type = PACKET_OTHERHOST;
+        }
+#endif
+	if (ntohs (eth->h_proto) >= 1536)
+		return eth->h_proto;
+
+	rawp = skb->data;
+
+        if (*(unsigned short *)rawp == 0xFFFF)
+		return htons (ETH_P_802_3);
+
+        return htons (ETH_P_802_2);
+}
+
+/* Parse an encapsulated IP1394 header into an ethernet frame packet.
+ * We also perform ARP translation here, if need be.  */
+static inline unsigned short ether1394_parse_encap (struct sk_buff *skb, struct net_device *dev,
+					     nodeid_t srcid, nodeid_t destid)
+{
+	union eth1394_hdr *hdr = (union eth1394_hdr *)skb->data;
+	unsigned char src_hw[ETH_ALEN], dest_hw[ETH_ALEN];
+	unsigned short ret = 0;
+
+	/* Setup our hw addresses. We use these to build the
+	 * ethernet header.  */
+	*(u16 *)dest_hw = htons(destid);
+	*(u16 *)src_hw = htons(srcid);
+
+	/* Remove the encapsulation header */
+	hdr->words.word1 = ntohs(hdr->words.word1);
+	skb_pull (skb, hdr_type_len[hdr->common.lf]);
+
+	/* If this is an ARP packet, convert it. First, we want to make
+	 * use of some of the fields, since they tell us a little bit
+	 * about the sending machine.  */
+	if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) {
+		int flags;
+		u16 phy_id = srcid & NODE_MASK;
+		struct eth1394_priv *priv =
+			(struct eth1394_priv *)dev->priv;
+		struct eth1394_arp arp1394;
+		struct arphdr *arp = (struct arphdr *)skb->data;
+		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+
+		memcpy (&arp1394, arp, sizeof (struct eth1394_arp));
+
+		/* Update our speed/payload/fifo_offset table */
+		spin_lock_irqsave (&priv->lock, flags);
+		ether1394_register_limits (phy_id, arp1394.max_rec, arp1394.sspd,
+					   le64_to_cpu (arp1394.s_uniq_id),
+					   ntohs (arp1394.fifo_hi),
+					   ntohl (arp1394.fifo_lo), priv);
+		spin_unlock_irqrestore (&priv->lock, flags);
+
+#define PROCESS_MEMBER(ptr,val,len) \
+  ptr = memcpy (ptr, val, len) + len
+                PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len);
+                PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4);
+                PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len);
+                PROCESS_MEMBER (arp_ptr, &arp1394.tip, 4);
+#undef PROCESS_MEMBER
+
+		arp->ar_hln = dev->addr_len;
+		arp->ar_hrd = __constant_htons (ARPHRD_ETHER);
+
+		skb_trim (skb, sizeof (struct arphdr) + 2*(dev->addr_len+4));
+	}
+
+	/* Now add the ethernet header. */
+	if (dev->hard_header (skb, dev, __constant_ntohs (hdr->uf.ether_type),
+			      dest_hw, src_hw, skb->len) >= 0)
+		ret = ether1394_type_trans(skb, dev);
+
+	return ret;
+}
+
+/* Packet reception. We convert the IP1394 encapsulation header to an
+ * ethernet header, and fill it with some of our other fields. This is
+ * an incoming packet from the 1394 bus.  */
+static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
+			    quadlet_t *data, u64 addr, unsigned int len)
+{
+	struct sk_buff *skb;
+	char *buf = (char *)data;
+	int flags;
+	struct net_device *dev = ether1394_find_dev (host);
+	struct eth1394_priv *priv;
+
+	if (dev == NULL) {
+		ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n",
+				 host);
+		return RCODE_ADDRESS_ERROR;
+	}
+
+	priv = (struct eth1394_priv *)dev->priv;
+
+	/* A packet has been received by the ieee1394 bus. Build an skbuff
+	 * around it so we can pass it to the high level network layer. */
+
+	skb = dev_alloc_skb (len + dev->hard_header_len + 15);
+	if (!skb) {
+		HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
+		priv->stats.rx_dropped++;
+		return RCODE_ADDRESS_ERROR;
+	}
+
+	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+
+	memcpy (skb_put (skb, len), buf, len);
+
+	/* Write metadata, and then pass to the receive level */
+	skb->dev = dev;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;	/* don't check it */
+
+	/* Parse the encapsulation header. This actually does the job of
+	 * converting to an ethernet frame header, aswell as arp
+	 * conversion if needed. ARP conversion is easier in this
+	 * direction, since we are using ethernet as our backend.  */
+	skb->protocol = ether1394_parse_encap (skb, dev, srcid, destid);
+
+	spin_lock_irqsave (&priv->lock, flags);
+	if (!skb->protocol) {
+		priv->stats.rx_errors++;
+		priv->stats.rx_dropped++;
+		dev_kfree_skb_any(skb);
+		goto bad_proto;
+	}
+
+	netif_stop_queue(dev);
+	if (netif_rx (skb) == NET_RX_DROP) {
+		priv->stats.rx_errors++;
+		priv->stats.rx_dropped++;
+		goto bad_proto;
+	}
+
+	/* Statistics */
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += skb->len;
+
+bad_proto:
+	netif_start_queue(dev);
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	dev->last_rx = jiffies;
+
+	return RCODE_COMPLETE;
+}
+
+/* This function is our scheduled write */
+static void hpsb_write_sched (void *__ptask)
+{
+	struct packet_task *ptask = (struct packet_task *)__ptask;
+	struct sk_buff *skb = ptask->skb;
+	struct net_device *dev = ptask->skb->dev;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	int flags;
+
+	/* Statistics */
+	spin_lock_irqsave (&priv->lock, flags);
+	if (!hpsb_write(priv->host, ptask->dest_node,
+			get_hpsb_generation(priv->host),
+			ptask->addr, (quadlet_t *)skb->data, skb->len)) {
+		priv->stats.tx_bytes += skb->len;
+		priv->stats.tx_packets++;
+	} else {
+		//printk("Failed in hpsb_write_sched\n");
+		priv->stats.tx_dropped++;
+		priv->stats.tx_errors++;
+		if (netif_queue_stopped (dev))
+			netif_wake_queue (dev);
+	}
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	dev->trans_start = jiffies;
+	dev_kfree_skb(skb);
+	kmem_cache_free(packet_task_cache, ptask);
+
+	return;
+}
+
+/* Transmit a packet (called by kernel) */
+static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
+{
+	int kmflags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+	struct ethhdr *eth;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	int proto, flags;
+	nodeid_t dest_node;
+	u64 addr;
+	struct packet_task *ptask = NULL;
+	int ret = 0;
+
+	if ((skb = skb_share_check (skb, kmflags)) == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	/* Get rid of the ethernet header, but save a pointer */
+	eth = (struct ethhdr *)skb->data;
+	skb_pull (skb, ETH_HLEN);
+
+	/* Save the destination id, and proto for our encapsulation, then
+	 * toss the ethernet header aside like the cheap whore it is.  */
+	dest_node = ntohs (*(nodeid_t *)(eth->h_dest));
+	proto = eth->h_proto;
+
+	/* If this is an ARP packet, convert it */
+	if (proto == __constant_htons (ETH_P_ARP))
+		ether1394_arp_to_1394arp (skb, dev);
+
+	/* Now add our encapsulation header */
+	ether1394_encapsulate (skb, dev, proto);
+
+	/* TODO: The above encapsulate function needs to recognize when a
+	 * packet needs to be split for a specified node. It should create
+	 * a list of skb's that we could then iterate over for the below
+	 * call to schedule our writes.  */
+
+	/* XXX: Right now we accept that we don't exactly follow RFC. When
+	 * we do, we will send ARP requests via GASP format, and so we wont
+	 * need this hack.  */
+
+	spin_lock_irqsave (&priv->lock, flags);
+	addr = (u64)priv->fifo_hi[dest_node & NODE_MASK] << 32 |
+		priv->fifo_lo[dest_node & NODE_MASK];
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	if (!addr)
+		addr = ETHER1394_REGION_ADDR;
+
+	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
+	if (ptask == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	ptask->skb = skb;
+	ptask->addr = addr;
+	ptask->dest_node = dest_node;
+	INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
+	schedule_task(&ptask->tq);
+
+	return 0;
+fail:
+	printk("Failed in ether1394_tx\n");
+
+	if (skb != NULL)
+		dev_kfree_skb (skb);
+
+	spin_lock_irqsave (&priv->lock, flags);
+	priv->stats.tx_dropped++;
+	priv->stats.tx_errors++;
+	if (netif_queue_stopped (dev))
+		netif_wake_queue (dev);
+	spin_unlock_irqrestore (&priv->lock, flags);
+
+	return ret;
+}
+
+/* Function for incoming 1394 packets */
+static struct hpsb_address_ops addr_ops = {
+	write:		ether1394_write,
+};
+
+/* Ieee1394 highlevel driver functions */
+static struct hpsb_highlevel_ops hl_ops = {
+	add_host:	ether1394_add_host,
+	remove_host:	ether1394_remove_host,
+	host_reset:	ether1394_host_reset,
+};
+
+static int __init ether1394_init_module (void)
+{
+	packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task),
+					      0, 0, NULL, NULL);
+
+	/* Register ourselves as a highlevel driver */
+	hl_handle = hpsb_register_highlevel (ETHER1394_DRIVER_NAME, &hl_ops);
+
+	if (hl_handle == NULL) {
+		ETH1394_PRINT_G (KERN_ERR, "No more memory for driver\n");
+		return -ENOMEM;
+	}
+
+	hpsb_register_addrspace (hl_handle, &addr_ops, ETHER1394_REGION_ADDR,
+				 ETHER1394_REGION_ADDR_END);
+
+	return 0;
+}
+
+static void __exit ether1394_exit_module (void)
+{
+	hpsb_unregister_highlevel (hl_handle);
+	kmem_cache_destroy(packet_task_cache);
+}
+
+module_init(ether1394_init_module);
+module_exit(ether1394_exit_module);
diff -urN linux-2.5.8-pre2/drivers/ieee1394/eth1394.h linux-2.5.8-pre3/drivers/ieee1394/eth1394.h
--- linux-2.5.8-pre2/drivers/ieee1394/eth1394.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/ieee1394/eth1394.h	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,190 @@
+/*
+ * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
+ *
+ * Copyright (C) 2000 Bonin Franck <boninf@free.fr>
+ *           (C) 2001 Ben Collins <bcollins@debian.org>
+ *
+ * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ETH1394_H
+#define __ETH1394_H
+
+/* Register for incoming packets. This is 8192 bytes, which supports up to
+ * 1600mbs. We'll need to change this if that ever becomes "small" :)  */
+#define ETHER1394_REGION_ADDR_LEN	8192
+#define ETHER1394_REGION_ADDR		0xfffff0200000ULL
+#define ETHER1394_REGION_ADDR_END	(ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
+
+/* Node set == 64 */
+#define NODE_SET			(ALL_NODES + 1)
+
+/* Private structure for our ethernet driver */
+struct eth1394_priv {
+	struct net_device_stats stats;	/* Device stats			 */
+	struct hpsb_host *host;		/* The card for this dev	 */
+	unsigned char max_rec[NODE_SET];/* Max payload per node		 */
+	unsigned char sspd[NODE_SET];	/* Max speed per node		 */
+	u16 fifo_hi[ALL_NODES];		/* 16bit hi fifo offset per node */
+	u32 fifo_lo[ALL_NODES];		/* 32bit lo fifo offset per node */
+	u64 eui[ALL_NODES];		/* EUI-64 per node		 */
+	spinlock_t lock;		/* Private lock			 */
+};
+
+struct host_info {
+	struct list_head list;
+	struct hpsb_host *host;
+	struct net_device *dev;
+};
+
+/* This is our task struct. It's used for the complete_tq callback.  */
+struct packet_task {
+	struct sk_buff *skb;	/* Socket buffer we are sending */
+	nodeid_t dest_node;	/* Destination of the packet */
+	u64 addr;		/* Address */
+	struct tq_struct tq;	/* The task */
+};
+
+/* IP1394 headers */
+#include <asm/byteorder.h>
+
+/* Unfragmented */
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_uf_hdr {
+	u8 lf:2;
+	u16 res:14;
+	u16 ether_type;		/* Ethernet packet type */
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_uf_hdr {
+	u16 res:14;
+	u8 lf:2;
+	u16 ether_type;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+/* First fragment */
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_ff_hdr {
+	u8 lf:2;
+	u8 res1:2;
+	u16 dg_size:12;		/* Datagram size */
+	u16 ether_type;		/* Ethernet packet type */
+	u16 dgl;		/* Datagram label */
+	u16 res2;
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_ff_hdr {
+	u16 dg_size:12;
+	u8 res1:2;
+	u8 lf:2;
+	u16 ether_type;
+	u16 dgl;
+	u16 res2;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+/* XXX: Subsequent fragments, including last */
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_sf_hdr {
+	u8 lf:2;
+	u8 res1:2;
+	u16 dg_size:12;		/* Datagram size */
+	u8 res2:6;
+	u16 fg_off:10;		/* Fragment offset */
+	u16 dgl;		/* Datagram label */
+	u16 res3;
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_sf_hdr {
+	u16 dg_size:12;
+	u8 res1:2;
+	u8 lf:2;
+	u16 fg_off:10;
+	u8 res2:6;
+	u16 dgl;
+	u16 res3;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+#if defined __BIG_ENDIAN_BITFIELD
+struct eth1394_common_hdr {
+	u8 lf:2;
+	u16 pad1:14;
+} __attribute__((packed));
+#elif defined __LITTLE_ENDIAN_BITFIELD
+struct eth1394_common_hdr {
+	u16 pad1:14;
+	u8 lf:2;
+} __attribute__((packed));
+#else
+#error Unknown bit field type
+#endif
+
+struct eth1394_hdr_words {
+	u16 word1;
+	u16 word2;
+	u16 word3;
+	u16 word4;
+};
+
+union eth1394_hdr {
+	struct eth1394_common_hdr common;
+	struct eth1394_uf_hdr uf;
+	struct eth1394_ff_hdr ff;
+	struct eth1394_sf_hdr sf;
+	struct eth1394_hdr_words words;
+};
+
+/* End of IP1394 headers */
+
+/* Fragment types */
+#define ETH1394_HDR_LF_UF	0	/* unfragmented		*/
+#define ETH1394_HDR_LF_FF	1	/* first fragment	*/
+#define ETH1394_HDR_LF_LF	2	/* last fragment	*/
+#define ETH1394_HDR_LF_IF	3	/* interior fragment	*/
+
+#define IP1394_HW_ADDR_LEN	16	/* As per RFC		*/
+
+/* Our arp packet (ARPHRD_IEEE1394) */
+struct eth1394_arp {
+	u16 hw_type;		/* 0x0018	*/
+	u16 proto_type;		/* 0x0806	*/
+	u8 hw_addr_len;		/* 16 		*/
+	u8 ip_addr_len;		/* 4		*/
+	u16 opcode;		/* ARP Opcode	*/
+	/* Above is exactly the same format as struct arphdr */
+
+	u64 s_uniq_id;		/* Sender's 64bit EUI			*/
+	u8 max_rec;		/* Sender's max packet size		*/
+	u8 sspd;		/* Sender's max speed			*/
+	u16 fifo_hi;		/* hi 16bits of sender's FIFO addr	*/
+	u32 fifo_lo;		/* lo 32bits of sender's FIFO addr	*/
+	u32 sip;		/* Sender's IP Address			*/
+	u32 tip;		/* IP Address of requested hw addr	*/
+};
+
+/* Network timeout */
+#define ETHER1394_TIMEOUT	100000
+
+#endif /* __ETH1394_H */
diff -urN linux-2.5.8-pre2/drivers/ieee1394/hosts.c linux-2.5.8-pre3/drivers/ieee1394/hosts.c
--- linux-2.5.8-pre2/drivers/ieee1394/hosts.c	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/hosts.c	Tue Apr  9 18:35:19 2002
@@ -43,6 +43,16 @@
         devctl:           dummy_devctl
 };
 
+/**
+ * hpsb_ref_host - increase reference count for host controller.
+ * @host: the host controller
+ *
+ * Increase the reference count for the specified host controller.
+ * When holding a reference to a host, the memory allocated for the
+ * host struct will not be freed and the host is guaranteed to be in a
+ * consistent state.  The driver may be unloaded or the controller may
+ * be removed (PCMCIA), but the host struct will remain valid.
+ */
 
 int hpsb_ref_host(struct hpsb_host *host)
 {
@@ -53,18 +63,26 @@
         spin_lock_irqsave(&hosts_lock, flags);
         list_for_each(lh, &hosts) {
                 if (host == list_entry(lh, struct hpsb_host, host_list)) {
-                        if (host->ops->devctl(host, MODIFY_USAGE, 1)) {
-				host->refcount++;
-                                retval = 1;
-                }
+                        host->ops->devctl(host, MODIFY_USAGE, 1);
+			host->refcount++;
+                        retval = 1;
 			break;
-        }
+        	}
         }
         spin_unlock_irqrestore(&hosts_lock, flags);
 
         return retval;
 }
 
+/**
+ * hpsb_unref_host - decrease reference count for host controller.
+ * @host: the host controller
+ *
+ * Decrease the reference count for the specified host controller.
+ * When the reference count reaches zero, the memory allocated for the
+ * &hpsb_host will be freed.
+ */
+
 void hpsb_unref_host(struct hpsb_host *host)
 {
         unsigned long flags;
@@ -74,23 +92,44 @@
         spin_lock_irqsave(&hosts_lock, flags);
         host->refcount--;
 
-        if (!host->refcount && !host->is_shutdown)
+        if (!host->refcount && host->is_shutdown)
                 kfree(host);
         spin_unlock_irqrestore(&hosts_lock, flags);
 }
 
+/**
+ * hpsb_alloc_host - allocate a new host controller.
+ * @drv: the driver that will manage the host controller
+ * @extra: number of extra bytes to allocate for the driver
+ *
+ * Allocate a &hpsb_host and initialize the general subsystem specific
+ * fields.  If the driver needs to store per host data, as drivers
+ * usually do, the amount of memory required can be specified by the
+ * @extra parameter.  Once allocated, the driver should initialize the
+ * driver specific parts, enable the controller and make it available
+ * to the general subsystem using hpsb_add_host().
+ *
+ * The &hpsb_host is allocated with an single initial reference
+ * belonging to the driver.  Once the driver is done with the struct,
+ * for example, when the driver is unloaded, it should release this
+ * reference using hpsb_unref_host().
+ *
+ * Return Value: a pointer to the &hpsb_host if succesful, %NULL if
+ * no memory was available.
+ */
+
 struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
 {
         struct hpsb_host *h;
 
         h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
         if (!h) return NULL;
+        memset(h, 0, sizeof(struct hpsb_host));
 
-        memset(h, 0, sizeof(struct hpsb_host) + extra);
-
+	h->hostdata = h + 1;
         h->driver = drv;
         h->ops = drv->ops;
-	h->hostdata = h + 1;
+	h->refcount = 1;
 
         INIT_LIST_HEAD(&h->pending_packets);
         spin_lock_init(&h->pending_pkt_lock);
@@ -134,9 +173,7 @@
         spin_lock_irqsave(&hosts_lock, flags);
         list_del(&host->driver_list);
         list_del(&host->host_list);
-
         drv->number_of_hosts--;
-        if (!host->refcount) kfree(host);
         spin_unlock_irqrestore(&hosts_lock, flags);
 }
 
diff -urN linux-2.5.8-pre2/drivers/ieee1394/hosts.h linux-2.5.8-pre3/drivers/ieee1394/hosts.h
--- linux-2.5.8-pre2/drivers/ieee1394/hosts.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/hosts.h	Tue Apr  9 18:35:19 2002
@@ -36,6 +36,7 @@
 
         int node_count; /* number of identified nodes on this bus */
         int selfid_count; /* total number of SelfIDs received */
+	int nodes_active; /* number of nodes that are actually active */
 
         nodeid_t node_id; /* node ID of this host */
         nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
diff -urN linux-2.5.8-pre2/drivers/ieee1394/ieee1394_core.c linux-2.5.8-pre3/drivers/ieee1394/ieee1394_core.c
--- linux-2.5.8-pre2/drivers/ieee1394/ieee1394_core.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/ieee1394_core.c	Tue Apr  9 18:35:19 2002
@@ -41,6 +41,10 @@
 MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
 static int disable_nodemgr = 0;
 
+MODULE_PARM(disable_hotplug, "i");
+MODULE_PARM_DESC(disable_hotplug, "Disable hotplug for detected nodes.");
+static int disable_hotplug = 0;
+
 /* We are GPL, so treat us special */
 MODULE_LICENSE("GPL");
 
@@ -108,7 +112,7 @@
                 packet->data_size = data_size;
         }
 
-        INIT_TQ_HEAD(packet->complete_tq);
+        INIT_LIST_HEAD(&packet->complete_tq);
         INIT_LIST_HEAD(&packet->list);
         sema_init(&packet->state_change, 0);
         packet->state = hpsb_unused;
@@ -177,6 +181,8 @@
         struct ext_selfid *esid;
         int esid_seq = 23;
 
+	host->nodes_active = 0;
+
         while (rest_of_selfids--) {
                 if (!sid->extended) {
                         nodeid++;
@@ -188,9 +194,11 @@
                                 return 0;
                         }
                         
-                        if (sid->contender && sid->link_active) {
-                                host->irm_id = LOCAL_BUS | sid->phy_id;
-                        }
+			if (sid->link_active) {
+				host->nodes_active++;
+				if (sid->contender)
+					host->irm_id = LOCAL_BUS | sid->phy_id;
+			}
                 } else {
                         esid = (struct ext_selfid *)sid;
 
@@ -224,7 +232,8 @@
                         return 0;
         }
 
-        return nodeid + 1;
+	host->node_count = nodeid + 1;
+        return 1;
 }
 
 static void build_speed_map(struct hpsb_host *host, int nodecount)
@@ -322,8 +331,7 @@
         host->node_id = LOCAL_BUS | phyid;
         host->is_root = isroot;
 
-        host->node_count = check_selfids(host);
-        if (!host->node_count) {
+        if (!check_selfids(host)) {
                 if (host->reset_retries++ < 20) {
                         /* selfid stage did not complete without error */
                         HPSB_NOTICE("Error in SelfID stage, resetting");
@@ -803,8 +811,8 @@
 static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
 
 static struct file_operations ieee1394_chardev_ops = {
-	OWNER_THIS_MODULE
-	open: ieee1394_dispatch_open,
+	owner:	THIS_MODULE,
+	open:	ieee1394_dispatch_open,
 };
 
 devfs_handle_t ieee1394_devfs_handle;
@@ -828,8 +836,6 @@
 		ieee1394_chardevs[blocknum].module = module;
 		
 		retval = 0;
-
-		V22_COMPAT_MOD_INC_USE_COUNT;
 	} else {
 		/* block already taken */
 		retval = -EBUSY;
@@ -851,7 +857,6 @@
 	if(ieee1394_chardevs[blocknum].file_ops) {
 		ieee1394_chardevs[blocknum].file_ops = NULL;
 		ieee1394_chardevs[blocknum].module = NULL;
-		V22_COMPAT_MOD_DEC_USE_COUNT;
 	}
 	
 	write_unlock(&ieee1394_chardevs_lock);
@@ -868,12 +873,6 @@
 	/*
 	  Maintaining correct module reference counts is tricky here!
 
-	  For Linux v2.2:
-
-	  The task-specific driver is expected to maintain its own
-	  reference count via V22_COMPAT_MOD_[INC,DEC]_USE_COUNT.
-	  We don't need to do anything special.
-	  
 	  For Linux v2.4 and later:
 	  
 	  The key thing to remember is that the VFS increments the
@@ -894,17 +893,10 @@
 	  
 	*/
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-	/* 2.2 */
-#define INCREF(mod) do {} while (0)
-#define DECREF(mod) do {} while (0)
-#else
-	/* 2.4 */
 #define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
                           if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
 #define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
                           if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
-#endif
 	
         /* shift away lower four bits of the minor
 	   to get the index of the ieee1394_driver
@@ -1013,7 +1005,7 @@
 	init_hpsb_highlevel();
 	init_csr();
 	if (!disable_nodemgr)
-		init_ieee1394_nodemgr();
+		init_ieee1394_nodemgr(disable_hotplug);
 	else
 		HPSB_INFO("nodemgr functionality disabled");
 
@@ -1099,8 +1091,10 @@
 
 EXPORT_SYMBOL(hpsb_guid_get_entry);
 EXPORT_SYMBOL(hpsb_nodeid_get_entry);
-EXPORT_SYMBOL(hpsb_get_host_by_ne);
-EXPORT_SYMBOL(hpsb_guid_fill_packet);
+EXPORT_SYMBOL(hpsb_node_fill_packet);
+EXPORT_SYMBOL(hpsb_node_read);
+EXPORT_SYMBOL(hpsb_node_write);
+EXPORT_SYMBOL(hpsb_node_lock);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(hpsb_release_unit_directory);
diff -urN linux-2.5.8-pre2/drivers/ieee1394/ieee1394_transactions.c linux-2.5.8-pre3/drivers/ieee1394/ieee1394_transactions.c
--- linux-2.5.8-pre2/drivers/ieee1394/ieee1394_transactions.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/ieee1394_transactions.c	Tue Apr  9 18:35:19 2002
@@ -415,8 +415,8 @@
  * avoid in kernel buffers for user space callers
  */
 
-int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
-              quadlet_t *buffer, size_t length)
+int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, quadlet_t *buffer, size_t length)
 {
         struct hpsb_packet *packet;
         int retval = 0;
@@ -447,7 +447,7 @@
                 return -ENOMEM;
         }
 
-	packet->generation = get_hpsb_generation(host);
+	packet->generation = generation;
         if (!hpsb_send_packet(packet)) {
 		retval = -EINVAL;
 		goto hpsb_read_fail;
@@ -496,8 +496,8 @@
 	return packet;
 }
 
-int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
-	       quadlet_t *buffer, size_t length)
+int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	       u64 addr, quadlet_t *buffer, size_t length)
 {
 	struct hpsb_packet *packet;
 	int retval;
@@ -522,7 +522,7 @@
 	if (!packet)
 		return -ENOMEM;
 
-	packet->generation = get_hpsb_generation(host);
+	packet->generation = generation;
         if (!hpsb_send_packet(packet)) {
 		retval = -EINVAL;
 		goto hpsb_write_fail;
@@ -541,8 +541,8 @@
 
 
 /* We need a hpsb_lock64 function for the 64 bit equivalent.  Probably. */
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
-              quadlet_t *data, quadlet_t arg)
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
 {
         struct hpsb_packet *packet;
         int retval = 0, length;
@@ -588,7 +588,7 @@
         }
         fill_async_lock(packet, addr, extcode, length);
 
-	packet->generation = get_hpsb_generation(host);
+	packet->generation = generation;
         if (!hpsb_send_packet(packet)) {
 		retval = -EINVAL;
 		goto hpsb_lock_fail;
diff -urN linux-2.5.8-pre2/drivers/ieee1394/ieee1394_transactions.h linux-2.5.8-pre3/drivers/ieee1394/ieee1394_transactions.h
--- linux-2.5.8-pre2/drivers/ieee1394/ieee1394_transactions.h	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/ieee1394_transactions.h	Tue Apr  9 18:35:19 2002
@@ -63,14 +63,16 @@
  * The generic read, write and lock functions.  All recognize the local node ID
  * and act accordingly.  Read and write automatically use quadlet commands if
  * length == 4 and and block commands otherwise (however, they do not yet
- * support lengths that are not a multiple of 4).
+ * support lengths that are not a multiple of 4).  You must explicitly specifiy
+ * the generation for which the node ID is valid, to avoid sending packets to
+ * the wrong nodes when we race with a bus reset.
  */
-int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
-              quadlet_t *buffer, size_t length);
-int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
-               quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
-              quadlet_t *data, quadlet_t arg);
+int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, quadlet_t *buffer, size_t length);
+int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	       u64 addr, quadlet_t *buffer, size_t length);
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
 
 /* Generic packet creation. Used by hpsb_write. Also useful for protocol
  * drivers that want to implement their own hpsb_write replacement.  */
diff -urN linux-2.5.8-pre2/drivers/ieee1394/ieee1394_types.h linux-2.5.8-pre3/drivers/ieee1394/ieee1394_types.h
--- linux-2.5.8-pre2/drivers/ieee1394/ieee1394_types.h	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/ieee1394_types.h	Tue Apr  9 18:35:19 2002
@@ -10,17 +10,6 @@
 #include <asm/byteorder.h>
 
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#include "linux22compat.h"
-#else
-#define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0)
-#define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0)
-#define OWNER_THIS_MODULE owner: THIS_MODULE,
-
-#define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list)
-#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq))
-#endif
-
 /* The great kdev_t changeover in 2.5.x */
 #include <linux/kdev_t.h>
 #ifndef minor
@@ -48,11 +37,7 @@
 
 #endif /* Linux version < 2.4.12 */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
-#include <asm/spinlock.h>
-#else
 #include <linux/spinlock.h>
-#endif
 
 #ifndef list_for_each_safe
 #define list_for_each_safe(pos, n, head) \
@@ -61,6 +46,10 @@
 
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
+#define pte_offset_kernel pte_offset
+#endif
+
 #ifndef MIN
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
@@ -78,7 +67,8 @@
 #define LOCAL_BUS 0xffc0
 #define ALL_NODES 0x003f
 
-#define NODE_BUS_FMT    "%d:%d"
+/* Can be used to consistently print a node/bus ID. */
+#define NODE_BUS_FMT    "%02d:%04d"
 #define NODE_BUS_ARGS(nodeid) \
 	(nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6)
 
diff -urN linux-2.5.8-pre2/drivers/ieee1394/nodemgr.c linux-2.5.8-pre3/drivers/ieee1394/nodemgr.c
--- linux-2.5.8-pre2/drivers/ieee1394/nodemgr.c	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/nodemgr.c	Tue Apr  9 18:35:19 2002
@@ -12,11 +12,11 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <asm/byteorder.h>
-#include <asm/atomic.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kmod.h>
 #include <linux/completion.h>
+#include <linux/delay.h>
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #endif
@@ -61,70 +61,122 @@
 static LIST_HEAD(host_info_list);
 static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
 
+/* Disables use of the hotplug calls.  */
+static int nodemgr_disable_hotplug = 0;
+
 struct host_info {
 	struct hpsb_host *host;
 	struct list_head list;
-	struct completion started;
 	struct completion exited;
-	wait_queue_head_t wait;
+	struct semaphore reset_sem;
 	int pid;
 };
 
 #ifdef CONFIG_PROC_FS
 
-static int raw1394_read_proc(char *buffer, char **start, off_t offset,
-			     int size, int *eof, void *data )
+#define PUTF(fmt, args...) out += sprintf(out, fmt, ## args)
+
+static int raw1394_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data)
 {
 	struct list_head *lh;
 	struct node_entry *ne;
-	int disp_size = 0;
-	char display_str[1024];
+	int len;
+	char *out = page;
 
-#define PUTF(fmt, args...) disp_size += sprintf(display_str, fmt, ## args); strcat(buffer,display_str)
-	buffer[0] = '\0';
 	list_for_each(lh, &node_list) {
+		struct list_head *l;
+		int ud_count = 0;
+
 		ne = list_entry(lh, struct node_entry, list);
 		if (!ne)
 			continue;
+
 		PUTF("Node[" NODE_BUS_FMT "]  GUID[%016Lx]:\n",
 		     NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
-		if (ne->host != NULL && ne->host->node_id == ne->nodeid) {
-			PUTF("\tNodes connected : %d\n", ne->host->node_count);
-			PUTF("\tSelfIDs received: %d\n", ne->host->selfid_count);
-			PUTF("\tOwn ID          : 0x%08x\n",ne->host->node_id);
-			PUTF("\tIrm ID          : 0x%08x\n",ne->host->irm_id);
-			PUTF("\tBusMgr ID       : 0x%08x\n",ne->host->busmgr_id);
-			PUTF("\tBR IR IC II IB\n");
-			PUTF("\t%02d %02d %02d %02d %02d\n",
-			     ne->host->in_bus_reset, ne->host->is_root,
-			     ne->host->is_cycmst, ne->host->is_irm,
-			     ne->host->is_busmgr);
-		}
-		PUTF("\tVendor ID: %s [0x%06x]\n",
+
+		/* Generic Node information */
+		PUTF("  Vendor ID: `%s' [0x%06x]\n",
 		     ne->vendor_name ?: "Unknown", ne->vendor_id);
-		PUTF("\tCapabilities: 0x%06x\n", ne->capabilities);
-		PUTF("\tirmc=%d cmc=%d isc=%d bmc=%d pmc=%d cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d\n",
+		PUTF("  Capabilities: 0x%06x\n", ne->capabilities);
+		PUTF("  Bus Options:\n");
+		PUTF("    IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d)\n"
+		     "    LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n",
 		     ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
-		     ne->busopt.pmc, ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
-		     ne->busopt.generation, ne->busopt.lnkspd);
+		     ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
+		     ne->busopt.max_rec, ne->busopt.cyc_clk_acc);
+
+		/* If this is the host entry, output some info about it aswell */
+		if (ne->host != NULL && ne->host->node_id == ne->nodeid) {
+			PUTF("  Host Node Status:\n");
+			PUTF("    Host Driver     : %s\n", ne->host->driver->name);
+			PUTF("    Nodes connected : %d\n", ne->host->node_count);
+			PUTF("    Nodes active    : %d\n", ne->host->nodes_active);
+			PUTF("    SelfIDs received: %d\n", ne->host->selfid_count);
+			PUTF("    Irm ID          : [" NODE_BUS_FMT "]\n",
+			     NODE_BUS_ARGS(ne->host->irm_id));
+			PUTF("    BusMgr ID       : [" NODE_BUS_FMT "]\n",
+			     NODE_BUS_ARGS(ne->host->busmgr_id));
+			PUTF("    In Bus Reset    : %s\n", ne->host->in_bus_reset ? "yes" : "no");
+			PUTF("    Root            : %s\n", ne->host->is_root ? "yes" : "no");
+			PUTF("    Cycle Master    : %s\n", ne->host->is_cycmst ? "yes" : "no");
+			PUTF("    IRM             : %s\n", ne->host->is_irm ? "yes" : "no");
+			PUTF("    Bus Manager     : %s\n", ne->host->is_busmgr ? "yes" : "no");
+		}
+
+		/* Now the unit directories */
+		list_for_each (l, &ne->unit_directories) {
+			struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
+			PUTF("  Unit Directory %d:\n", ud_count++);
+			if (ud->flags & UNIT_DIRECTORY_VENDOR_ID)
+				PUTF("    Vendor/Model ID: %s [%06x]",
+				     ud->vendor_name ?: "Unknown", ud->vendor_id);
+			else if (ud->flags & UNIT_DIRECTORY_MODEL_ID) /* Have to put something */
+				PUTF("    Vendor/Model ID: %s [%06x]",
+				      ne->vendor_name ?: "Unknown", ne->vendor_id);
+			if (ud->flags & UNIT_DIRECTORY_MODEL_ID)
+				PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id);
+			PUTF("\n");
+			if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
+				PUTF("    Software Specifier ID: %06x\n", ud->specifier_id);
+			if (ud->flags & UNIT_DIRECTORY_VERSION)
+				PUTF("    Software Version: %06x\n", ud->version);
+			if (ud->driver)
+				PUTF("    Driver: %s\n", ud->driver->name);
+			PUTF("    Length (in quads): %d\n", ud->count);
+		}
+
 	}
-#undef PUTF
-    return disp_size;
+
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	} else
+		len = count;
+
+        *start = page + off;
+
+	return len;
 }
+
+#undef PUTF
 #endif /* CONFIG_PROC_FS */
 
 static void nodemgr_process_config_rom(struct node_entry *ne, 
 				       quadlet_t busoptions);
 
 static int nodemgr_read_quadlet(struct hpsb_host *host,
-				nodeid_t nodeid, octlet_t address,
-				quadlet_t *quad)
+				nodeid_t nodeid, unsigned int generation,
+				octlet_t address, quadlet_t *quad)
 {
 	int i;
 	int ret = 0;
 
 	for (i = 0; i < 3; i++) {
-		ret = hpsb_read(host, nodeid, address, quad, 4);
+		ret = hpsb_read(host, nodeid, generation, address, quad, 4);
 		if (ret != -EAGAIN)
 			break;
 	}
@@ -134,17 +186,17 @@
 }
 
 static int nodemgr_size_text_leaf(struct hpsb_host *host,
-				  nodeid_t nodeid,
+				  nodeid_t nodeid, unsigned int generation,
 				  octlet_t address)
 {
 	quadlet_t quad;
 	int size = 0;
-	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
 		return -1;
 	if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) {
 		/* This is the offset.  */
 		address += 4 * CONFIG_ROM_VALUE(quad); 
-		if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
 			return -1;
 		/* Now we got the size of the text descriptor leaf. */
 		size = CONFIG_ROM_LEAF_LENGTH(quad);
@@ -152,21 +204,20 @@
 	return size;
 }
 
-static int nodemgr_read_text_leaf(struct hpsb_host *host,
-				  nodeid_t nodeid,
+static int nodemgr_read_text_leaf(struct node_entry *ne,
 				  octlet_t address,
 				  quadlet_t *quadp)
 {
 	quadlet_t quad;
 	int i, size, ret;
 
-	if (nodemgr_read_quadlet(host, nodeid, address, &quad)
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)
 	    && CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF)
 		return -1;
 
 	/* This is the offset.  */
 	address += 4 * CONFIG_ROM_VALUE(quad);
-	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))
 		return -1;
 
 	/* Now we got the size of the text descriptor leaf. */
@@ -176,7 +227,7 @@
 
 	address += 4;
 	for (i = 0; i < 2; i++, address += 4, quadp++) {
-		if (nodemgr_read_quadlet(host, nodeid, address, quadp))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, quadp))
 			return -1;
 	}
 
@@ -184,7 +235,7 @@
 	ret = -ENXIO;
 	for (; size > 0; size--, address += 4, quadp++) {
 		for (i = 0; i < 3; i++) {
-			ret = hpsb_read(host, nodeid, address, quadp, 4);
+			ret = hpsb_read(ne->host, ne->nodeid, ne->generation, address, quadp, 4);
 			if (ret != -EAGAIN)
 				break;
 		}
@@ -196,7 +247,7 @@
 }
 
 static struct node_entry *nodemgr_scan_root_directory
-	(struct hpsb_host *host, nodeid_t nodeid)
+	(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation)
 {
 	octlet_t address;
 	quadlet_t quad;
@@ -206,11 +257,11 @@
 
 	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
 	
-	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
 		return NULL;
 	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
 
-	if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
 		return NULL;
 	length = CONFIG_ROM_ROOT_LENGTH(quad);
 	address += 4;
@@ -218,30 +269,22 @@
 	size = 0;
 	total_size = sizeof(struct node_entry);
 	for (; length > 0; length--, address += 4) {
-		if (nodemgr_read_quadlet(host, nodeid, address, &quad))
+		if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
 			return NULL;
 		code = CONFIG_ROM_KEY(quad);
 
-		if (code == CONFIG_ROM_VENDOR_ID) {
+		if (code == CONFIG_ROM_VENDOR_ID && length > 0) {
 			/* Check if there is a text descriptor leaf
 			   immediately after this.  */
-			length--;
-			if (length <= 0)
-				break;	
-			address += 4;
-			size = nodemgr_size_text_leaf(host, nodeid,
-						      address);
-			switch (size) {
-			case -1:
-				return NULL;
-				break;
-			case 0:
-				break;
-			default:
+			size = nodemgr_size_text_leaf(host, nodeid, generation,
+						      address + 4);
+			if (size > 0) {
+				address += 4;
+				length--;
 				total_size += (size + 1) * sizeof (quadlet_t);
-				break;
 			}
-			break;
+			else if (size < 0)
+				return NULL;
 		}
 	}
 	ne = kmalloc(total_size, SLAB_ATOMIC);
@@ -259,12 +302,13 @@
 }
 
 static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,
-					      struct hpsb_host *host, nodeid_t nodeid)
+					      struct hpsb_host *host,
+					      nodeid_t nodeid, unsigned int generation)
 {
         struct node_entry *ne;
         unsigned long flags;
 
-	ne = nodemgr_scan_root_directory (host, nodeid);
+	ne = nodemgr_scan_root_directory (host, nodeid, generation);
         if (!ne) return NULL;
 
         INIT_LIST_HEAD(&ne->list);
@@ -272,7 +316,7 @@
         ne->host = host;
         ne->nodeid = nodeid;
         ne->guid = guid;
-	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
+	ne->generation = generation;
 
         write_lock_irqsave(&node_lock, flags);
         list_add_tail(&ne->list, &node_list);
@@ -281,7 +325,7 @@
 	nodemgr_process_config_rom (ne, busoptions);
 
 	HPSB_DEBUG("%s added: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",
-		   (host->node_id == nodeid) ? "Local host" : "Device",
+		   (host->node_id == nodeid) ? "Host" : "Device",
 		   NODE_BUS_ARGS(nodeid), (unsigned long long)guid,
 		   ne->vendor_name ?: "Unknown");
 
@@ -323,7 +367,7 @@
 	int length, size, total_size, count;
 	int vendor_name_size, model_name_size;
 
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad))
 		return NULL;
 	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
 	address += 4;
@@ -338,8 +382,8 @@
 		int code;
 		quadlet_t value;
 
-retry:
-		if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+					 address, &quad))
 			return NULL;
 		code = CONFIG_ROM_KEY(quad);
 		value = CONFIG_ROM_VALUE(quad);
@@ -373,32 +417,27 @@
 			break;
 		}
 
-		if (todo) {
+		if (todo && length > 0) {
 			/* Check if there is a text descriptor leaf
 			   immediately after this.  */
-			length--;
-			if (length <= 0)
-				break;
-			address += 4;
 			size = nodemgr_size_text_leaf(ne->host,
 						      ne->nodeid,
-						      address);
-			if (todo | UNIT_DIRECTORY_VENDOR_TEXT)
+						      ne->generation,
+						      address + 4);
+
+			if (todo == UNIT_DIRECTORY_VENDOR_TEXT)
 				vendor_name_size = size;
 			else
 				model_name_size = size;
-			switch (size) {
-			case -1:
-				return NULL;
-				break;
-			case 0:
-				goto retry;
-				break;
-			default:
+
+			if (size > 0) {
+				address += 4;
+				length--;
 				flags |= todo;
 				total_size += (size + 1) * sizeof (quadlet_t);
-				break;
 			}
+			else if (size < 0)
+				return NULL;
 		}
 	}
 	total_size += count * sizeof (quadlet_t);
@@ -435,7 +474,8 @@
 	ud->ne = ne;
 	ud->address = address;
 
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+				 address, &quad))
 		goto unit_directory_error;
 	length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ;
 	address += 4;
@@ -446,7 +486,8 @@
 		quadlet_t value;
 		quadlet_t *quadp;
 
-		if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+					 address, &quad))
 			goto unit_directory_error;
 		code = CONFIG_ROM_KEY(quad) ;
 		value = CONFIG_ROM_VALUE(quad);
@@ -459,9 +500,7 @@
 				length--;
 				address += 4;
 				quadp = &(ud->quadlets[ud->count]);
-				if (nodemgr_read_text_leaf(ne->host,
-							   ne->nodeid,
-							   address,
+				if (nodemgr_read_text_leaf(ne, address,
 							   quadp) == 0
 				    && quadp[0] == 0
 				    && quadp[1] == 0) {
@@ -481,9 +520,7 @@
 				length--;
 				address += 4;
 				quadp = &(ud->quadlets[ud->count + ud->vendor_name_size + 1]);
-				if (nodemgr_read_text_leaf(ne->host,
-							   ne->nodeid,
-							   address,
+				if (nodemgr_read_text_leaf(ne, address,
 							   quadp) == 0
 				    && quadp[0] == 0
 				    && quadp[1] == 0) {
@@ -568,11 +605,13 @@
 
 	address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
 	
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+				 address, &quad))
 		return;
 	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
 
-	if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+				 address, &quad))
 		return;
 	length = CONFIG_ROM_ROOT_LENGTH(quad);
 	address += 4;
@@ -580,7 +619,8 @@
 	for (; length > 0; length--, address += 4) {
 		int code, value;
 
-		if (nodemgr_read_quadlet(ne->host, ne->nodeid, address, &quad))
+		if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
+					 address, &quad))
 			return;
 		code = CONFIG_ROM_KEY(quad);
 		value = CONFIG_ROM_VALUE(quad);
@@ -593,9 +633,7 @@
 			if (ne->vendor_name != NULL) {
 				length--;
 				address += 4;
-				if (nodemgr_read_text_leaf(ne->host,
-							   ne->nodeid,
-							   address,
+				if (nodemgr_read_text_leaf(ne, address,
 							   ne->quadlets)
 				    != 0
 				    || ne->quadlets [0] != 0
@@ -631,6 +669,10 @@
 	char *argv [3], **envp, *buf, *scratch;
 	int i = 0, value;
 
+	/* User requested to disable hotplug when module was loaded. */
+	if (nodemgr_disable_hotplug)
+		return;
+
 	if (!hotplug_path [0])
 		return;
 	if (!current->fs->root)
@@ -902,7 +944,8 @@
  * the to take whatever actions required.
  */
 static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions,
-                               struct hpsb_host *host, nodeid_t nodeid)
+                               struct hpsb_host *host,
+				nodeid_t nodeid, unsigned int generation)
 {
 	struct list_head *lh;
 	struct unit_directory *ud;
@@ -917,7 +960,7 @@
 		nodemgr_process_config_rom (ne, busoptions);
 
 	/* Since that's done, we can declare this record current */
-	atomic_set(&ne->generation, get_hpsb_generation(ne->host));
+	ne->generation = generation;
 
 	list_for_each (lh, &ne->unit_directories) {
 		ud = list_entry (lh, struct unit_directory, node_list);
@@ -926,73 +969,59 @@
 	}
 }
 
-static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid,
+static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation,
 			      quadlet_t *buffer, int buffer_length)
 {
-	octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
-	int retries = 3;
-	int header_count;
+	octlet_t addr = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
 	unsigned header_size;
-	quadlet_t quad;
-	int ret;
-
-retry_configrom:
-
-	if (!retries--) {
-		HPSB_ERR("Giving up on node " NODE_BUS_FMT
-			 " for ConfigROM probe, too many errors",
-			 NODE_BUS_ARGS(nodeid));
-		return -1;
-	}
+	int i;
 
-	header_count = 0;
-	header_size = 0;
+	/* IEEE P1212 says that devices should support 64byte block
+	 * reads, aligned on 64byte boundaries. That doesn't seem to
+	 * work though, and we are forced to doing quadlet sized
+	 * reads.  */
 
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_INFO("Initiating ConfigROM request for node " NODE_BUS_FMT,
 		  NODE_BUS_ARGS(nodeid));
 #endif
 
-	/* Now, P1212 says that devices should support 64byte block
-	 * reads, aligned on 64byte boundaries. That doesn't seem
-	 * to work though, and we are forced to doing quadlet
-	 * sized reads.  */
-
-	ret = hpsb_read(host, nodeid, base, &quad, 4);
-	if (ret) {
-		HPSB_ERR("ConfigROM quadlet transaction error (%d) for node " NODE_BUS_FMT,
-			 ret, NODE_BUS_ARGS(nodeid));
-		goto retry_configrom;
+	if (nodemgr_read_quadlet(host, nodeid, generation,
+				 addr, &buffer[0]) < 0) {
+		HPSB_ERR("ConfigROM quadlet transaction error for node "
+			 NODE_BUS_FMT, NODE_BUS_ARGS(nodeid));
+		return -1;
 	}
-	buffer[header_count++] = be32_to_cpu(quad);
 
 	header_size = buffer[0] >> 24;
+	addr += 4;
 
 	if (header_size < 4) {
-		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM format (%d quads), "
-			  "cannot parse", NODE_BUS_ARGS(nodeid), header_size);
+		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM "
+			  "format (%d quads), cannot parse",
+			  NODE_BUS_ARGS(nodeid), header_size);
 		return -1;
 	}
 
-	while (header_count <= header_size && header_count < buffer_length) {
-		ret = hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4);
-		if (ret) {
-			HPSB_ERR("ConfigROM quadlet transaction error (%d) for " NODE_BUS_FMT,
-				 ret, NODE_BUS_ARGS(nodeid));
-			goto retry_configrom;
+	for (i = 1; i < buffer_length; i++, addr += 4) {
+		if (nodemgr_read_quadlet(host, nodeid, generation,
+					 addr, &buffer[i]) < 0) {
+			HPSB_ERR("ConfigROM quadlet transaction "
+				 "error for node " NODE_BUS_FMT,
+				 NODE_BUS_ARGS(nodeid));
+			return -1;
 		}
-		buffer[header_count++] = be32_to_cpu(quad);
 	}
 
 	return 0;
-}
+}		
 
 static void nodemgr_remove_node(struct node_entry *ne)
 {
 	unsigned long flags;
 
 	HPSB_DEBUG("%s removed: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",
-		   (ne->host->node_id == ne->nodeid) ? "Local host" : "Device",
+		   (ne->host->node_id == ne->nodeid) ? "Host" : "Device",
 		   NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid,
 		   ne->vendor_name ?: "Unknown");
 
@@ -1007,7 +1036,8 @@
 
 /* This is where we probe the nodes for their information and provided
  * features.  */
-static void nodemgr_node_probe_one(struct hpsb_host *host, nodeid_t nodeid)
+static void nodemgr_node_probe_one(struct hpsb_host *host,
+				   nodeid_t nodeid, int generation)
 {
 	struct node_entry *ne;
 	quadlet_t buffer[5];
@@ -1016,7 +1046,8 @@
 	/* We need to detect when the ConfigROM's generation has changed,
 	 * so we only update the node's info when it needs to be.  */
 
-	if (read_businfo_block (host, nodeid, buffer, sizeof(buffer) >> 2))
+	if (read_businfo_block (host, nodeid, generation,
+				buffer, sizeof(buffer) >> 2))
 		return;
 
 	if (buffer[1] != IEEE1394_BUSID_MAGIC) {
@@ -1030,14 +1061,14 @@
 	ne = hpsb_guid_get_entry(guid);
 
 	if (!ne)
-		nodemgr_create_node(guid, buffer[2], host, nodeid);
+		nodemgr_create_node(guid, buffer[2], host, nodeid, generation);
 	else
-		nodemgr_update_node(ne, buffer[2], host, nodeid);
+		nodemgr_update_node(ne, buffer[2], host, nodeid, generation);
 
 	return;
 }
 
-static void nodemgr_node_probe_cleanup(struct hpsb_host *host)
+static void nodemgr_node_probe_cleanup(struct hpsb_host *host, unsigned int generation)
 {
 	unsigned long flags;
 	struct list_head *lh, *next;
@@ -1057,7 +1088,7 @@
 		 * node was removed, or it failed the above probe. Either
 		 * way, we remove references to it, since they are
 		 * invalid.  */
-		if (!hpsb_node_entry_valid(ne))
+		if (ne->generation != generation)
 			nodemgr_remove_node(ne);
 	}
 	write_unlock_irqrestore(&node_lock, flags);
@@ -1067,22 +1098,46 @@
 
 static void nodemgr_node_probe(struct hpsb_host *host)
 {
-	int nodecount = host->node_count;
+	int count;
 	struct selfid *sid = (struct selfid *)host->topology_map;
 	nodeid_t nodeid = LOCAL_BUS;
+	unsigned int generation;
+
+	/* Pause for 1 second, to make sure things settle down. If
+	 * schedule_timeout returns non-zero, it means we caught a signal
+	 * and need to return. */
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (schedule_timeout (HZ))
+		return;
+
+	/* Now get the generation in which the node ID's we collect
+	 * are valid.  During the bus scan we will use this generation
+	 * for the read transactions, so that if another reset occurs
+	 * during the scan the transactions will fail instead of
+	 * returning bogus data. */
+	generation = get_hpsb_generation(host);
 
 	/* Scan each node on the bus */
-	for (; nodecount; nodecount--, nodeid++, sid++) {
-		while (sid->extended)
-			sid++;
-		if (!sid->link_active)
+	for (count = host->selfid_count; count; count--, sid++) {
+		if (sid->extended)
 			continue;
 
-		nodemgr_node_probe_one(host, nodeid);
+		if (!sid->link_active) {
+			nodeid++;
+			continue;
+		}
+
+		nodemgr_node_probe_one(host, nodeid++, generation);
 	}
 
-	/* Cleanup if needed */
-	nodemgr_node_probe_cleanup(host);
+	/* If we had a bus reset while we were scanning the bus, it is
+	 * possible that we did not probe all nodes.  In that case, we
+	 * skip the clean up for now, since we could remove nodes that
+	 * were still on the bus.  The bus reset increased
+	 * hi->reset_sem, so there's a bus scan pending which will do
+	 * the clean up eventually. */
+	if (generation == get_hpsb_generation(host))
+		nodemgr_node_probe_cleanup(host, generation);
 
 	return;
 }
@@ -1090,29 +1145,21 @@
 static int nodemgr_host_thread(void *__hi)
 {
 	struct host_info *hi = (struct host_info *)__hi;
-	lock_kernel();
 
 	/* No userlevel access needed */
 	daemonize();
 
-	strcpy(current->comm, "NodeMgr");
-
-	complete(&hi->started);
+	strcpy(current->comm, "knodemgrd");
 
 	/* Sit and wait for a signal to probe the nodes on the bus. This
-	 * happens when we get a bus reset.  */
-	do {
-		interruptible_sleep_on(&hi->wait);
-		if (!signal_pending(current))
-			nodemgr_node_probe(hi->host);
-	} while (!signal_pending(current));
+	 * happens when we get a bus reset. */
+	while (!down_interruptible(&hi->reset_sem))
+		nodemgr_node_probe(hi->host);
 
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name);
 #endif
 
-	unlock_kernel();
-
 	complete_and_exit(&hi->exited, 0);
 }
 
@@ -1140,23 +1187,57 @@
 	return ne;
 }
 
-struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne)
+/* The following four convenience functions use a struct node_entry
+ * for addressing a node on the bus.  They are intended for use by any
+ * process context, not just the nodemgr thread, so we need to be a
+ * little careful when reading out the node ID and generation.  The
+ * thing that can go wrong is that we get the node ID, then a bus
+ * reset occurs, and then we read the generation.  The node ID is
+ * possibly invalid, but the generation is current, and we end up
+ * sending a packet to a the wrong node.
+ *
+ * The solution is to make sure we read the generation first, so that
+ * if a reset occurs in the process, we end up with a stale generation
+ * and the transactions will fail instead of silently using wrong node
+ * ID's.
+ */
+
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
 {
-        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))
-		return NULL;
-        if (ne->nodeid == ne->host->node_id) return ne->host;
-        return NULL;
+        pkt->host = ne->host;
+        pkt->generation = ne->generation;
+	barrier();
+        pkt->node_id = ne->nodeid;
 }
 
-int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
+int hpsb_node_read(struct node_entry *ne, u64 addr,
+		   quadlet_t *buffer, size_t length)
 {
-        if (atomic_read(&ne->generation) != get_hpsb_generation(ne->host))
-		return 0;
+	unsigned int generation = ne->generation;
 
-        pkt->host = ne->host;
-        pkt->node_id = ne->nodeid;
-        pkt->generation = atomic_read(&ne->generation);
-        return 1;
+	barrier();
+	return hpsb_read(ne->host, ne->nodeid, generation,
+			 addr, buffer, length);
+}
+
+int hpsb_node_write(struct node_entry *ne, u64 addr, 
+		    quadlet_t *buffer, size_t length)
+{
+	unsigned int generation = ne->generation;
+
+	barrier();
+	return hpsb_write(ne->host, ne->nodeid, generation,
+			  addr, buffer, length);
+}
+
+int hpsb_node_lock(struct node_entry *ne, u64 addr, 
+		   int extcode, quadlet_t *data, quadlet_t arg)
+{
+	unsigned int generation = ne->generation;
+
+	barrier();
+	return hpsb_lock(ne->host, ne->nodeid, generation,
+			 addr, extcode, data, arg);
 }
 
 static void nodemgr_add_host(struct hpsb_host *host)
@@ -1169,23 +1250,24 @@
 		return;
 	}
 
-	/* We simply initialize the struct here. We don't start the thread
-	 * until the first bus reset.  */
+	/* Initialize the hostinfo here and start the thread.  The
+	 * thread blocks on the reset semaphore until a bus reset
+	 * happens. */
 	hi->host = host;
 	INIT_LIST_HEAD(&hi->list);
-	init_completion(&hi->started);
 	init_completion(&hi->exited);
-	init_waitqueue_head(&hi->wait);
-
-	hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+        sema_init(&hi->reset_sem, 0);
 
+	hi->pid = kernel_thread(nodemgr_host_thread, hi,
+				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	
 	if (hi->pid < 0) {
-		HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s", host->driver->name);
+		HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s",
+			  host->driver->name);
+		kfree(hi);
 		return;
 	}
 
-	wait_for_completion(&hi->started);
-
 	spin_lock_irqsave (&host_info_lock, flags);
 	list_add_tail (&hi->list, &host_info_list);
 	spin_unlock_irqrestore (&host_info_lock, flags);
@@ -1216,8 +1298,7 @@
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_DEBUG ("NodeMgr: Processing host reset for %s", host->driver->name);
 #endif
-
-	wake_up(&hi->wait);
+	up(&hi->reset_sem);
 
 done_reset_host:
 	spin_unlock_irqrestore (&host_info_lock, flags);
@@ -1254,7 +1335,7 @@
 		ne = list_entry(lh, struct node_entry, list);
 
 		if (ne->host == host)
-		nodemgr_remove_node(ne);
+			nodemgr_remove_node(ne);
 	}
 	write_unlock_irqrestore(&node_lock, flags);
 
@@ -1279,8 +1360,9 @@
 
 #define PROC_ENTRY "devices"
 
-void init_ieee1394_nodemgr(void)
+void init_ieee1394_nodemgr(int disable_hotplug)
 {
+	nodemgr_disable_hotplug = disable_hotplug;
 #ifdef CONFIG_PROC_FS
 	if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL))
 		HPSB_ERR("Can't create devices procfs entry");
diff -urN linux-2.5.8-pre2/drivers/ieee1394/nodemgr.h linux-2.5.8-pre3/drivers/ieee1394/nodemgr.h
--- linux-2.5.8-pre2/drivers/ieee1394/nodemgr.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/nodemgr.h	Tue Apr  9 18:35:19 2002
@@ -125,7 +125,7 @@
 	struct hpsb_host *host;		/* Host this node is attached to */
 	nodeid_t nodeid;		/* NodeID */
 	struct bus_options busopt;	/* Bus Options */
-	atomic_t generation;		/* Synced with hpsb generation */
+	unsigned int generation;	/* Synced with hpsb generation */
 
 	/* The following is read from the config rom */
 	u32 vendor_id;
@@ -138,7 +138,7 @@
 
 static inline int hpsb_node_entry_valid(struct node_entry *ne)
 {
-	return atomic_read(&ne->generation) == get_hpsb_generation(ne->host);
+	return ne->generation == get_hpsb_generation(ne->host);
 }
 
 /*
@@ -170,10 +170,17 @@
  * number).  It will at least reliably fail so that you don't accidentally and
  * unknowingly send your packet to the wrong node.
  */
-int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
 
+int hpsb_node_read(struct node_entry *ne, u64 addr,
+		   quadlet_t *buffer, size_t length);
+int hpsb_node_write(struct node_entry *ne, u64 addr, 
+		    quadlet_t *buffer, size_t length);
+int hpsb_node_lock(struct node_entry *ne, u64 addr, 
+		   int extcode, quadlet_t *data, quadlet_t arg);
 
-void init_ieee1394_nodemgr(void);
+
+void init_ieee1394_nodemgr(int disable_hotplug);
 void cleanup_ieee1394_nodemgr(void);
 
 #endif /* _IEEE1394_NODEMGR_H */
diff -urN linux-2.5.8-pre2/drivers/ieee1394/ohci1394.c linux-2.5.8-pre3/drivers/ieee1394/ohci1394.c
--- linux-2.5.8-pre2/drivers/ieee1394/ohci1394.c	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/ohci1394.c	Tue Apr  9 18:35:19 2002
@@ -96,7 +96,6 @@
 #include <linux/poll.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
-#include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/tqueue.h>
 #include <linux/delay.h>
@@ -161,7 +160,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Revision: 1.91 $ Ben Collins <bcollins@debian.org>";
+	"$Revision: 1.101 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -487,7 +486,6 @@
 /* Global initialization */
 static void ohci_initialize(struct ti_ohci *ohci)
 {
-	int i;
 	quadlet_t buf;
 
 	spin_lock_init(&ohci->phy_reg_lock);
@@ -535,14 +533,6 @@
 	/* Don't accept phy packets into AR request context */ 
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
 
-	/* Initialize IR dma */
-	for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
-		reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
-			  0xffffffff);
-		reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);
-		reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);
-	}
-
 	/* Set bufferFill, isochHeader, multichannel for IR context */
 	reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);
 			
@@ -553,13 +543,6 @@
 	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
 
-	/* Initialize IT dma */
-	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
-		reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
-			  0xffffffff);
-		reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);
-	}
-	
 	/* Clear the interrupt mask */
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
@@ -615,7 +598,8 @@
 		  OHCI1394_respTxComplete |
 		  OHCI1394_reqTxComplete |
 		  OHCI1394_isochRx |
-		  OHCI1394_isochTx);
+		  OHCI1394_isochTx |
+		  OHCI1394_cycleInconsistent);
 
 	/* Enable link */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
@@ -936,6 +920,7 @@
                 } else {
                         MOD_DEC_USE_COUNT;
                 }
+		retval = 1;
                 break;
 
 	case ISO_LISTEN_CHANNEL:
@@ -1098,6 +1083,14 @@
 		return;
 	}
 
+	if (event & OHCI1394_cycleInconsistent) {
+		/* We subscribe to the cycleInconsistent event only to
+		 * clear the corresponding event bit... otherwise,
+		 * isochronous cycleMatch DMA wont work. */
+		DBGMSG(ohci->id, "OHCI1394_cycleInconsistent");
+		event &= ~OHCI1394_cycleInconsistent;
+	}
+
 	if (event & OHCI1394_busReset) {
 		/* The busReset event bit can't be cleared during the
 		 * selfID phase, so we disable busReset interrupts, to
@@ -1265,8 +1258,8 @@
 		/* Finally, we clear the busReset event and reenable
 		 * the busReset interrupt. */
 		spin_lock_irqsave(&ohci->event_lock, flags);
-		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
 		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
 		event &= ~OHCI1394_selfIDComplete;	
 	}
@@ -1509,6 +1502,15 @@
 			/* this packet hasn't been sent yet*/
 			break;
 
+		if (!(ack & 0x10)) {
+			/* XXX: This is an OHCI evt_* code. We need to handle
+			 * this specially! For right now, we just fake an
+			 * ackx_send_error. */
+			PRINT(KERN_DEBUG, ohci->id, "Received OHCI evt_* error 0x%x",
+			       ack & 0xf);
+			ack = (ack & 0xffe0) | ACK_BUSY_A;
+		}
+
 #ifdef OHCI1394_DEBUG
 		if (datasize)
 			DBGMSG(ohci->id,
@@ -1942,7 +1944,8 @@
 
 	/* Root directory */
 	cf_unit_begin(&cr, 1);
-	cf_put_keyval(&cr, 0x03, 0x00005e);	/* Vendor ID */
+	/* Vendor ID */
+	cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF);
 	cf_put_refer(&cr, 0x81, 2);		/* Textual description unit */
 	cf_put_keyval(&cr, 0x0c, 0x0083c0);	/* Node capabilities */
 	/* NOTE: Add other unit referers here, and append at bottom */
@@ -2287,7 +2290,7 @@
 #endif /* CONFIG_ALL_PPC */
 
 	pci_set_drvdata(ohci->dev, NULL);
-	kfree(ohci);
+	hpsb_unref_host(ohci->host);
 }
 
 #define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
diff -urN linux-2.5.8-pre2/drivers/ieee1394/ohci1394.h linux-2.5.8-pre3/drivers/ieee1394/ohci1394.h
--- linux-2.5.8-pre2/drivers/ieee1394/ohci1394.h	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/ohci1394.h	Tue Apr  9 18:35:19 2002
@@ -22,6 +22,7 @@
 #define _OHCI1394_H
 
 #include "ieee1394_types.h"
+#include <asm/io.h>
 
 #define OHCI1394_DRIVER_NAME      "ohci1394"
 
@@ -192,7 +193,7 @@
 
 	/* IRQ hooks, for video1394 and dv1394 */
 	
-#define OHCI1394_MAX_IRQ_HOOKS 4
+#define OHCI1394_MAX_IRQ_HOOKS 16
 	
 	struct ohci1394_irq_hook {
 		void (*irq_handler) (int card, quadlet_t isoRecvEvent, 
@@ -314,7 +315,7 @@
 #define OHCI1394_AsRspRcvCommandPtr           0x1EC
 
 /* Isochronous transmit registers */
-/* Add (32 * n) for context n */
+/* Add (16 * n) for context n */
 #define OHCI1394_IsoXmitContextBase           0x200
 #define OHCI1394_IsoXmitContextControlSet     0x200
 #define OHCI1394_IsoXmitContextControlClear   0x204
@@ -363,6 +364,28 @@
 #define DMA_CTL_BRANCH                   0x000c0000
 #define DMA_CTL_WAIT                     0x00030000
 
+/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
+#define EVT_NO_STATUS		0x0	/* No event status */
+#define EVT_RESERVED		0x1	/* Reserved, not used !!! */
+#define EVT_LONG_PACKET		0x2	/* The revc data was longer than the buf */
+#define EVT_MISSING_ACK		0x3	/* A subaction gap was detected before an ack
+					   arrived, or recv'd ack had a parity error */
+#define EVT_UNDERRUN		0x4	/* Underrun on corresponding FIFO, packet
+					   truncated */
+#define EVT_OVERRUN		0x5	/* A recv FIFO overflowed on reception of ISO
+					   packet */
+#define EVT_DESCRIPTOR_READ	0x6	/* An unrecoverable error occured while host was
+					   reading a descriptor block */
+#define EVT_DATA_READ		0x7	/* An error occured while host controller was
+					   attempting to read from host memory in the data
+					   stage of descriptor processing */
+#define EVT_DATA_WRITE		0x8	/* An error occured while host controller was
+					   attempting to write either during the data stage
+					   of descriptor processing, or when processing a single
+					   16-bit host memory write */
+#define EVT_BUS_RESET		0x9	/* Identifies a PHY packet in the recv buffer as
+					   being a synthesized bus reset packet */
+
 #define OHCI1394_TCODE_PHY               0xE
 
 void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
diff -urN linux-2.5.8-pre2/drivers/ieee1394/pcilynx.c linux-2.5.8-pre3/drivers/ieee1394/pcilynx.c
--- linux-2.5.8-pre2/drivers/ieee1394/pcilynx.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/pcilynx.c	Tue Apr  9 18:35:19 2002
@@ -29,7 +29,6 @@
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -56,6 +55,7 @@
 #define PRINTD(level, card, fmt, args...) do {} while (0)
 #endif
 
+
 static struct hpsb_host_driver *lynx_driver;
 static unsigned int card_id;
 
@@ -614,7 +614,7 @@
 
 
 static struct file_operations aux_ops = {
-        OWNER_THIS_MODULE
+	owner:		THIS_MODULE,
         read:           mem_read,
         write:          mem_write,
         poll:           aux_poll,
@@ -639,42 +639,31 @@
         enum { t_rom, t_aux, t_ram } type;
         struct memdata *md;
         
-        V22_COMPAT_MOD_INC_USE_COUNT;
-
         if (cid < PCILYNX_MINOR_AUX_START) {
                 /* just for completeness */
-                V22_COMPAT_MOD_DEC_USE_COUNT;
                 return -ENXIO;
         } else if (cid < PCILYNX_MINOR_ROM_START) {
                 cid -= PCILYNX_MINOR_AUX_START;
-                if (cid >= num_of_cards || !cards[cid].aux_port) {
-                        V22_COMPAT_MOD_DEC_USE_COUNT;
+                if (cid >= num_of_cards || !cards[cid].aux_port)
                         return -ENXIO;
-                }
                 type = t_aux;
         } else if (cid < PCILYNX_MINOR_RAM_START) {
                 cid -= PCILYNX_MINOR_ROM_START;
-                if (cid >= num_of_cards || !cards[cid].local_rom) {
-                        V22_COMPAT_MOD_DEC_USE_COUNT;
+                if (cid >= num_of_cards || !cards[cid].local_rom)
                         return -ENXIO;
-                }
                 type = t_rom;
         } else {
                 /* WARNING: Know what you are doing when opening RAM.
                  * It is currently used inside the driver! */
                 cid -= PCILYNX_MINOR_RAM_START;
-                if (cid >= num_of_cards || !cards[cid].local_ram) {
-                        V22_COMPAT_MOD_DEC_USE_COUNT;
+                if (cid >= num_of_cards || !cards[cid].local_ram)
                         return -ENXIO;
-                }
                 type = t_ram;
         }
 
         md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);
-        if (md == NULL) {
-                V22_COMPAT_MOD_DEC_USE_COUNT;
+        if (md == NULL)
                 return -ENOMEM;
-        }
 
         md->lynx = &cards[cid];
         md->cid = cid;
@@ -700,11 +689,7 @@
 
 static int mem_release(struct inode *inode, struct file *file)
 {
-        struct memdata *md = (struct memdata *)file->private_data;
-
-        kfree(md);
-
-        V22_COMPAT_MOD_DEC_USE_COUNT;
+        kfree(file->private_data);
         return 0;
 }
 
@@ -732,9 +717,8 @@
 
 loff_t mem_llseek(struct file *file, loff_t offs, int orig)
 {
-        loff_t newoffs = -1;
+        loff_t newoffs;
 
-        lock_kernel();
         switch (orig) {
         case 0:
                 newoffs = offs;
@@ -744,14 +728,13 @@
                 break;
         case 2:
                 newoffs = PCILYNX_MAX_MEMORY + 1 + offs;
-        }
-
-        if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) {
-                unlock_kernel();
+                break;
+        default:
                 return -EINVAL;
         }
 
-        unlock_kernel();
+        if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL;
+
         file->f_pos = newoffs;
         return newoffs;
 }
@@ -1229,7 +1212,7 @@
         }
 
 	tasklet_kill(&lynx->iso_rcv.tq);
-        kfree(lynx);
+	hpsb_unref_host(lynx->host);
 }
 
 
diff -urN linux-2.5.8-pre2/drivers/ieee1394/raw1394.c linux-2.5.8-pre3/drivers/ieee1394/raw1394.c
--- linux-2.5.8-pre2/drivers/ieee1394/raw1394.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/raw1394.c	Tue Apr  9 18:35:19 2002
@@ -21,10 +21,7 @@
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
 #include <linux/devfs_fs_kernel.h>
-#endif
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -919,13 +916,9 @@
                 return -ENXIO;
         }
 
-        V22_COMPAT_MOD_INC_USE_COUNT;
-
         fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
-        if (fi == NULL) {
-                V22_COMPAT_MOD_DEC_USE_COUNT;
+        if (fi == NULL)
                 return -ENOMEM;
-        }
         
         memset(fi, 0, sizeof(struct file_info));
 
@@ -988,7 +981,6 @@
 
         kfree(fi);
 
-        V22_COMPAT_MOD_DEC_USE_COUNT;
         return 0;
 }
 
@@ -1001,12 +993,12 @@
 };
 
 static struct file_operations file_ops = {
-        OWNER_THIS_MODULE
-        read:     raw1394_read, 
-        write:    raw1394_write, 
-        poll:     raw1394_poll, 
-        open:     raw1394_open, 
-        release:  raw1394_release, 
+	owner:		THIS_MODULE,
+        read:		raw1394_read, 
+        write:		raw1394_write, 
+        poll:		raw1394_poll, 
+        open:		raw1394_open, 
+        release:	raw1394_release, 
 };
 
 static int __init init_raw1394(void)
diff -urN linux-2.5.8-pre2/drivers/ieee1394/sbp2.c linux-2.5.8-pre3/drivers/ieee1394/sbp2.c
--- linux-2.5.8-pre2/drivers/ieee1394/sbp2.c	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/sbp2.c	Tue Apr  9 18:35:19 2002
@@ -27,6 +27,7 @@
  * driver. It also registers as a SCSI lower-level driver in order to accept
  * SCSI commands for transport using SBP-2.
  *
+ *
  * Driver Loading:
  *
  * Currently, the SBP-2 driver is supported only as a module. Because the 
@@ -45,7 +46,7 @@
  *
  * Currently, the SBP-2 driver will catch any attached SBP-2 devices during the
  * initial scsi bus scan (when the driver is first loaded). To add or remove
- * SBP-2 devices after this initial scan (i.e. if you plug-in or un-plug a 
+ * SBP-2 devices "after" this initial scan (i.e. if you plug-in or un-plug a 
  * device after the SBP-2 driver is loaded), you must either use the scsi procfs
  * add-single-device, remove-single-device, or a shell script such as 
  * rescan-scsi-bus.sh.
@@ -76,6 +77,19 @@
  * fdisk, mkfs, etc.).
  *
  *
+ * Module Load Options:
+ *
+ * sbp2_max_speed 		- Force max speed allowed 
+ *				  (2 = 400mb, 1 = 200mb, 0 = 100mb. default = 2)
+ * sbp2_serialize_io		- Serialize all I/O coming down from the scsi drivers 
+ *				  (0 = deserialized, 1 = serialized, default = 0)
+ * sbp2_max_sectors, 		- Change max sectors per I/O supported (default = 255)
+ * sbp2_max_outstanding_cmds	- Change max outstanding concurrent commands (default = 8)
+ * sbp2_max_cmds_per_lun	- Change max concurrent commands per sbp2 device (default = 1)
+ *
+ * (e.g. insmod sbp2 sbp2_serialize_io = 1)
+ *
+ *
  * Current Support:
  *
  * The SBP-2 driver is still in an early state, but supports a variety of devices.
@@ -83,7 +97,8 @@
  * performance of more than 25 MBytes/s on individual drives (limit of the media 
  * transfer rate).
  *
- * Following are the devices that have been tested successfully:
+ *
+ * Following are a sampling of devices that have been tested successfully:
  *
  *	- Western Digital IEEE-1394 hard drives
  *	- Maxtor IEEE-1394 hard drives
@@ -102,7 +117,7 @@
  *	- APDrives IEEE-1394 hard drives
  *	- Fujitsu IEEE-1394 MO drives
  *	- Sony IEEE-1394 CD-RW drives
- *	- Epson IEEE-1394 scanner
+ *	- Epson IEEE-1394 scanners
  *	- ADS IEEE-1394 memory stick and compact flash readers 
  *	- SBP-2 bridge-based devices (LSI, Oxford Semiconductor, Indigita bridges)
  *	- Various other standard IEEE-1394 hard drives and enclosures
@@ -117,10 +132,6 @@
  *
  * Current Issues:
  *
- *	- Currently, all I/O from the scsi stack is serialized by default, as there
- *	  are some stress issues under investigation with deserialized I/O. To enable
- *	  deserialized I/O for testing, do "insmod sbp2 serialize_io=0"
- *
  *	- Error Handling: SCSI aborts and bus reset requests are handled somewhat
  *	  but the code needs additional debugging.
  *
@@ -246,6 +257,28 @@
  *		   1394 devices (Peerless, Jazz). Also a bit of clean-up of the 
  *		   driver, thanks to H.J.Lu (hjl@lucon.org). Removed mode_sense_hack
  *		   module load option, as it's been fixed in the 2.4 scsi stack.
+ *	02/10/02 - Added support for max_sectors, minor fix for inquiry command, make
+ *		   up sbp2 device type from inquiry response data if not part of 
+ *		   device's 1394 unit directory. (JSG)
+ *	02/18/02 - Code clean-up and enhancements: (JSG)
+ *		   * Finish cleaning out hacked code for dealing with broken sbp2 devices
+ *		     which do not support requests of 128KB or greater. Now use 
+ *		     max_sectors scsi host entry to limit transfer sizes.
+ *		   * Change status fifo address from a single address to a set of addresses,
+ *		     with each sbp2 device having it's own status fifo address. This makes
+ *		     it easier to match the status write to the sbp2 device instance.
+ *		   * Minor change to use lun when logging into sbp2 devices. First step in
+ *		     supporting multi-lun devices such as CD/DVD changer devices.
+ *		   * Added a new module load option for setting max sectors. For use by folk
+ *		     who'd like to bump up the max scsi transfer size supported.
+ *		   * Enabled deserialized operation by default, allowing for better performance,
+ *		     particularily when running with multiple sbp2 devices. For debugging,
+ *		     you may enable serialization through use of the sbp2_serialize_io module
+ *		     load option (e.g. insmod sbp2 sbp2_serialize_io=1).
+ *	02/20/02 - Added a couple additional module load options. 
+ *		   Needed to bump down max commands per lun because of the !%@&*^# QPS CDRW 
+ *		   drive I have, which doesn't seem to get along with other sbp2 devices 
+ *		   (or handle linked commands well).  
  */
 
 
@@ -301,7 +334,7 @@
  */
 
 /*
- * Change max_speed on module load if you have a bad IEEE-1394 controller
+ * Change sbp2_max_speed on module load if you have a bad IEEE-1394 controller
  * that has trouble running 2KB packets at 400mb.
  *
  * NOTE: On certain OHCI parts I have seen short packets on async transmit
@@ -309,31 +342,51 @@
  * bump down the speed if you are running into problems.
  *
  * Valid values:
- * max_speed = 2 (default: max speed 400mb)
- * max_speed = 1 (max speed 200mb)
- * max_speed = 0 (max speed 100mb)
+ * sbp2_max_speed = 2 (default: max speed 400mb)
+ * sbp2_max_speed = 1 (max speed 200mb)
+ * sbp2_max_speed = 0 (max speed 100mb)
  */
-MODULE_PARM(max_speed,"i");
-MODULE_PARM_DESC(max_speed, "Force down max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)");
-static int max_speed = SPEED_400;
+MODULE_PARM(sbp2_max_speed,"i");
+MODULE_PARM_DESC(sbp2_max_speed, "Force max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)");
+static int sbp2_max_speed = SPEED_400;
 
 /*
- * Set serialize_io to 1 if you'd like only one scsi command sent down to
- * us at a time (debugging).
+ * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent down to
+ * us at a time (debugging). This might be necessary for very badly behaved sbp2 devices.
  */
-MODULE_PARM(serialize_io,"i");
-MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (debugging)");
-static int serialize_io = 1;	/* serialize I/O until stress issues are resolved */
+MODULE_PARM(sbp2_serialize_io,"i");
+MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
+static int sbp2_serialize_io = 0;	/* serialize I/O - available for debugging purposes */
 
 /*
- * Set no_large_packets to 1 if you'd like to limit the size of requests
- * sent down to us (normally the sbp2 driver will break up any requests to
- * any individual devices with 128KB transfer size limits).  Sets max s/g
- * list elements to 0x1f in size and disables s/g clustering.
+ * Bump up sbp2_max_sectors if you'd like to support very large sized transfers. Please note 
+ * that some older sbp2 bridge chips are broken for transfers greater or equal to 128KB.
+ * Default is a value of 255 sectors, or just under 128KB (at 512 byte sector size). I can note
+ * that the Oxsemi sbp2 chipsets have no problems supporting very large transfer sizes.
  */
-MODULE_PARM(no_large_packets,"i");
-MODULE_PARM_DESC(no_large_packets, "Do not allow large transfers from scsi drivers (debugging)");
-static int no_large_packets = 0;
+MODULE_PARM(sbp2_max_sectors,"i");
+MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)");
+static int sbp2_max_sectors = SBP2_MAX_SECTORS;
+
+/*
+ * Adjust sbp2_max_outstanding_cmds to tune performance if you have many sbp2 devices attached
+ * (or if you need to do some debugging).
+ */
+MODULE_PARM(sbp2_max_outstanding_cmds,"i");
+MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)");
+static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS;
+
+/*
+ * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than one concurrent/linked 
+ * command per sbp2 device may allow some performance gains, but some older sbp2 devices have 
+ * firmware bugs resulting in problems when linking commands... so, enable this with care. 
+ * I can note that the Oxsemi OXFW911 sbp2 chipset works very well with large numbers of 
+ * concurrent/linked commands.  =)
+ */
+MODULE_PARM(sbp2_max_cmds_per_lun,"i");
+MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)");
+static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN;
+
 
 /*
  * Export information about protocols/devices supported by this driver.
@@ -351,9 +404,14 @@
 MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
 
 /*
- * Debug levels, configured via kernel config.
+ * Debug levels, configured via kernel config, or enable here.
  */
 
+/* #define CONFIG_IEEE1394_SBP2_DEBUG_ORBS */
+/* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA */
+/* #define CONFIG_IEEE1394_SBP2_DEBUG 1 */
+/* #define CONFIG_IEEE1394_SBP2_DEBUG 2 */
+
 #ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS
 #define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)
 static u32 global_outstanding_command_orbs = 0;
@@ -390,9 +448,9 @@
 #define SBP2_WARN(fmt, args...)		HPSB_WARN("sbp2: "fmt, ## args)
 #else 
 #define SBP2_DEBUG(fmt, args...)
-#define SBP2_INFO(fmt, args...)
-#define SBP2_NOTICE(fmt, args...)
-#define SBP2_WARN(fmt, args...)
+#define SBP2_INFO(fmt, args...)		HPSB_INFO("sbp2: "fmt, ## args)
+#define SBP2_NOTICE(fmt, args...)       HPSB_NOTICE("sbp2: "fmt, ## args)
+#define SBP2_WARN(fmt, args...)         HPSB_WARN("sbp2: "fmt, ## args)
 #endif
 
 #define SBP2_ERR(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
@@ -490,7 +548,19 @@
 	struct hpsb_packet *packet;
 	int i;
 
-	/* Create SBP2_MAX_REQUEST_PACKETS number of request packets. */
+	hi->request_packet = kmalloc(sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS, 
+				     GFP_KERNEL);
+
+	if (!hi->request_packet) {
+		SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!");
+		return(-ENOMEM);
+	}
+	memset(hi->request_packet, 0, sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS);
+
+	/* 
+	 * Create a pool of request packets. Just take the max supported 
+	 * concurrent commands and multiply by two to be safe... 
+	 */
 	for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) {
 
 		/*
@@ -547,6 +617,7 @@
 		}
 
 	}
+	kfree(hi->request_packet);
 	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
 
 	return;
@@ -561,7 +632,7 @@
  */
 static struct sbp2_request_packet *
 sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
-				       nodeid_t node, u64 addr,
+				       struct node_entry *ne, u64 addr,
 				       size_t data_size,
 				       quadlet_t data) {
 	struct list_head *lh;
@@ -590,12 +661,11 @@
 		INIT_LIST_HEAD(&packet->list);
 		sema_init(&packet->state_change, 0);
 		packet->state = hpsb_unused;
-		packet->generation = get_hpsb_generation(hi->host);
 		packet->data_be = 1;
+		
+		hpsb_node_fill_packet(ne, packet);
 
-		packet->host = hi->host;
-		packet->tlabel = get_tlabel(hi->host, node, 1);
-		packet->node_id = node;
+		packet->tlabel = get_tlabel(hi->host, packet->node_id, 1);
 
 		if (!data_size) {
 			fill_async_writequad(packet, addr, data);
@@ -717,8 +787,8 @@
 }
 
 /* 
- * This functions finds the sbp2_command for a given outstanding command
- * orb. Only looks at the inuse list.
+ * This function finds the sbp2_command for a given outstanding command
+ * orb.Only looks at the inuse list.
  */
 static struct sbp2_command_info *sbp2util_find_command_for_orb(
 		struct scsi_id_instance_data *scsi_id, dma_addr_t orb)
@@ -745,7 +815,7 @@
 }
 
 /* 
- * This functions finds the sbp2_command for a given outstanding SCpnt.
+ * This function finds the sbp2_command for a given outstanding SCpnt.
  * Only looks at the inuse list.
  */
 static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
@@ -788,7 +858,6 @@
 		command = list_entry(lh, struct sbp2_command_info, list);
 		command->Current_done = Current_done;
 		command->Current_SCpnt = Current_SCpnt;
-		command->linked = 0;
 		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);
 	} else {
 		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
@@ -878,7 +947,8 @@
 	 * Register our sbp2 status address space...
 	 */
 	hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS,
-				SBP2_STATUS_FIFO_ADDRESS + sizeof(struct sbp2_status_block));
+				SBP2_STATUS_FIFO_ADDRESS + 
+				SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
 
 	hpsb_register_protocol(&sbp2_driver);
 
@@ -936,7 +1006,8 @@
 
 	if (sbp2_reconnect_device(hi, scsi_id)) {
 		
-		/* Ok, reconnect has failed.  Perhaps we didn't
+		/* 
+		 * Ok, reconnect has failed. Perhaps we didn't
 		 * reconnect fast enough. Try doing a regular login.
 		 */
 		if (sbp2_login_device(hi, scsi_id)) {
@@ -1008,8 +1079,10 @@
 
 	/* Register our host with the SCSI stack. */
 	hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *));
-	if (hi->scsi_host)
+	if (hi->scsi_host) {
 		hi->scsi_host->hostdata[0] = (unsigned long)hi;
+		hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS;
+	}
 	scsi_driver_template.present++;
 
 	return;
@@ -1190,19 +1263,11 @@
 	/* 
 	 * Knock the total command orbs down if we are serializing I/O
 	 */
-	if (serialize_io) {
+	if (sbp2_serialize_io) {
 		scsi_id->sbp2_total_command_orbs = 2;	/* one extra for good measure */
 	}
 
 	/*
-	 * Allocate some extra command orb structures for devices with
-	 * 128KB limit.
-	 */
-	if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) {
-		scsi_id->sbp2_total_command_orbs *= 4;
-	} 
-
-	/*
 	 * Find an empty spot to stick our scsi id instance data. 
 	 */
 	for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
@@ -1348,14 +1413,19 @@
 	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST);
 	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
 	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1);	/* Exclusive access to device */
-	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);		/* Notify us of login complete */
+	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);	/* Notify us of login complete */
+	/* Set the lun if we were able to pull it from the device's unit directory */
+	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
+		scsi_id->login_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
+	}
 	SBP2_DEBUG("sbp2_login_device: lun_misc initialized");
 
 	scsi_id->login_orb->passwd_resp_lengths =
 		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
 	SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized");
 
-	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
+	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
+					     SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
 	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
 					      SBP2_STATUS_FIFO_ADDRESS_HI);
 	SBP2_DEBUG("sbp2_login_device: status FIFO initialized");
@@ -1383,7 +1453,7 @@
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
 	SBP2_DEBUG("sbp2_login_device: prepared to write");
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 	SBP2_DEBUG("sbp2_login_device: written");
 
 	/*
@@ -1472,7 +1542,8 @@
 	scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
 
 	scsi_id->logout_orb->reserved5 = 0x0;
-	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
+	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
+					      SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
 	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
 					       SBP2_STATUS_FIFO_ADDRESS_HI);
 
@@ -1488,7 +1559,7 @@
 	data[1] = scsi_id->logout_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
 	/* Wait for device to logout...1 second. */
 	sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ);
@@ -1526,7 +1597,8 @@
 	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
 
 	scsi_id->reconnect_orb->reserved5 = 0x0;
-	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO;
+	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
+						 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
 	scsi_id->reconnect_orb->status_FIFO_hi =
 		(ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);
 
@@ -1547,7 +1619,7 @@
 	data[1] = scsi_id->reconnect_orb_dma;
 	sbp2util_cpu_to_be32_buffer(data, 8);
 
-	hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, scsi_id->sbp2_management_agent_addr, data, 8);
+	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 
 	/*
 	 * Wait for reconnect status... but, only if the device has not
@@ -1601,7 +1673,7 @@
 	 */
 	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
 
-	if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->ne->nodeid, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
+	if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
 		SBP2_ERR("sbp2_set_busy_timeout error");
 	}
 
@@ -1620,6 +1692,14 @@
 
 	SBP2_DEBUG("sbp2_parse_unit_directory");
 
+	/* Initialize some fields, in case an entry does not exist */
+	scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED;
+	scsi_id->sbp2_management_agent_addr = 0x0;
+	scsi_id->sbp2_command_set_spec_id = 0x0;
+	scsi_id->sbp2_command_set = 0x0;
+	scsi_id->sbp2_unit_characteristics = 0x0;
+	scsi_id->sbp2_firmware_revision = 0x0;
+
 	ud = scsi_id->ud;
 
 	/* Handle different fields in the unit directory, based on keys */
@@ -1683,7 +1763,9 @@
 			 */
 			scsi_id->sbp2_firmware_revision
 				= CONFIG_ROM_VALUE(ud->quadlets[i]);
-			if (scsi_id->sbp2_firmware_revision ==
+			SBP2_DEBUG("sbp2_firmware_revision = %x",
+				   (unsigned int) scsi_id->sbp2_firmware_revision);
+			if ((scsi_id->sbp2_firmware_revision & 0xffff00) ==
 			    SBP2_128KB_BROKEN_FIRMWARE) {
 				SBP2_WARN("warning: Bridge chipset supports 128KB max transfer size");
 			}
@@ -1713,8 +1795,8 @@
 						  + (scsi_id->ne->nodeid & NODE_MASK)];
 
 	/* Bump down our speed if the user requested it */
-	if (scsi_id->speed_code > max_speed) {
-		scsi_id->speed_code = max_speed;
+	if (scsi_id->speed_code > sbp2_max_speed) {
+		scsi_id->speed_code = sbp2_max_speed;
 		SBP2_ERR("Forcing SBP-2 max speed down to %s",
 			 hpsb_speedto_str[scsi_id->speed_code]);
 	}
@@ -1744,7 +1826,7 @@
 	 * Ok, let's write to the target's management agent register
 	 */
 	agent_reset_request_packet =
-		sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,
+		sbp2util_allocate_write_request_packet(hi, scsi_id->ne,
 						       scsi_id->sbp2_command_block_agent_addr +
 						       SBP2_AGENT_RESET_OFFSET,
 						       0, ntohl(SBP2_AGENT_RESET_DATA));
@@ -2034,8 +2116,8 @@
 	struct sbp2_command_orb *command_orb = &command->command_orb;
 
 	outstanding_orb_incr;
-	SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x",
-			command_orb, command->linked, global_outstanding_command_orbs);
+	SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",
+			command_orb, global_outstanding_command_orbs);
 
 	pci_dma_sync_single(hi->host->pdev, command->command_orb_dma,
 			    sizeof(struct sbp2_command_orb),
@@ -2054,7 +2136,7 @@
 		if (hpsb_node_entry_valid(scsi_id->ne)) {
 
 			command_request_packet =
-				sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->ne->nodeid,
+				sbp2util_allocate_write_request_packet(hi, scsi_id->ne,
 								scsi_id->sbp2_command_block_agent_addr +
 								SBP2_ORB_POINTER_OFFSET, 8, 0);
 		
@@ -2099,13 +2181,12 @@
 				    PCI_DMA_BIDIRECTIONAL);
 
 		/*
-		 * Only ring the doorbell if we need to (first parts of
-		 * linked orbs don't need this).
+		 * Ring the doorbell
 		 */
-		if (!command->linked && hpsb_node_entry_valid(scsi_id->ne)) {
+		if (hpsb_node_entry_valid(scsi_id->ne)) {
 
 			command_request_packet = sbp2util_allocate_write_request_packet(hi,
-				LOCAL_BUS | scsi_id->ne->nodeid,
+				scsi_id->ne,
 				scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET,
 				0, cpu_to_be32(command->command_orb_dma));
 	
@@ -2151,24 +2232,6 @@
 	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);
 
 	/*
-	 * Check for broken devices that can't handle greater than 128K
-	 * transfers, and deal with them in a hacked ugly way.
-	 */
-	if ((scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) && 
-	    (SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) && 
-	    (device_type == TYPE_DISK) &&
-	    (SCpnt->use_sg) &&
-	    (*cmd == READ_6 || *cmd == READ_10 || *cmd == WRITE_6 || *cmd == WRITE_10)) {
-
-		/*
-		 * Darn, a broken device. We'll need to split up the
-		 * transfer ourselves.
-		 */
-		sbp2_send_split_command(hi, scsi_id, SCpnt, done);
-		return(0);
-	}
-
-	/*
 	 * Allocate a command orb and s/g structure
 	 */
 	command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi);
@@ -2179,11 +2242,11 @@
 	/*
 	 * The scsi stack sends down a request_bufflen which does not match the
 	 * length field in the scsi cdb. This causes some sbp2 devices to 
-	 * reject this inquiry command. Fix is to fix request_bufflen to match
-	 * the value in the cdb.
+	 * reject this inquiry command. Hack fix is to set both buff length and
+	 * length field in cdb to 36. This gives best compatibility.
 	 */
 	if (*cmd == INQUIRY) {
-		request_bufflen = cmd[4];
+		request_bufflen = cmd[4] = 0x24;
 	}
 
 	/*
@@ -2215,120 +2278,6 @@
 	return(0);
 }
 
-/*
- * This function is called for broken sbp2 device, where we have to break
- * up large transfers.
- */
-static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
-				   Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-{
-	unchar *cmd = (unchar *) SCpnt->cmnd;
-	struct scatterlist *sgpnt = (struct scatterlist *) SCpnt->request_buffer;
-	struct sbp2_command_info *command;
-	unsigned int i, block_count, block_address, block_size;
-	unsigned int current_sg = 0;
-	unsigned int total_transfer = 0;
-	unsigned int total_sg = 0;
-	unchar new_cmd[12];
-
-	memset(new_cmd, 0, 12);
-	memcpy(new_cmd, cmd, COMMAND_SIZE(*cmd));
-
-	/*
-	 * Turns command into 10 byte version
-	 */
-	sbp2_check_sbp2_command(new_cmd);
-        
-	/*
-	 * Pull block size, block address, block count from command sent down
-	 */
-	block_count = (cmd[7] << 8) | cmd[8];
-	block_address = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5]; 
-	block_size = SCpnt->request_bufflen/block_count;
-
-	/*
-	 * Walk the scsi s/g list to determine how much we can transfer in one pop
-	 */
-	for (i=0; i<SCpnt->use_sg; i++) {
-
-		total_transfer+=sgpnt[i].length;
-		total_sg++;
-
-		if (total_transfer > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) {
-
-			/*
-			 * Back everything up one, so that we're less than 128KB
-			 */
-			total_transfer-=sgpnt[i].length;
-			total_sg--;
-			i--;
-
-			command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi);
-			if (!command) {
-				return(-EIO);
-			}
-
-			/*
-			 * This is not the final piece, so mark it as linked
-			 */
-			command->linked = 1;
-
-			block_count = total_transfer/block_size;
-			new_cmd[2] = (unchar) (block_address >> 24) & 0xff;
-			new_cmd[3] = (unchar) (block_address >> 16) & 0xff;
-			new_cmd[4] = (unchar) (block_address >> 8) & 0xff;
-			new_cmd[5] = (unchar) block_address & 0xff;
-			new_cmd[7] = (unchar) (block_count >> 8) & 0xff;
-			new_cmd[8] = (unchar) block_count & 0xff;
-			block_address+=block_count;
-
-			sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, 
-						total_transfer, &sgpnt[current_sg],
-						SCpnt->sc_data_direction);
-
-			/*
-			 * Link up the orb, and ring the doorbell if needed
-			 */
-			memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
-			sbp2_link_orb_command(hi, scsi_id, command);
-
-			current_sg += total_sg;
-			total_sg = 0;
-			total_transfer = 0;
-
-		}
-
-	}
-
-	/*
-	 * Get the last piece...
-	 */
-	command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi);
-	if (!command) {
-		return(-EIO);
-	}
-
-	block_count = total_transfer/block_size;
-	new_cmd[2] = (unchar) (block_address >> 24) & 0xff;
-	new_cmd[3] = (unchar) (block_address >> 16) & 0xff;
-	new_cmd[4] = (unchar) (block_address >> 8) & 0xff;
-	new_cmd[5] = (unchar) block_address & 0xff;
-	new_cmd[7] = (unchar) (block_count >> 8) & 0xff;
-	new_cmd[8] = (unchar) block_count & 0xff;
-
-	sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, 
-				total_transfer, &sgpnt[current_sg],
-				SCpnt->sc_data_direction);
-
-	/*
-	 * Link up the orb, and ring the doorbell if needed
-	 */
-	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
-	sbp2_link_orb_command(hi, scsi_id, command);
-
-
-	return(0);
-}
 
 /*
  * This function deals with command set differences between Linux scsi
@@ -2469,6 +2418,15 @@
 		case INQUIRY:
 
 			/*
+			 * If scsi_id->sbp2_device_type_and_lun is uninitialized, then fill 
+			 * this information in from the inquiry response data. Lun is set to zero.
+			 */
+			if (scsi_id->sbp2_device_type_and_lun == SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
+				SBP2_DEBUG("Creating sbp2_device_type_and_lun from scsi inquiry data");
+				scsi_id->sbp2_device_type_and_lun = (scsi_buf[0] & 0x1f) << 16;
+			}
+
+			/*
 			 * Make sure data length is ok. Minimum length is 36 bytes
 			 */
 			if (scsi_buf[4] == 0) {
@@ -2529,7 +2487,7 @@
 {
 	struct sbp2scsi_host_info *hi = NULL;
 	struct scsi_id_instance_data *scsi_id = NULL;
-	int i;
+	u32 id;
 	unsigned long flags;
 	Scsi_Cmnd *SCpnt = NULL;
 	u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
@@ -2554,17 +2512,11 @@
 	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
 
 	/*
-	 * Find our scsi_id structure
+	 * Find our scsi_id structure by looking at the status fifo address written to by
+	 * the sbp2 device.
 	 */
-	for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) {
-		if (hi->scsi_id[i]) {
-			if ((hi->scsi_id[i]->ne->nodeid & NODE_MASK) == (nodeid & NODE_MASK)) {
-				scsi_id = hi->scsi_id[i];
-				SBP2_DEBUG("SBP-2 status write from node %x", scsi_id->ne->nodeid);
-				break;
-			}
-		}
-	}
+	id = SBP2_STATUS_FIFO_OFFSET_TO_ENTRY((u32)(addr - SBP2_STATUS_FIFO_ADDRESS)); 
+	scsi_id = hi->scsi_id[id];
 
 	if (!scsi_id) {
 		SBP2_ERR("scsi_id is NULL - device is gone?");
@@ -2605,12 +2557,12 @@
 		SCpnt = command->Current_SCpnt;
 		sbp2util_mark_command_completed(scsi_id, command);
 
-		if (SCpnt && !command->linked) {
+		if (SCpnt) {
 
 			/*
 			 * See if the target stored any scsi status information
 			 */
-			if (length > 8) {
+			if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) {
 				/*
 				 * Translate SBP-2 status to SCSI sense data
 				 */
@@ -2657,7 +2609,6 @@
 	return(RCODE_COMPLETE);
 }
 
-
 
 /**************************************
  * SCSI interface related section
@@ -2722,8 +2673,7 @@
 	}
 
 	/*
-	 * Check to see if there is a command in progress and just return
-	 * busy (to be queued later)
+	 * Check to see if we are in the middle of a bus reset.
 	 */
 	if (!hpsb_node_entry_valid(scsi_id->ne)) {
 		SBP2_ERR("Bus reset in progress - rejecting command");
@@ -2769,7 +2719,7 @@
 				    sizeof(command->scatter_gather_element),
 				    PCI_DMA_BIDIRECTIONAL);
 		sbp2util_mark_command_completed(scsi_id, command);
-		if (command->Current_SCpnt && !command->linked) {
+		if (command->Current_SCpnt) {
 			void (*done)(Scsi_Cmnd *) = command->Current_done;
 			command->Current_SCpnt->result = status << 16;
 			done (command->Current_SCpnt);
@@ -2873,14 +2823,22 @@
 	 * or hot-plug...
 	 */
 	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
-		SBP2_INFO("UNIT ATTENTION - return busy");
+		SBP2_DEBUG("UNIT ATTENTION - return busy");
 		SCpnt->result = DID_BUS_BUSY << 16;
 	}
 
 	/*
 	 * Tell scsi stack that we're done with this command
 	 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	spin_lock_irq(&io_request_lock);
+	done (SCpnt);
+	spin_unlock_irq(&io_request_lock);
+#else
+	spin_lock_irq(&hi->scsi_host->host_lock);
 	done (SCpnt);
+	spin_unlock_irq(&hi->scsi_host->host_lock);
+#endif
 
 	return;
 }
@@ -2903,30 +2861,27 @@
 
 		/*
 		 * Right now, just return any matching command structures
-		 * to the free pool (there may be more than one because of
-		 * broken up/linked commands).
+		 * to the free pool.
 		 */
 		sbp2_spin_lock(&hi->sbp2_command_lock, flags);
-		do {
-			command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
-			if (command) {
-				SBP2_DEBUG("Found command to abort");
-				pci_dma_sync_single(hi->host->pdev,
-						    command->command_orb_dma,
-						    sizeof(struct sbp2_command_orb),
-						    PCI_DMA_BIDIRECTIONAL);
-				pci_dma_sync_single(hi->host->pdev,
-						    command->sge_dma,
-						    sizeof(command->scatter_gather_element),
-						    PCI_DMA_BIDIRECTIONAL);
-				sbp2util_mark_command_completed(scsi_id, command);
-				if (command->Current_SCpnt && !command->linked) {
-					void (*done)(Scsi_Cmnd *) = command->Current_done;
-					command->Current_SCpnt->result = DID_ABORT << 16;
-					done (command->Current_SCpnt);
-				}
+		command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
+		if (command) {
+			SBP2_DEBUG("Found command to abort");
+			pci_dma_sync_single(hi->host->pdev,
+					    command->command_orb_dma,
+					    sizeof(struct sbp2_command_orb),
+					    PCI_DMA_BIDIRECTIONAL);
+			pci_dma_sync_single(hi->host->pdev,
+					    command->sge_dma,
+					    sizeof(command->scatter_gather_element),
+					    PCI_DMA_BIDIRECTIONAL);
+			sbp2util_mark_command_completed(scsi_id, command);
+			if (command->Current_SCpnt) {
+				void (*done)(Scsi_Cmnd *) = command->Current_done;
+				command->Current_SCpnt->result = DID_ABORT << 16;
+				done (command->Current_SCpnt);
 			}
-		} while (command);
+		}
 
 		/*
 		 * Initiate a fetch agent reset. 
@@ -2945,12 +2900,13 @@
 static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) 
 {
 	struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
+	struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->target];
 
 	SBP2_ERR("reset requested");
 
-	if (hi) {
+	if (scsi_id) {
 		SBP2_ERR("Generating IEEE-1394 bus reset");
-		hpsb_reset_bus(hi->host, LONG_RESET);
+		sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
 	}
 
 	return(SUCCESS);
@@ -2990,7 +2946,7 @@
 	SBP2_DEBUG("sbp2scsi_detect");
 
 	/*
-	 * Call sbp2_init to register with the ieee1394 stack.  This
+	 * Call sbp2_init to register with the ieee1394 stack. This
 	 * results in a callback to sbp2_add_host for each ieee1394
 	 * host controller currently registered, and for each of those
 	 * we register a scsi host with the scsi stack.
@@ -3013,8 +2969,19 @@
 	if (!hi) /* shouldn't happen, but... */
         	return "IEEE-1394 SBP-2 protocol driver";
 
-	sprintf(info, "IEEE-1394 SBP-2 protocol driver\nHost Driver: %s\nSerial I/O: %s",
-		hi->host->driver->name, serialize_io ? "yes" : "no");
+	sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n"
+		"SBP-2 module load options:\n"
+		"- Max speed supported: %s\n"
+		"- Max sectors per I/O supported: %d\n"
+		"- Max outstanding commands supported: %d\n"
+		"- Max outstanding commands per lun supported: %d\n"
+                "- Serialized I/O (debug): %s",
+		hi->host->driver->name, 
+		hpsb_speedto_str[sbp2_max_speed],
+		sbp2_max_sectors,
+		sbp2_max_outstanding_cmds,
+		sbp2_max_cmds_per_lun,
+		sbp2_serialize_io ? "yes" : "no");
 
 	return info;
 }
@@ -3025,17 +2992,6 @@
 MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
 MODULE_LICENSE("GPL");
 
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,26)
-#define PROC_SCSI_SBP2 PROC_SCSI_NOT_PRESENT /* What should I use? */
-static struct proc_dir_entry proc_scsi_sbp2scsi = {
-	low_ino:	PROC_SCSI_SBP2,
-	namelen:	SBP2_DEVICE_NAME_SIZE,
-	name:		SBP2_DEVICE_NAME,
-	mode:		S_IFDIR | S_IRUGO | S_IXUGO,
-	nlink:		2
-};
-#endif
-
 /* SCSI host template */
 static Scsi_Host_Template scsi_driver_template = {
 	name:			"IEEE-1394 SBP-2 protocol driver",
@@ -3047,20 +3003,14 @@
 	eh_bus_reset_handler:	sbp2scsi_reset,
 	eh_host_reset_handler:	sbp2scsi_reset,
 	bios_param:		sbp2scsi_biosparam,
-	can_queue:		SBP2SCSI_MAX_OUTSTANDING_CMDS,
 	this_id:		-1,
 	sg_tablesize:		SBP2_MAX_SG_ELEMENTS,
-	cmd_per_lun:		SBP2SCSI_MAX_CMDS_PER_LUN,
 	use_clustering:		SBP2_CLUSTERING,
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	use_new_eh_code:	TRUE,
 #endif
 	emulated:		1,
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,26)
 	proc_name:	SBP2_DEVICE_NAME,
-#else
-	proc_dir:	&proc_scsi_sbp2scsi,
-#endif
 };
 
 static int sbp2_module_init(void)
@@ -3068,29 +3018,26 @@
 	SBP2_DEBUG("sbp2_module_init");
 
 	/*
-	 * Module load option for force one command at a time
+	 * Module load debug option to force one command at a time (serializing I/O)
 	 */
-	if (serialize_io) {
+	if (sbp2_serialize_io) {
 		SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)");
 		scsi_driver_template.can_queue = 1;
 		scsi_driver_template.cmd_per_lun = 1;
+	} else {
+		scsi_driver_template.can_queue = sbp2_max_outstanding_cmds;
+		scsi_driver_template.cmd_per_lun = sbp2_max_cmds_per_lun;
 	}
 
-	/*
-	 * Module load option to limit max size of requests from the
-	 * scsi drivers
+	/* 
+	 * Set max sectors (module load option). Default is 255 sectors. 
 	 */
-	if (no_large_packets) {
-		SBP2_ERR("Driver forced to limit max transfer size "
-			 "(no_large_packets = 1)");
-		scsi_driver_template.sg_tablesize = 0x1f;
-		scsi_driver_template.use_clustering = DISABLE_CLUSTERING;
-	}
+	scsi_driver_template.max_sectors = sbp2_max_sectors;
 
 	/*
 	 * Ideally we would register our scsi_driver_template with the
 	 * scsi stack and after that register with the ieee1394 stack
-	 * and process the add_host callbacks.  However, the detect
+	 * and process the add_host callbacks. However, the detect
 	 * function in the scsi host template requires that we find at
 	 * least one host, so we "nest" the registrations by calling
 	 * sbp2_init from the detect function.
diff -urN linux-2.5.8-pre2/drivers/ieee1394/sbp2.h linux-2.5.8-pre3/drivers/ieee1394/sbp2.h
--- linux-2.5.8-pre2/drivers/ieee1394/sbp2.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/sbp2.h	Tue Apr  9 18:35:19 2002
@@ -195,10 +195,28 @@
  * Miscellaneous SBP2 related config rom defines
  */
 
-#define SBP2_STATUS_FIFO_ADDRESS				0xfffe00000000ULL     /* for write posting! */
+/* 
+ * The status fifo address definition below is used as a status base, with a chunk
+ * separately assigned for each sbp2 device detected. For example, 0xfffe00000000ULL 
+ * is used for the first sbp2 device detected, 0xfffe00000020ULL for the next sbp2 
+ * device, and so on.
+ *
+ * Note: We could use a single status fifo address for all sbp2 devices, and figure 
+ * out which sbp2 device the status belongs to by looking at the source node id of
+ * the status write... but, using separate addresses for each sbp2 device allows for
+ * better code and the ability to support multiple luns within a single 1394 node.
+ *
+ * Also note that we choose the address range below as it is a region specified for
+ * write posting, where the ohci controller will automatically send an ack_complete
+ * when the status is written by the sbp2 device... saving a split transaction.   =)
+ */ 
+#define SBP2_STATUS_FIFO_ADDRESS				0xfffe00000000ULL
 #define SBP2_STATUS_FIFO_ADDRESS_HI                             0xfffe
 #define SBP2_STATUS_FIFO_ADDRESS_LO                             0x0
 
+#define SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(entry)			((entry) << 5)
+#define SBP2_STATUS_FIFO_OFFSET_TO_ENTRY(offset)		((offset) >> 5)
+
 #define SBP2_UNIT_DIRECTORY_OFFSET_KEY				0xd1
 #define SBP2_CSR_OFFSET_KEY					0x54
 #define SBP2_UNIT_SPEC_ID_KEY					0x12
@@ -209,8 +227,8 @@
 #define SBP2_DEVICE_TYPE_AND_LUN_KEY				0x14
 #define SBP2_FIRMWARE_REVISION_KEY				0x3c
 
-#define SBP2_DEVICE_TYPE(q)			(((q) >> 16) & 0x1f)
-#define SBP2_DEVICE_LUN(q)			((q) & 0xffff)
+#define SBP2_DEVICE_TYPE(q)					(((q) >> 16) & 0x1f)
+#define SBP2_DEVICE_LUN(q)					((q) & 0xffff)
 
 #define SBP2_AGENT_STATE_OFFSET					0x00ULL
 #define SBP2_AGENT_RESET_OFFSET					0x04ULL
@@ -231,10 +249,14 @@
 #define SBP2_UNIT_SPEC_ID_ENTRY					0x0000609e
 #define SBP2_SW_VERSION_ENTRY					0x00010483
 
-
+/*
+ * Other misc defines
+ */
 #define SBP2_128KB_BROKEN_FIRMWARE				0xa0b800
 #define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER			0x20000
 
+#define SBP2_DEVICE_TYPE_LUN_UNINITIALIZED			0xffffffff
+
 /*
  * Flags for SBP-2 functions
  */
@@ -247,9 +269,10 @@
 #define SBP2_MAX_SG_ELEMENTS		SG_ALL
 #define SBP2_CLUSTERING			ENABLE_CLUSTERING
 #define SBP2_MAX_SG_ELEMENT_LENGTH	0xf000
-#define SBP2SCSI_MAX_SCSI_IDS		8
+#define SBP2SCSI_MAX_SCSI_IDS		16	/* Max sbp2 device instances supported */
 #define SBP2SCSI_MAX_OUTSTANDING_CMDS	8	/* Max total outstanding sbp2 commands allowed at a time! */
-#define SBP2SCSI_MAX_CMDS_PER_LUN	4 	/* Max outstanding sbp2 commands per device - tune as needed */
+#define SBP2SCSI_MAX_CMDS_PER_LUN	1 	/* Max outstanding sbp2 commands per device - tune as needed */
+#define SBP2_MAX_SECTORS		255	/* Max sectors supported */
 
 #ifndef TYPE_SDAD
 #define TYPE_SDAD			0x0e	/* simplified direct access device */
@@ -291,13 +314,8 @@
 	DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
 };
 
-
-/*
- * Number of request packets available for actual sbp2 I/O requests (these are used
- * for sending command and agent reset packets).
- */
-#define SBP2_MAX_REQUEST_PACKETS	SBP2SCSI_MAX_OUTSTANDING_CMDS	/* Per host adapter instance */
-#define SBP2_MAX_COMMAND_ORBS		SBP2SCSI_MAX_CMDS_PER_LUN * 2	/* Per sbp2 device instance */
+#define SBP2_MAX_REQUEST_PACKETS	(sbp2_max_outstanding_cmds * 2)
+#define SBP2_MAX_COMMAND_ORBS		(sbp2_max_cmds_per_lun * 2)
 
 /*
  * Request packets structure (used for sending command and agent reset packets)
@@ -327,7 +345,6 @@
 	dma_addr_t command_orb_dma ____cacheline_aligned;
 	Scsi_Cmnd *Current_SCpnt;
 	void (*Current_done)(Scsi_Cmnd *);
-	unsigned int linked;
 
 	/* Also need s/g structure for each sbp2 command */
 	struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS] ____cacheline_aligned;
@@ -434,7 +451,7 @@
 	 * Here is the pool of request packets. All the hpsb packets (for 1394 bus transactions)
 	 * are allocated at init and simply re-initialized when needed.
 	 */
-	struct sbp2_request_packet request_packet[SBP2_MAX_REQUEST_PACKETS];
+	struct sbp2_request_packet *request_packet;
 
 	/*
 	 * SCSI ID instance data (one for each sbp2 device instance possible)
@@ -453,7 +470,7 @@
 static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi);
 static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi);
 static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
-									  nodeid_t node, u64 addr,
+									  struct node_entry *ne, u64 addr,
 									  size_t data_size,
 									  quadlet_t data);
 static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet);
@@ -505,8 +522,6 @@
 				 struct sbp2_command_info *command);
 static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
 			     Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
-				   Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data);
 static void sbp2_check_sbp2_command(unchar *cmd);
 static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, 
diff -urN linux-2.5.8-pre2/drivers/ieee1394/video1394.c linux-2.5.8-pre3/drivers/ieee1394/video1394.c
--- linux-2.5.8-pre2/drivers/ieee1394/video1394.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/ieee1394/video1394.c	Tue Apr  9 18:35:19 2002
@@ -18,6 +18,9 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+/* jds -- add private data to file to keep track of iso contexts associated
+   with each open -- so release won't kill all iso transfers */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -31,18 +34,12 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
 #include <linux/proc_fs.h>
 #include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/devfs_fs_kernel.h>
 
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
+#include <asm/bitops.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
@@ -70,6 +67,14 @@
 #define vmalloc_32(x) vmalloc(x)
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3))
+#define remap_page_range_1394(vma, start, addr, size, prot) \
+	remap_page_range(start, addr, size, prot)
+#else
+#define remap_page_range_1394(vma, start, addr, size, prot) \
+	remap_page_range(vma, start, addr, size, prot)
+#endif
+
 struct it_dma_prg {
 	struct dma_cmd begin;
 	quadlet_t data[4];
@@ -107,6 +112,8 @@
 	spinlock_t lock;
 	unsigned int syt_offset;
 	int flags;
+
+	struct list_head link;
 };
 
 struct video_card {
@@ -114,9 +121,12 @@
 	struct list_head list;
 	int id;
 	devfs_handle_t devfs;
+};
+
 
-	struct dma_iso_ctx **ir_context;
-	struct dma_iso_ctx **it_context;
+struct file_ctx {
+	struct video_card *video;
+	struct list_head context_list;
 	struct dma_iso_ctx *current_ctx;
 };
 
@@ -158,35 +168,86 @@
 /* Memory management functions */
 /*******************************/
 
-static inline unsigned long kvirt_to_bus(unsigned long adr) 
+#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ *    out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guaranteed.  We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+        unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+  
+	if (!pgd_none(*pgd)) {
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset_kernel(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte)) {
+				ret = (unsigned long) 
+					page_address(pte_page(pte));
+                                ret |= (adr & (PAGE_SIZE - 1));
+			}
+                }
+        }
+        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
+	return ret;
+}
+
+static inline unsigned long uvirt_to_bus(unsigned long adr) 
 {
         unsigned long kva, ret;
 
-	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
 	ret = virt_to_bus((void *)kva);
+        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
+        return ret;
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr) 
+{
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = virt_to_bus((void *)kva);
+        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
         return ret;
 }
 
 /* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
  */
 static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
-        unsigned long kva, ret;
+        unsigned long va, kva, ret;
 
-	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
 	ret = __pa(kva);
+        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
         return ret;
 }
 
 static void * rvmalloc(unsigned long size)
 {
 	void * mem;
-	unsigned long adr;
- 
-	size=PAGE_ALIGN(size);
+	unsigned long adr, page;
+        
 	mem=vmalloc_32(size);
 	if (mem) 
 	{
@@ -195,7 +256,8 @@
 	        adr=(unsigned long) mem;
 		while (size > 0) 
                 {
-			mem_map_reserve(vmalloc_to_page((void *)adr));
+	                page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -205,14 +267,15 @@
 
 static void rvfree(void * mem, unsigned long size)
 {
-        unsigned long adr;
-
+        unsigned long adr, page;
+        
 	if (mem) 
 	{
 	        adr=(unsigned long) mem;
-		while ((long) size > 0) 
+		while (size > 0) 
                 {
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
 			adr+=PAGE_SIZE;
 			size-=PAGE_SIZE;
 		}
@@ -221,52 +284,48 @@
 }
 /* End of code taken from bttv.c */
 
-static int free_dma_iso_ctx(struct dma_iso_ctx **d)
+static int free_dma_iso_ctx(struct dma_iso_ctx *d)
 {
 	int i;
-	struct ti_ohci *ohci;
 	unsigned long *usage;
 	
-	if ((*d)==NULL) return -1;
+	DBGMSG(d->ohci->id, "Freeing dma_iso_ctx %d", d->ctx);
 
-	ohci = (struct ti_ohci *)(*d)->ohci;
+	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
+	ohci1394_unhook_irq(d->ohci, irq_handler, d);
 
-	DBGMSG(ohci->id, "Freeing dma_iso_ctx %d", (*d)->ctx);
+	if (d->buf)
+		rvfree((void *)d->buf, d->num_desc * d->buf_size);
 
-	ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
-
-	if ((*d)->buf) rvfree((void *)(*d)->buf, 
-			      (*d)->num_desc * (*d)->buf_size);
-
-	if ((*d)->ir_prg) {
-		for (i=0;i<(*d)->num_desc;i++) 
-			if ((*d)->ir_prg[i]) kfree((*d)->ir_prg[i]);
-		kfree((*d)->ir_prg);
+	if (d->ir_prg) {
+		for (i=0;i<d->num_desc;i++) 
+			if (d->ir_prg[i]) kfree(d->ir_prg[i]);
+		kfree(d->ir_prg);
 	}
 
-	if ((*d)->it_prg) {
-		for (i=0;i<(*d)->num_desc;i++) 
-			if ((*d)->it_prg[i]) kfree((*d)->it_prg[i]);
-		kfree((*d)->it_prg);
+	if (d->it_prg) {
+		for (i=0;i<d->num_desc;i++) 
+			if (d->it_prg[i]) kfree(d->it_prg[i]);
+		kfree(d->it_prg);
 	}
 
-	if ((*d)->buffer_status)
-		kfree((*d)->buffer_status);
-	if ((*d)->buffer_time)
-		kfree((*d)->buffer_time);
-	if ((*d)->last_used_cmd)
-		kfree((*d)->last_used_cmd);
-	if ((*d)->next_buffer)
-		kfree((*d)->next_buffer);
+	if (d->buffer_status)
+		kfree(d->buffer_status);
+	if (d->buffer_time)
+		kfree(d->buffer_time);
+	if (d->last_used_cmd)
+		kfree(d->last_used_cmd);
+	if (d->next_buffer)
+		kfree(d->next_buffer);
 
-	usage = ((*d)->type == ISO_RECEIVE) ? &ohci->ir_ctx_usage :
-		&ohci->it_ctx_usage;
+	usage = (d->type == ISO_RECEIVE) ? &d->ohci->ir_ctx_usage :
+		&d->ohci->it_ctx_usage;
        
 	/* clear the ISO context usage bit */
-	clear_bit((*d)->ctx, usage);
-	
-	kfree(*d);
-	*d = NULL;
+	clear_bit(d->ctx, usage);
+	list_del(&d->link);
+
+	kfree(d);
 
 	return 0;
 }
@@ -318,11 +377,17 @@
 	d->ir_prg = NULL;
 	init_waitqueue_head(&d->waitq);
 
+	if (ohci1394_hook_irq(ohci, irq_handler, d) != 0) {
+		PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed");
+		free_dma_iso_ctx(d);
+		return NULL;
+	}
+
 	d->buf = rvmalloc(d->num_desc * d->buf_size);
 
 	if (d->buf == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	memset(d->buf, 0, d->num_desc * d->buf_size);
@@ -339,7 +404,7 @@
 		if (d->ir_prg == NULL) {
 			PRINT(KERN_ERR, ohci->id, 
 			      "Failed to allocate dma ir prg");
-			free_dma_iso_ctx(&d);
+			free_dma_iso_ctx(d);
 			return NULL;
 		}
 		memset(d->ir_prg, 0, d->num_desc * sizeof(struct dma_cmd *));
@@ -355,7 +420,7 @@
 			if (d->ir_prg[i] == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Failed to allocate dma ir prg");
-				free_dma_iso_ctx(&d);
+				free_dma_iso_ctx(d);
 				return NULL;
 			}
 		}
@@ -371,7 +436,7 @@
 		if (d->it_prg == NULL) {
 			PRINT(KERN_ERR, ohci->id, 
 			      "Failed to allocate dma it prg");
-			free_dma_iso_ctx(&d);
+			free_dma_iso_ctx(d);
 			return NULL;
 		}
 		memset(d->it_prg, 0, d->num_desc*sizeof(struct it_dma_prg *));
@@ -383,7 +448,7 @@
 			      "Packet size %d (page_size: %ld) "
 			      "not yet supported\n",
 			      packet_size, PAGE_SIZE);
-			free_dma_iso_ctx(&d);
+			free_dma_iso_ctx(d);
 			return NULL;
 		}
 
@@ -402,7 +467,7 @@
 			if (d->it_prg[i] == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Failed to allocate dma it prg");
-				free_dma_iso_ctx(&d);
+				free_dma_iso_ctx(d);
 				return NULL;
 			}
 		}
@@ -419,22 +484,22 @@
 
 	if (d->buffer_status == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_status");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	if (d->buffer_time == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_time");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	if (d->last_used_cmd == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate last_used_cmd");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	if (d->next_buffer == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate next_buffer");
-		free_dma_iso_ctx(&d);
+		free_dma_iso_ctx(d);
 		return NULL;
 	}
 	memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
@@ -536,36 +601,17 @@
 }
 
 /* find which context is listening to this channel */
-static struct dma_iso_ctx **
-ir_ctx_listening(struct video_card *video, int channel)
-{
-	int i;
-	struct ti_ohci *ohci = video->ohci;
-
-	for (i = 0; i < ohci->nb_iso_rcv_ctx-1; i++) 
-		if (video->ir_context[i] &&
-		    video->ir_context[i]->channel == channel)
-			return &video->ir_context[i];
-		
-	PRINT(KERN_ERR, ohci->id, "No iso context is listening to channel %d",
-	      channel);
-
-	return NULL;
-}
-
-static struct dma_iso_ctx **
-it_ctx_talking(struct video_card *video, int channel)
+static struct dma_iso_ctx *
+find_ctx(struct list_head *list, int type, int channel)
 {
-	int i;
-	struct ti_ohci *ohci = video->ohci;
+	struct list_head *lh;
 
-	for (i = 0; i < ohci->nb_iso_xmit_ctx; i++) 
-		if (video->it_context[i] &&
-		    video->it_context[i]->channel==channel)
-			return &video->ir_context[i];
-		
-	PRINT(KERN_ERR, ohci->id, "No iso context is talking to channel %d",
-	      channel);
+	list_for_each(lh, list) {
+		struct dma_iso_ctx *ctx;
+		ctx = list_entry(lh, struct dma_iso_ctx, link);
+		if (ctx->type == type && ctx->channel == channel)
+			return ctx;
+	}
 
 	return NULL;
 }
@@ -585,7 +631,11 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+			get_fast_time(&d->buffer_time[i]);
+#else
 			do_gettimeofday(&d->buffer_time[i]);
+#endif
 		}
 	}
 	spin_unlock(&d->lock);
@@ -790,13 +840,14 @@
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
 }
 
-static int do_iso_mmap(struct vm_area_struct *vma, struct ti_ohci *ohci, struct dma_iso_ctx *d, 
-		       const char *adr, unsigned long size)
+static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d,
+		       struct vm_area_struct *vma)
 {
-        unsigned long start=(unsigned long) adr;
-        unsigned long page,pos;
+        unsigned long start = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+        unsigned long page, pos;
 
-        if (size>d->num_desc * d->buf_size) {
+        if (size > d->num_desc * d->buf_size) {
 		PRINT(KERN_ERR, ohci->id, 
 		      "iso context %d buf size is different from mmap size", 
 		      d->ctx);
@@ -808,14 +859,14 @@
 		return -EINVAL;
 	}
 
-        pos=(unsigned long) d->buf;
+	pos = (unsigned long) d->buf;
         while (size > 0) {
                 page = kvirt_to_pa(pos);
-                if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                if (remap_page_range_1394(vma, start, page, PAGE_SIZE, PAGE_SHARED))
                         return -EAGAIN;
-                start+=PAGE_SIZE;
-                pos+=PAGE_SIZE;
-                size-=PAGE_SIZE;
+                start += PAGE_SIZE;
+                pos += PAGE_SIZE;
+                size -= PAGE_SIZE;
         }
         return 0;
 }
@@ -823,30 +874,10 @@
 static int video1394_ioctl(struct inode *inode, struct file *file,
 			   unsigned int cmd, unsigned long arg)
 {
-	struct video_card *video = NULL;
-	struct ti_ohci *ohci = NULL;
+	struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+	struct video_card *video = ctx->video;
+	struct ti_ohci *ohci = video->ohci;
 	unsigned long flags;
-	struct list_head *lh;
-
-	spin_lock_irqsave(&video1394_cards_lock, flags);
-	if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == ieee1394_file_to_instance(file)) {
-				video = p;
-				ohci = video->ohci;
-				break;
-			}
-		}
-	}
-	spin_unlock_irqrestore(&video1394_cards_lock, flags);
-
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, "%s: Unknown video card for minor %d",
-			__FUNCTION__, ieee1394_file_to_instance(file));
-		return -EFAULT;
-	}
 
 	switch(cmd)
 	{
@@ -855,6 +886,7 @@
 	{
 		struct video1394_mmap v;
 		u64 mask;
+		struct dma_iso_ctx *d;
 		int i;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
@@ -889,7 +921,7 @@
 			return -EFAULT;
 		}
 		ohci->ISO_channel_usage |= mask;
-		
+
 		if (v.buf_size<=0) {
 			PRINT(KERN_ERR, ohci->id,
 			      "Invalid %d length buffer requested",v.buf_size);
@@ -910,67 +942,47 @@
 		}
 
 		if (cmd == VIDEO1394_LISTEN_CHANNEL) {
-			/* find a free iso receive context */
-			for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 
-				if (video->ir_context[i]==NULL) break;
-			    
-			if (i==(ohci->nb_iso_rcv_ctx-1)) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "No iso context available");
-				return -EFAULT;
-			}
+			d = alloc_dma_iso_ctx(ohci, ISO_RECEIVE,
+					      v.nb_buffers, v.buf_size, 
+					      v.channel, 0);
 
-			video->ir_context[i] = 
-				alloc_dma_iso_ctx(ohci, ISO_RECEIVE,
-						  v.nb_buffers, v.buf_size, 
-						  v.channel, 0);
-
-			if (video->ir_context[i] == NULL) {
+			if (d == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Couldn't allocate ir context");
 				return -EFAULT;
 			}
-			initialize_dma_ir_ctx(video->ir_context[i], 
-					      v.sync_tag, v.flags);
+			initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
 
-			video->current_ctx = video->ir_context[i];
+			ctx->current_ctx = d;
 
-			v.buf_size = video->ir_context[i]->buf_size;
+			v.buf_size = d->buf_size;
+			list_add_tail(&d->link, &ctx->context_list);
 
 			PRINT(KERN_INFO, ohci->id, 
 			      "iso context %d listen on channel %d",
-			      video->current_ctx->ctx, v.channel);
+			      d->ctx, v.channel);
 		}
 		else {
-			/* find a free iso transmit context */
-			for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 
-				if (video->it_context[i]==NULL) break;
-			    
-			if (i==ohci->nb_iso_xmit_ctx) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "No iso context available");
-				return -EFAULT;
-			}
-			
-			video->it_context[i] = 
-				alloc_dma_iso_ctx(ohci, ISO_TRANSMIT,
-						  v.nb_buffers, v.buf_size, 
-						  v.channel, v.packet_size);
+			d = alloc_dma_iso_ctx(ohci, ISO_TRANSMIT,
+					      v.nb_buffers, v.buf_size, 
+					      v.channel, v.packet_size);
 
-			if (video->it_context[i] == NULL) {
+			if (d == NULL) {
 				PRINT(KERN_ERR, ohci->id, 
 				      "Couldn't allocate it context");
 				return -EFAULT;
 			}
-			initialize_dma_it_ctx(video->it_context[i], 
-					      v.sync_tag, v.syt_offset, v.flags);
+			initialize_dma_it_ctx(d, v.sync_tag, 
+					      v.syt_offset, v.flags);
 
-			video->current_ctx = video->it_context[i];
+			ctx->current_ctx = d;
 
-			v.buf_size = video->it_context[i]->buf_size;
+			v.buf_size = d->buf_size;
+
+			list_add_tail(&d->link, &ctx->context_list);
 
 			PRINT(KERN_INFO, ohci->id, 
-			      "Iso context %d talk on channel %d", i, 
+			      "Iso context %d talk on channel %d", d->ctx,
 			      v.channel);
 		}
 
@@ -984,6 +996,7 @@
 	{
 		int channel;
 		u64 mask;
+		struct dma_iso_ctx *d;
 
 		if(copy_from_user(&channel, (void *)arg, sizeof(int)))
 			return -EFAULT;
@@ -999,41 +1012,31 @@
 			      "Channel %d is not being used", channel);
 			return -EFAULT;
 		}
+
+		/* Mark this channel as unused */
 		ohci->ISO_channel_usage &= ~mask;
 
-		if (cmd == VIDEO1394_UNLISTEN_CHANNEL) {
-			struct dma_iso_ctx **d;
-			d = ir_ctx_listening(video, channel);
-			if (d == NULL) return -EFAULT;
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso context %d stop listening on channel %d", 
-			      (*d)->ctx, channel);
-			free_dma_iso_ctx(d);
-		}
-		else {
-			struct dma_iso_ctx **d;
-			d = it_ctx_talking(video, channel);
-			if (d == NULL) return -EFAULT;
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso context %d stop talking on channel %d", 
-			      (*d)->ctx, channel);
-			free_dma_iso_ctx(d);
+		if (cmd == VIDEO1394_UNLISTEN_CHANNEL)
+			d = find_ctx(&ctx->context_list, ISO_RECEIVE, channel);
+		else
+			d = find_ctx(&ctx->context_list, ISO_TRANSMIT, channel);
 
-		}
+		if (d == NULL) return -EFAULT;
+		PRINT(KERN_INFO, ohci->id, "Iso context %d "
+		      "stop talking on channel %d", d->ctx, channel);
+		free_dma_iso_ctx(d);
 		
 		return 0;
 	}
 	case VIDEO1394_LISTEN_QUEUE_BUFFER:
 	{
 		struct video1394_wait v;
-		struct dma_iso_ctx *d, **dd;
+		struct dma_iso_ctx *d;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		dd = ir_ctx_listening(video, v.channel);
-		if (dd == NULL) return -EFAULT;
-		d = *dd;
+		d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1089,15 +1092,13 @@
 	case VIDEO1394_LISTEN_POLL_BUFFER:
 	{
 		struct video1394_wait v;
-		struct dma_iso_ctx *d, **dd;
+		struct dma_iso_ctx *d;
 		int i;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		dd = ir_ctx_listening(video, v.channel);
-		if (dd==NULL) return -EFAULT;
-		d = *dd;
+		d = find_ctx(&ctx->context_list, ISO_RECEIVE, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1173,14 +1174,12 @@
 	{
 		struct video1394_wait v;
 		struct video1394_queue_variable qv;
-		struct dma_iso_ctx *d, **dd;
+		struct dma_iso_ctx *d;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		dd = it_ctx_talking(video, v.channel);
-		if (dd == NULL) return -EFAULT;
-		d = *dd;
+		d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1264,14 +1263,12 @@
 	case VIDEO1394_TALK_WAIT_BUFFER:
 	{
 		struct video1394_wait v;
-		struct dma_iso_ctx *d, **dd;
+		struct dma_iso_ctx *d;
 
 		if(copy_from_user(&v, (void *)arg, sizeof(v)))
 			return -EFAULT;
 
-		dd = it_ctx_talking(video, v.channel);
-		if (dd == NULL) return -EFAULT;
-		d = *dd;
+		d = find_ctx(&ctx->context_list, ISO_TRANSMIT, v.channel);
 
 		if ((v.buffer<0) || (v.buffer>d->num_desc)) {
 			PRINT(KERN_ERR, ohci->id, 
@@ -1321,40 +1318,18 @@
 
 int video1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct video_card *video = NULL;
-	struct ti_ohci *ohci;
+	struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+	struct video_card *video = ctx->video;
+	struct ti_ohci *ohci = video->ohci;
 	int res = -EINVAL;
-	unsigned long flags;
-	struct list_head *lh;
-
-        spin_lock_irqsave(&video1394_cards_lock, flags);
-        if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == ieee1394_file_to_instance(file)) {
-				video = p;
-				break;
-			}
-                }
-        }
-        spin_unlock_irqrestore(&video1394_cards_lock, flags);
-
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, "%s: Unknown video card for minor %d",
-			__FUNCTION__, ieee1394_file_to_instance(file));
-		return -EFAULT;
-	}
 
 	lock_kernel();
 	ohci = video->ohci;
 
-	if (video->current_ctx == NULL) {
+	if (ctx->current_ctx == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Current iso context not set");
 	} else
-		res = do_iso_mmap(vma, ohci, video->current_ctx, 
-			   (char *)vma->vm_start, 
-			   (unsigned long)(vma->vm_end-vma->vm_start));
+		res = do_iso_mmap(ohci, ctx->current_ctx, vma);
 	unlock_kernel();
 	return res;
 }
@@ -1365,16 +1340,14 @@
 	unsigned long flags;
 	struct video_card *video = NULL;
 	struct list_head *lh;
+	struct file_ctx *ctx;
 
 	spin_lock_irqsave(&video1394_cards_lock, flags);
-	if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == i) {
-				video = p;
-				break;
-			}
+	list_for_each(lh, &video1394_cards) {
+		struct video_card *p = list_entry(lh, struct video_card, list);
+		if (p->id == i) {
+			video = p;
+			break;
 		}
 	}
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
@@ -1382,76 +1355,50 @@
         if (video == NULL)
                 return -EIO;
 
-	V22_COMPAT_MOD_INC_USE_COUNT;
+	ctx = kmalloc(sizeof(struct file_ctx), GFP_KERNEL);
+	if (ctx == NULL)  {
+		PRINT(KERN_ERR, video->ohci->id, "Cannot malloc file_ctx");
+		return -ENOMEM;
+	}
+
+	memset(ctx, 0, sizeof(struct file_ctx));
+	ctx->video = video;
+	INIT_LIST_HEAD(&ctx->context_list);
+	ctx->current_ctx = NULL;
+	file->private_data = ctx;
 
 	return 0;
 }
 
 static int video1394_release(struct inode *inode, struct file *file)
 {
-	struct video_card *video = NULL;
-	struct ti_ohci *ohci;
+	struct file_ctx *ctx = (struct file_ctx *)file->private_data;
+	struct video_card *video = ctx->video;
+	struct ti_ohci *ohci = video->ohci;
+	struct list_head *lh, *next;
 	u64 mask;
-	int i;
-	unsigned long flags;
-	struct list_head *lh;
-
-        spin_lock_irqsave(&video1394_cards_lock, flags);
-        if (!list_empty(&video1394_cards)) {
-		struct video_card *p;
-		list_for_each(lh, &video1394_cards) {
-			p = list_entry(lh, struct video_card, list);
-			if (p->id == ieee1394_file_to_instance(file)) {
-				video = p;
-				break;
-			}
-		}
-	}
-        spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, "%s: Unknown device for minor %d",
-			__FUNCTION__, ieee1394_file_to_instance(file));
-		return 1;
+	lock_kernel();
+	list_for_each_safe(lh, next, &ctx->context_list) {
+		struct dma_iso_ctx *d;
+		d = list_entry(lh, struct dma_iso_ctx, link);
+		mask = (u64) 1 << d->channel;
+		
+		if (!(ohci->ISO_channel_usage & mask))
+			PRINT(KERN_ERR, ohci->id, "On release: Channel %d "
+			      "is not being used", d->channel);
+		else
+			ohci->ISO_channel_usage &= ~mask;
+		PRINT(KERN_INFO, ohci->id, "On release: Iso %s context "
+		      "%d stop listening on channel %d",
+		      d->type == ISO_RECEIVE ? "receive" : "transmit",
+		      d->ctx, d->channel);
+		free_dma_iso_ctx(d);
 	}
 
-	ohci = video->ohci;
-
-	lock_kernel();
-	for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) 
-		if (video->ir_context[i]) {
-			mask = (u64)0x1<<video->ir_context[i]->channel;
-			if (!(ohci->ISO_channel_usage & mask))
-				PRINT(KERN_ERR, ohci->id, 
-				      "On release: Channel %d is not being used", 
-				      video->ir_context[i]->channel);
-			else
-				ohci->ISO_channel_usage &= ~mask;
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso receive context %d stop listening "
-			      "on channel %d", video->ir_context[i]->ctx,
-			      video->ir_context[i]->channel);
-			free_dma_iso_ctx(&video->ir_context[i]);
-		}
+	kfree(ctx);
+	file->private_data = NULL;
 	
-	for (i=0;i<ohci->nb_iso_xmit_ctx;i++) 
-		if (video->it_context[i]) {
-			mask = (u64)0x1<<video->it_context[i]->channel;
-			if (!(ohci->ISO_channel_usage & mask))
-				PRINT(KERN_ERR, ohci->id, 
-				      "Channel %d is not being used", 
-				      video->it_context[i]->channel);
-			else
-				ohci->ISO_channel_usage &= ~mask;
-			PRINT(KERN_INFO, ohci->id, 
-			      "Iso transmit context %d stop talking "
-			      "on channel %d", video->it_context[i]->ctx,
-			      video->it_context[i]->channel);
-			free_dma_iso_ctx(&video->it_context[i]);
-		}
-
-	V22_COMPAT_MOD_DEC_USE_COUNT;
-
 	unlock_kernel();
 	return 0;
 }
@@ -1459,32 +1406,20 @@
 static void irq_handler(int card, quadlet_t isoRecvIntEvent, 
 			quadlet_t isoXmitIntEvent, void *data)
 {
-	int i;
-	struct video_card *video = (struct video_card*) data;
+	struct dma_iso_ctx *d = (struct dma_iso_ctx *) data;
 
-	if (video == NULL) {
-		PRINT_G(KERN_ERR, "%s: Unknown card number %d",
-			__FUNCTION__, card);
-		return;
-	}
-	
 	DBGMSG(card, "Iso event Recv: %08x Xmit: %08x",
 	       isoRecvIntEvent, isoXmitIntEvent);
 
-	for (i = 0; i < video->ohci->nb_iso_rcv_ctx-1; i++)
-		if (video->ir_context[i] != NULL &&
-		    isoRecvIntEvent & (1<<(video->ir_context[i]->ctx)))
-			wakeup_dma_ir_ctx(video->ohci, video->ir_context[i]);
-
-	for (i = 0; i < video->ohci->nb_iso_xmit_ctx; i++)
-		if (video->it_context[i] != NULL &&
-		    isoXmitIntEvent & (1<<(video->it_context[i]->ctx)))
-			wakeup_dma_it_ctx(video->ohci, video->it_context[i]);
+	if (d->type == ISO_RECEIVE && isoRecvIntEvent & (1 << d->ctx))
+		wakeup_dma_ir_ctx(d->ohci, d);
+	if (d->type == ISO_TRANSMIT && isoXmitIntEvent & (1 << d->ctx))
+		wakeup_dma_it_ctx(d->ohci, d);
 }
 
 static struct file_operations video1394_fops=
 {
-        OWNER_THIS_MODULE
+	owner:		THIS_MODULE,
 	ioctl:		video1394_ioctl,
 	mmap:		video1394_mmap,
 	open:		video1394_open,
@@ -1493,10 +1428,12 @@
 
 static int video1394_init(struct ti_ohci *ohci)
 {
-	struct video_card *video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
+	struct video_card *video;
 	unsigned long flags;
 	char name[16];
+	int minor;
 
+	video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
 	if (video == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Cannot allocate video_card");
 		return -1;
@@ -1509,43 +1446,14 @@
 	list_add_tail(&video->list, &video1394_cards);
 	spin_unlock_irqrestore(&video1394_cards_lock, flags);
 
-	if (ohci1394_hook_irq(ohci, irq_handler, (void*) video) != 0) {
-		PRINT(KERN_ERR, ohci->id, "ohci1394_hook_irq() failed");
-		return -1;
-	}
-
 	video->id = ohci->id;
 	video->ohci = ohci;
 
-	/* Iso receive dma contexts */
-	video->ir_context = (struct dma_iso_ctx **)
-		kmalloc((ohci->nb_iso_rcv_ctx-1)*
-			sizeof(struct dma_iso_ctx *), GFP_KERNEL);
-	if (video->ir_context) 
-		memset(video->ir_context, 0,
-		       (ohci->nb_iso_rcv_ctx-1)*sizeof(struct dma_iso_ctx *));
-	else {
-		PRINT(KERN_ERR, ohci->id, "Cannot allocate ir_context");
-		return -1;
-	}
-
-	/* Iso transmit dma contexts */
-	video->it_context = (struct dma_iso_ctx **)
-		kmalloc(ohci->nb_iso_xmit_ctx *
-			sizeof(struct dma_iso_ctx *), GFP_KERNEL);
-	if (video->it_context) 
-		memset(video->it_context, 0,
-		       ohci->nb_iso_xmit_ctx * sizeof(struct dma_iso_ctx *));
-	else {
-		PRINT(KERN_ERR, ohci->id, "Cannot allocate it_context");
-		return -1;
-	}
-
 	sprintf(name, "%d", video->id);
+	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + video->id;
 	video->devfs = devfs_register(devfs_handle, name,
 				      DEVFS_FL_AUTO_OWNER,
-				      IEEE1394_MAJOR,
-				      IEEE1394_MINOR_BLOCK_VIDEO1394*16+video->id,
+				      IEEE1394_MAJOR, minor,
 				      S_IFCHR | S_IRUSR | S_IWUSR,
 				      &video1394_fops, NULL);
 
@@ -1555,27 +1463,7 @@
 /* Must be called under spinlock */
 static void remove_card(struct video_card *video)
 {
-	int i;
-
-	ohci1394_unhook_irq(video->ohci, irq_handler, (void*) video);
-
 	devfs_unregister(video->devfs);
-
-	/* Free the iso receive contexts */
-	if (video->ir_context) {
-		for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++) {
-			free_dma_iso_ctx(&video->ir_context[i]);
-		}
-		kfree(video->ir_context);
-	}
-
-	/* Free the iso transmit contexts */
-	if (video->it_context) {
-		for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++) {
-			free_dma_iso_ctx(&video->it_context[i]);
-		}
-		kfree(video->it_context);
-	}
 	list_del(&video->list);
 
 	kfree(video);
diff -urN linux-2.5.8-pre2/drivers/md/md.c linux-2.5.8-pre3/drivers/md/md.c
--- linux-2.5.8-pre2/drivers/md/md.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/md/md.c	Tue Apr  9 18:35:19 2002
@@ -283,10 +283,7 @@
 static unsigned int calc_dev_sboffset(kdev_t dev, mddev_t *mddev,
 						int persistent)
 {
-	unsigned int size = 0;
-
-	if (blk_size[major(dev)])
-		size = blk_size[major(dev)][minor(dev)];
+	unsigned int size = (blkdev_size_in_bytes(dev) >> BLOCK_SIZE_BITS);
 	if (persistent)
 		size = MD_NEW_SIZE_BLOCKS(size);
 	return size;
@@ -1106,12 +1103,11 @@
 	rdev->desc_nr = -1;
 	rdev->faulty = 0;
 
-	size = 0;
-	if (blk_size[major(newdev)])
-		size = blk_size[major(newdev)][minor(newdev)];
+	size = (blkdev_size_in_bytes(newdev) >> BLOCK_SIZE_BITS);
 	if (!size) {
-		printk(KERN_WARNING "md: %s has zero size, marking faulty!\n",
-				partition_name(newdev));
+		printk(KERN_WARNING
+		       "md: %s has zero or unknown size, marking faulty!\n",
+		       partition_name(newdev));
 		err = -EINVAL;
 		goto abort_free;
 	}
diff -urN linux-2.5.8-pre2/drivers/mtd/devices/blkmtd.c linux-2.5.8-pre3/drivers/mtd/devices/blkmtd.c
--- linux-2.5.8-pre2/drivers/mtd/devices/blkmtd.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/mtd/devices/blkmtd.c	Tue Apr  9 18:35:19 2002
@@ -67,7 +67,6 @@
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
 #define CONFIG_MTD_BLKDEV_ERASESIZE 128
 #define VERSION "1.7"
-extern int *blk_size[];
 
 /* Info for the block device */
 typedef struct mtd_raw_dev_data_s {
@@ -1062,7 +1061,7 @@
 
   int maj, min;
   int i, blocksize, blocksize_bits;
-  loff_t size = 0;
+  loff_t size;
   int readonly = 0;
   int erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
   kdev_t rdev;
@@ -1143,14 +1142,8 @@
     i >>= 1;
   }
 
-  if(count) {
-    size = count;
-  } else {
-    if (blk_size[maj]) {
-      size = ((loff_t) blk_size[maj][min] << BLOCK_SIZE_BITS) >> blocksize_bits;
-    }
-  }
-  size *= blocksize;
+  size = (count ? count*blocksize : blkdev_size_in_bytes(rdev));
+
   DEBUG(1, "blkmtd: size = %ld\n", (long int)size);
 
   if(size == 0) {
diff -urN linux-2.5.8-pre2/drivers/s390/block/xpram.c linux-2.5.8-pre3/drivers/s390/block/xpram.c
--- linux-2.5.8-pre2/drivers/s390/block/xpram.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/s390/block/xpram.c	Tue Apr  9 18:35:19 2002
@@ -1045,7 +1045,7 @@
 		for (i=0; i < xpram_devs; i++) 
 			if (xpram_sizes[i] == 0) xpram_sizes[i] = mem_auto;
 	}
-	blk_size[major]=xpram_sizes;
+	blk_size[major] = xpram_sizes;
 
 	xpram_offsets = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
 	if (!xpram_offsets) {
diff -urN linux-2.5.8-pre2/drivers/scsi/scsi.c linux-2.5.8-pre3/drivers/scsi/scsi.c
--- linux-2.5.8-pre2/drivers/scsi/scsi.c	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/drivers/scsi/scsi.c	Tue Apr  9 18:35:19 2002
@@ -2387,7 +2387,7 @@
 				       kdevname(SCpnt->request.rq_dev),
 				       SCpnt->request.sector,
 				       SCpnt->request.nr_sectors,
-				       SCpnt->request.current_nr_sectors,
+				       (long)SCpnt->request.current_nr_sectors,
 				       SCpnt->request.rq_status,
 				       SCpnt->use_sg,
 
diff -urN linux-2.5.8-pre2/drivers/scsi/sd.c linux-2.5.8-pre3/drivers/scsi/sd.c
--- linux-2.5.8-pre2/drivers/scsi/sd.c	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/drivers/scsi/sd.c	Tue Apr  9 18:35:19 2002
@@ -373,7 +373,7 @@
 
 	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
 				   nbuff,
-		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+		   (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
 				 this_count, SCpnt->request.nr_sectors));
 
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
diff -urN linux-2.5.8-pre2/drivers/usb/Config.help linux-2.5.8-pre3/drivers/usb/Config.help
--- linux-2.5.8-pre2/drivers/usb/Config.help	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/Config.help	Tue Apr  9 18:35:19 2002
@@ -37,387 +37,6 @@
   If you have an MGE Ellipse UPS, or you see timeouts in HID
   transactions, say Y; otherwise say N.
 
-CONFIG_USB_HID
-  Say Y here if you want full HID support to connect keyboards,
-  mice, joysticks, graphic tablets, or any other HID based devices
-  to your computer via USB. You also need to select HID Input layer
-  support (below) if you want to use keyboards, mice, joysticks and
-  the like.
-
-  You can't use this driver and the HIDBP (Boot Protocol) keyboard
-  and mouse drivers at the same time. More information is available:
-  <file:Documentation/input/input.txt>.
-
-  If unsure, say Y.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called hid.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_HIDINPUT
-  Say Y here if you want to use a USB keyboard, mouse or joystick,
-  or any other HID input device. You also need Input layer support, 
-  (CONFIG_INPUT) which you select under "Input core support".
-
-  If unsure, say Y.
-
-CONFIG_USB_HIDDEV
-  Say Y here if you want to support HID devices (from the USB
-  specification standpoint) that aren't strictly user interface
-  devices, like monitor controls and Uninterruptable Power Supplies.
-
-  This module supports these devices separately using a separate
-  event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
-  This driver requires CONFIG_USB_HID.
-
-  If unsure, say Y.
-
-CONFIG_USB_KBD
-  Say Y here only if you are absolutely sure that you don't want
-  to use the generic HID driver for your USB keyboard and prefer
-  to use the keyboard in its limited Boot Protocol mode instead.
-
-  This is almost certainly not what you want.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbkbd.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-  If even remotely unsure, say N.
-
-CONFIG_USB_MOUSE
-  Say Y here only if you are absolutely sure that you don't want
-  to use the generic HID driver for your USB keyboard and prefer
-  to use the keyboard in its limited Boot Protocol mode instead.
-
-  This is almost certainly not what you want.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbmouse.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-  If even remotely unsure, say N.
-
-CONFIG_USB_WACOM
-  Say Y here if you want to use the USB version of the Wacom Intuos
-  or Graphire tablet.  Make sure to say Y to "Mouse support"
-  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-  (CONFIG_INPUT_EVDEV) as well.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called wacom.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_SCANNER
-  Say Y here if you want to connect a USB scanner to your computer's
-  USB port. Please read <file:Documentation/usb/scanner.txt> and
-  <file:Documentation/usb/scanner-hp-sane.txt> for more information.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called scanner.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_AUDIO
-  Say Y here if you want to connect USB audio equipment such as
-  speakers to your computer's USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called audio.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_EMI26
-  This driver loads firmware to Emagic EMI 2|6 low latency USB
-  Audio interface.
-
-  After firmware load the device is handled with standard linux
-  USB Audio driver.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called audio.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_ACM
-  This driver supports USB modems and ISDN adapters which support the
-  Communication Device Class Abstract Control Model interface.
-  Please read <file:Documentation/usb/acm.txt> for details.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called acm.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_PRINTER
-  Say Y here if you want to connect a USB printer to your computer's
-  USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called printer.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_IBMCAM
-  Say Y here if you want to connect a IBM "C-It" camera, also known as
-  "Xirlink PC Camera" to your computer's USB port.  For more
-  information, read <file:Documentation/usb/ibmcam.txt>.
-
-  This driver uses the Video For Linux API.  You must enable
-  (Y or M in config) Video For Linux (under Character Devices)
-  to use this driver.  Information on this API and pointers to
-  "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ibmcam.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>. This
-  camera has several configuration options which can be specified when
-  you load the module.  Read <file:Documentation/usb/ibmcam.txt> to
-  learn more.
-
-CONFIG_USB_OV511
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port. See <file:Documentation/usb/ov511.txt> for more
-  information and for a list of supported cameras.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Character Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ov511.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_CDCETHER
-  This driver supports devices conforming to the Communication Device
-  Class Ethernet Control Model.  This is used in some cable modems.
-  For more details on the specification, get the Communication Device
-  Class specification from <http://www.usb.org/>.
-
-  This driver should work with the following devices:
-        * Ericsson PipeRider (all variants)
-        * Motorola (DM100 and SB4100)
-        * Broadcom Cable Modem (reference design)
-        * Toshiba PCX1100U and possibly other cable modems
-
-  The device creates a network device (ethX, where X depends on what
-  other networking devices you have in use), as for a normal PCI
-  or ISA based ethernet network card.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called CDCEther.o.  If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_PWC
-  Say Y or M here if you want to use one of these Philips USB webcams:
-  PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or
-  the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported
-  by this driver and never will be.
-
-  This driver has an optional plugin, which is distributed as a binary
-  module only.  It contains code that allow you to use higher
-  resolutions and framerates but may not be distributed as source.
-  But even without this plugin you can these cams for most
-  applications.
-
-  See <file:Documentation/usb/philips.txt> for more information and
-  installation instructions.
-
-  The built-in microphone is enabled by selecting USB Audio support.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Character Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called pwc.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_SE401
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port. See <file:Documentation/usb/se401.txt> for more
-  information and for a list of supported cameras.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Multimedia Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called se401.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_STV680
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port. This includes the Pencam line of cameras.
-  See <file:Documentation/usb/stv680.txt> for more information and for
-  a list of supported cameras.
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Multimedia Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called stv680.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_VICAM
-  Say Y here if you have 3com homeconnect camera (vicam).
-
-  This driver uses the Video For Linux API. You must say Y or M to
-  "Video For Linux" (under Multimedia Devices) to use this driver.
-  Information on this API and pointers to "v4l" programs may be found
-  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called vicam.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_PEGASUS
-  Say Y here if you know you have Pegasus or Pegasus-II based adapter.
-  If in doubt then look at linux/drivers/usb/pegasus.h for the complete
-  list of supported devices.
-  If your particular adapter is not in the list and you are _sure_ it
-  is Pegasus or Pegasus II based then send me (petkan@users.sourceforge.net)
-  vendor and device IDs.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called pegasus.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_RTL8150
-  Say Y here if you have RTL8150 based usb-ethernet adapter.
-  Send me (petkan@users.sourceforge.net) any comments you may have.
-  You can also check for updates at http://pegasus2.sourceforge.net/
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called rtl8150.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_KAWETH
-  Say Y here if you want to use one of the following 10Mbps only
-  USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
-       3Com 3C19250
-       ADS USB-10BT
-       ATEN USB Ethernet
-       ASANTE USB To Ethernet Adapter
-       AOX Endpoints USB Ethernet
-       Correga K.K.
-       D-Link DSB-650C and DU-E10
-       Entrega / Portgear E45
-       I-O DATA USB-ET/T
-       Jaton USB Ethernet Device Adapter
-       Kingston Technology USB Ethernet Adapter
-       Linksys USB10T
-       Mobility USB-Ethernet Adapter
-       NetGear EA-101
-       Peracom Enet and Enet2
-       Portsmith Express Ethernet Adapter
-       Shark Pocket Adapter
-       SMC 2202USB
-       Sony Vaio port extender
-
-  This driver is likely to work with most 10Mbps only USB Ethernet
-  adapters, including some "no brand" devices. It does NOT work on
-  SmartBridges smartNIC or on Belkin F5U111 devices - you should use
-  the CATC NetMate driver for those. If you are not sure which one
-  you need, select both, and the correct one should be selected for
-  you.
-
-  This driver makes the adapter appear as a normal Ethernet interface,
-  typically on eth0, if it is the only ethernet device, or perhaps on
-  eth1, if you have a PCI or ISA ethernet card installed.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called kaweth.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_CATC
-  Say Y if you want to use one of the following 10Mbps USB Ethernet
-  device based on the EL1210A chip. Supported devices are:
-    Belkin F5U011
-    Belkin F5U111
-    CATC NetMate
-    CATC NetMate II
-    smartBridges smartNIC
-
-  This driver makes the adapter appear as a normal Ethernet interface,
-  typically on eth0, if it is the only ethernet device, or perhaps on
-  eth1, if you have a PCI or ISA ethernet card installed.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called catc.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_DC2XX
-  Say Y here if you want to connect this type of still camera to your
-  computer's USB port.  See <file:Documentation/usb/dc2xx.txt> for
-  more information; some non-Kodak cameras may also work with this
-  driver, given application support (such as <http://www.gphoto.org/>).
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dc2xx.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_MDC800
-  Say Y here if you want to connect this type of still camera to
-  your computer's USB port. This driver can be used with gphoto 0.4.3
-  and higher (look at <http://www.gphoto.org/>).
-  To use it create a device node with "mknod /dev/mustek c 180 32" and
-  configure it in your software.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called mdc800.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_USS720
-  This driver is for USB parallel port adapters that use the Lucent
-  Technologies USS-720 chip. These cables are plugged into your USB
-  port and provide USB compatibility to peripherals designed with
-  parallel port interfaces.
-
-  The chip has two modes: automatic mode and manual mode. In automatic
-  mode, it looks to the computer like a standard USB printer. Only
-  printers may be connected to the USS-720 in this mode. The generic
-  USB printer driver ("USB Printer support", above) may be used in
-  that mode, and you can say N here if you want to use the chip only
-  in this mode.
-
-  Manual mode is not limited to printers, any parallel port
-  device should work. This driver utilizes manual mode.
-  Note however that some operations are three orders of magnitude
-  slower than on a PCI/ISA Parallel Port, so timing critical
-  applications might not work.
-
-  Say Y here if you own an USS-720 USB->Parport cable and intend to
-  connect anything other than a printer to it.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called uss720.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
 CONFIG_USB_DEVICEFS
   If you say Y here (and to "/proc file system support" in the "File
   systems section, above), you will get a file /proc/bus/usb/devices
@@ -430,8 +49,8 @@
   meaning they are generated on the fly and not stored on the hard
   drive.
 
-  You may need to mount the usbdevfs file system to see the files, use
-   mount -t usbdevfs none /proc/bus/usb
+  You may need to mount the usbfs file system to see the files, use
+     mount -t usbfs none /proc/bus/usb
 
   For the format of the various /proc/bus/usb/ files, please read
   <file:Documentation/usb/proc_usb_info.txt>.
@@ -450,129 +69,3 @@
   If you say N here, these conditions will cause warning messages
   about USB bandwidth usage to be logged and some devices or
   drivers may not work correctly.
-
-CONFIG_USB_DABUSB
-  A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
-  brought to you by the DAB-Team (<http://dab.in.tum.de/>).  This
-  driver can be taken as an example for URB-based bulk, control, and
-  isochronous transactions. URB's are explained in
-  <file:Documentation/usb/URB.txt>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dabusb.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_KONICAWC
-  Say Y here if you want support for webcams based on a Konica
-  chipset. This is known to work with the Intel YC76 webcam.
-
-  This driver uses the Video For Linux API.  You must enable
-  (Y or M in config) Video For Linux (under Character Devices)
-  to use this driver.  Information on this API and pointers to
-  "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called konicawc.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_USBNET
-  This driver supports network links over USB with USB "Network"
-  or "data transfer" cables, often used to network laptops to PCs.
-  Such cables have chips from suppliers such as Belkin/eTEK, GeneSys
-  (GeneLink), NetChip and Prolific. Intelligent USB devices could also
-  use this approach to provide Internet access, using standard USB
-  cabling. You can find these chips also on some motherboards with
-  USB PC2PC support.
-
-  These links will have names like "usb0", "usb1", etc.  They act
-  like two-node Ethernets, so you can use 802.1d Ethernet Bridging
-  (CONFIG_BRIDGE) to simplify your network routing.
-
-  This code is also available as a kernel module (code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called usbnet.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_RIO500
-  Say Y here if you want to connect a USB Rio500 mp3 player to your
-  computer's USB port. Please read <file:Documentation/usb/rio.txt>
-  for more information.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called rio500.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_AUERSWALD
-  Say Y here if you want to connect an Auerswald USB ISDN Device
-  to your computer's USB port.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called auerswald.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_DSBR
-  Say Y here if you want to connect this type of radio to your
-  computer's USB port. Note that the audio is not digital, and
-  you must connect the line out connector to a sound card or a
-  set of speakers.
-
-  This driver uses the Video For Linux API.  You must enable
-  (Y or M in config) Video For Linux (under Character Devices)
-  to use this driver.  Information on this API and pointers to
-  "v4l" programs may be found on the WWW at
-  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dsbr100.o. If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_MICROTEK
-  Say Y here if you want support for the Microtek X6USB and
-  possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L.
-  Support for anything but the X6 is experimental.
-  Please report failures and successes.
-  The scanner will appear as a scsi generic device to the rest
-  of the system. Scsi support is required.
-  This driver can be compiled as a module, called microtek.o.
-
-CONFIG_USB_HPUSBSCSI
-  Say Y here if you want support for the HP 53xx series of scanners
-  and the Minolta Scan Dual. This driver is experimental.
-  The scanner will be accessible as a SCSI device.
-  This can be compiled as a module, called hpusbscsi.o.
-
-CONFIG_USB_BLUETOOTH
-  Say Y here if you want to connect a USB Bluetooth device to your
-  computer's USB port. You will need the Bluetooth stack (available
-  at <http://developer.axis.com/software/index.shtml>) to fully use
-  the device.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called bluetooth.o. If you want to compile it as
-  a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_TIGL
-  If you own a Texas Instruments graphing calculator and use a 
-  TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
-  interested in this driver.
-
-  If you enable this driver, you will be able to communicate with
-  your calculator through a set of device nodes under /dev.
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called tiglusb.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
-
-  If you don't know what the SilverLink cable is or what a Texas
-  Instruments graphing calculator is, then you probably don't need this
-  driver.
-
-  If unsure, say N.
diff -urN linux-2.5.8-pre2/drivers/usb/class/Config.help linux-2.5.8-pre3/drivers/usb/class/Config.help
--- linux-2.5.8-pre2/drivers/usb/class/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/usb/class/Config.help	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,44 @@
+CONFIG_USB_ACM
+  This driver supports USB modems and ISDN adapters which support the
+  Communication Device Class Abstract Control Model interface.
+  Please read <file:Documentation/usb/acm.txt> for details.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called acm.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_AUDIO
+  Say Y here if you want to connect USB audio equipment such as
+  speakers to your computer's USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called audio.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_BLUETOOTH_TTY
+  Say Y here if you want to connect a USB Bluetooth device to your
+  computer's USB port. You will need the Bluetooth stack (available
+  at <http://developer.axis.com/software/index.shtml>) to fully use
+  the device.
+
+  This driver implements a tty inteface to a Bluetooth device.  If
+  you want to use a socket based Bluetooth stack (like the BlueZ
+  stack), do not use this driver.
+
+  If in doubt, say N here.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called bluetty.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_PRINTER
+  Say Y here if you want to connect a USB printer to your computer's
+  USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called printer.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -urN linux-2.5.8-pre2/drivers/usb/class/Config.in linux-2.5.8-pre3/drivers/usb/class/Config.in
--- linux-2.5.8-pre2/drivers/usb/class/Config.in	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/class/Config.in	Tue Apr  9 18:35:19 2002
@@ -3,14 +3,14 @@
 #
 comment 'USB Device Class drivers'
 dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
-dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Bluetooth TTY support' CONFIG_USB_BLUETOOTH_TTY $CONFIG_USB
 dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
 dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
 
 
 # Turn on CONFIG_USB_CLASS if any of the drivers are compiled into the kernel
 # to make our Makefile logic a bit simpler.
-if [ "$CONFIG_USB_AUDIO" = "y" -o "$CONFIG_USB_BLUETOOTH" = "y" ]; then
+if [ "$CONFIG_USB_AUDIO" = "y" -o "$CONFIG_USB_BLUETOOTH_TTY" = "y" ]; then
    define_bool CONFIG_USB_CLASS y
 fi
 if [ "$CONFIG_USB_ACM" = "y" -o "$CONFIG_USB_PRINTER" = "y" ]; then
diff -urN linux-2.5.8-pre2/drivers/usb/class/Makefile linux-2.5.8-pre3/drivers/usb/class/Makefile
--- linux-2.5.8-pre2/drivers/usb/class/Makefile	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/class/Makefile	Tue Apr  9 18:35:19 2002
@@ -7,7 +7,7 @@
 
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
-obj-$(CONFIG_USB_BLUETOOTH)	+= bluetooth.o
+obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= bluetty.o
 obj-$(CONFIG_USB_PRINTER)	+= printer.o
 
 
diff -urN linux-2.5.8-pre2/drivers/usb/class/bluetooth.c linux-2.5.8-pre3/drivers/usb/class/bluetooth.c
--- linux-2.5.8-pre2/drivers/usb/class/bluetooth.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/class/bluetooth.c	Wed Dec 31 16:00:00 1969
@@ -1,1364 +0,0 @@
-/*
- * bluetooth.c   Version 0.13
- *
- * Copyright (c) 2000, 2001 Greg Kroah-Hartman	<greg@kroah.com>
- * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
- *
- * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
- * 
- * (2001/11/30) Version 0.13 gkh
- *	- added locking patch from Masoodur Rahman <rmasoodu@in.ibm.com>
- *	- removed active variable, as open_count will do.
- *
- * (2001/07/09) Version 0.12 gkh
- *	- removed in_interrupt() call, as it doesn't make sense to do 
- *	  that anymore.
- *
- * (2001/06/05) Version 0.11 gkh
- *	- Fixed problem with read urb status saying that we have shutdown,
- *	  and that we shouldn't resubmit the urb.  Patch from unknown.
- *
- * (2001/05/28) Version 0.10 gkh
- *	- Fixed problem with using data from userspace in the bluetooth_write
- *	  function as found by the CHECKER project.
- *	- Added a buffer to the write_urb_pool which reduces the number of
- *	  buffers being created and destroyed for ever write.  Also cleans
- *	  up the logic a bit.
- *	- Added a buffer to the control_urb_pool which fixes a memory leak
- *	  when the device is removed from the system.
- *
- * (2001/05/28) Version 0.9 gkh
- *	Fixed problem with bluetooth==NULL for bluetooth_read_bulk_callback
- *	which was found by both the CHECKER project and Mikko Rahkonen.
- *
- * (08/04/2001) gb
- *	Identify version on module load.
- *
- * (2001/03/10) Version 0.8 gkh
- *	Fixed problem with not unlinking interrupt urb on device close
- *	and resubmitting the read urb on error with bluetooth struct.
- *	Thanks to Narayan Mohanram <narayan@RovingNetworks.com> for the
- *	fixes.
- *
- * (11/29/2000) Version 0.7 gkh
- *	Fixed problem with overrunning the tty flip buffer.
- *	Removed unneeded NULL pointer initialization.
- *
- * (10/05/2000) Version 0.6 gkh
- *	Fixed bug with urb->dev not being set properly, now that the usb
- *	core needs it.
- *	Got a real major id number and name.
- *
- * (08/06/2000) Version 0.5 gkh
- *	Fixed problem of not resubmitting the bulk read urb if there is
- *	an error in the callback.  Ericsson devices seem to need this.
- *
- * (07/11/2000) Version 0.4 gkh
- *	Fixed bug in disconnect for when we call tty_hangup
- *	Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not
- *	getting attached to the control urb properly.
- *	Fixed bug in bluetooth_write where we pay attention to the result
- *	of bluetooth_ctrl_msg.
- *
- * (08/03/2000) Version 0.3 gkh mdc
- *	Merged in Mark's changes to make the driver play nice with the Axis
- *	stack.
- *	Made the write bulk use an urb pool to enable larger transfers with
- *	fewer calls to the driver.
- *	Fixed off by one bug in acl pkt receive
- *	Made packet counters specific to each bluetooth device 
- *	Added checks for zero length callbacks
- *	Added buffers for int and bulk packets.  Had to do this otherwise 
- *	packet types could intermingle.
- *	Made a control urb pool for the control messages.
- *
- * (07/11/2000) Version 0.2 gkh
- *	Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe 
- *	function.
- *
- * (07/09/2000) Version 0.1 gkh
- *	Initial release. Has support for sending ACL data (which is really just
- *	a HCI frame.) Raw HCI commands and HCI events are not supported.
- *	A ioctl will probably be needed for the HCI commands and events in the
- *	future. All isoch endpoints are ignored at this time also.
- *	This driver should work for all currently shipping USB Bluetooth 
- *	devices at this time :)
- * 
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-
-#define DEBUG
-#include <linux/usb.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.13"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner"
-#define DRIVER_DESC "USB Bluetooth tty driver"
-
-/* define this if you have hardware that is not good */
-/*#define	BTBUGGYHARDWARE */
-
-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
-#define WIRELESS_CLASS_CODE			0xe0
-#define RF_SUBCLASS_CODE			0x01
-#define BLUETOOTH_PROGRAMMING_PROTOCOL_CODE	0x01
-
-
-#define BLUETOOTH_TTY_MAJOR	216	/* real device node major id */
-#define BLUETOOTH_TTY_MINORS	256	/* whole lotta bluetooth devices */
-
-#define USB_BLUETOOTH_MAGIC	0x6d02	/* magic number for bluetooth struct */
-
-#define BLUETOOTH_CONTROL_REQUEST_TYPE	0x20
-
-/* Bluetooth packet types */
-#define CMD_PKT			0x01
-#define ACL_PKT			0x02
-#define SCO_PKT			0x03
-#define EVENT_PKT		0x04
-#define ERROR_PKT		0x05
-#define NEG_PKT			0x06
-
-/* Message sizes */
-#define MAX_EVENT_SIZE		0xFF
-#define EVENT_HDR_SIZE		3	/* 2 for the header + 1 for the type indicator */
-#define EVENT_BUFFER_SIZE	(MAX_EVENT_SIZE + EVENT_HDR_SIZE)
-
-#define MAX_ACL_SIZE		0xFFFF
-#define ACL_HDR_SIZE		5	/* 4 for the header + 1 for the type indicator */
-#define ACL_BUFFER_SIZE		(MAX_ACL_SIZE + ACL_HDR_SIZE)
-
-/* parity check flag */
-#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-#define CHAR2INT16(c1,c0)	(((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
-
-#define NUM_BULK_URBS		24
-#define NUM_CONTROL_URBS	16
-
-struct usb_bluetooth {
-	int			magic;
-	struct usb_device *	dev;
-	struct tty_driver *	tty_driver;	/* the tty_driver for this device */
-	struct tty_struct *	tty;		/* the coresponding tty for this port */
-
-	unsigned char		minor;		/* the starting minor number for this device */
-	int			throttle;	/* throttled by tty layer */
-	int			open_count;
-	
-	__u8			control_out_bInterfaceNum;
-	struct urb *		control_urb_pool[NUM_CONTROL_URBS];
-	struct usb_ctrlrequest	dr[NUM_CONTROL_URBS];
-
-	unsigned char *		interrupt_in_buffer;
-	struct urb *		interrupt_in_urb;
-	__u8			interrupt_in_endpointAddress;
-	__u8			interrupt_in_interval;
-	int			interrupt_in_buffer_size;
-
-	unsigned char *		bulk_in_buffer;
-	struct urb *		read_urb;
-	__u8			bulk_in_endpointAddress;
-	int			bulk_in_buffer_size;
-
-	int			bulk_out_buffer_size;
-	struct urb *		write_urb_pool[NUM_BULK_URBS];
-	__u8			bulk_out_endpointAddress;
-
-	wait_queue_head_t	write_wait;
-
-	struct tq_struct	tqueue;		/* task queue for line discipline waking up */
-	
-	unsigned int		int_packet_pos;
-	unsigned char		int_buffer[EVENT_BUFFER_SIZE];
-	unsigned int		bulk_packet_pos;
-	unsigned char		bulk_buffer[ACL_BUFFER_SIZE];	/* 64k preallocated, fix? */
-	struct semaphore	lock;
-};
-
-
-/* local function prototypes */
-static int  bluetooth_open		(struct tty_struct *tty, struct file *filp);
-static void bluetooth_close		(struct tty_struct *tty, struct file *filp);
-static int  bluetooth_write		(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
-static int  bluetooth_write_room	(struct tty_struct *tty);
-static int  bluetooth_chars_in_buffer	(struct tty_struct *tty);
-static void bluetooth_throttle		(struct tty_struct *tty);
-static void bluetooth_unthrottle	(struct tty_struct *tty);
-static int  bluetooth_ioctl		(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static void bluetooth_set_termios	(struct tty_struct *tty, struct termios *old);
-
-static void bluetooth_int_callback		(struct urb *urb);
-static void bluetooth_ctrl_callback		(struct urb *urb);
-static void bluetooth_read_bulk_callback	(struct urb *urb);
-static void bluetooth_write_bulk_callback	(struct urb *urb);
-
-static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
-			 	  const struct usb_device_id *id);
-static void usb_bluetooth_disconnect	(struct usb_device *dev, void *ptr);
-
-
-static struct usb_device_id usb_bluetooth_ids [] = {
-	{ USB_DEVICE_INFO(WIRELESS_CLASS_CODE, RF_SUBCLASS_CODE, BLUETOOTH_PROGRAMMING_PROTOCOL_CODE) },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
-
-static struct usb_driver usb_bluetooth_driver = {
-	name:		"bluetooth",
-	probe:		usb_bluetooth_probe,
-	disconnect:	usb_bluetooth_disconnect,
-	id_table:	usb_bluetooth_ids,
-};
-
-static int			bluetooth_refcount;
-static struct tty_driver	bluetooth_tty_driver;
-static struct tty_struct *	bluetooth_tty[BLUETOOTH_TTY_MINORS];
-static struct termios *		bluetooth_termios[BLUETOOTH_TTY_MINORS];
-static struct termios *		bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
-static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS];
-
-
-static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
-{
-	if (!bluetooth) {
-		dbg("%s - bluetooth == NULL", function);
-		return -1;
-	}
-	if (bluetooth->magic != USB_BLUETOOTH_MAGIC) {
-		dbg("%s - bad magic number for bluetooth", function);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function)
-{
-	if (!bluetooth || 
-	    bluetooth_paranoia_check (bluetooth, function)) { 
-		/* then say that we dont have a valid usb_bluetooth thing, which will
-		 * end up generating -ENODEV return values */
-		return NULL;
-	}
-
-	return bluetooth;
-}
-
-
-static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor)
-{
-	return bluetooth_table[minor];
-}
-
-
-static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len)
-{
-	struct urb *urb = NULL;
-	struct usb_ctrlrequest *dr = NULL;
-	int i;
-	int status;
-
-	dbg (__FUNCTION__);
-
-	/* try to find a free urb in our list */
-	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
-		if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) {
-			urb = bluetooth->control_urb_pool[i];
-			dr = &bluetooth->dr[i];
-			break;
-		}
-	}
-	if (urb == NULL) {
-		dbg (__FUNCTION__ " - no free urbs");
-		return -ENOMEM;
-	}
-
-	/* keep increasing the urb transfer buffer to fit the size of the message */
-	if (urb->transfer_buffer == NULL) {
-		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
-		if (urb->transfer_buffer == NULL) {
-			err (__FUNCTION__" - out of memory");
-			return -ENOMEM;
-		}
-	}
-	if (urb->transfer_buffer_length < len) {
-		kfree (urb->transfer_buffer);
-		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
-		if (urb->transfer_buffer == NULL) {
-			err (__FUNCTION__" - out of memory");
-			return -ENOMEM;
-		}
-	}
-	memcpy (urb->transfer_buffer, buf, len);
-
-	dr->bRequestType= BLUETOOTH_CONTROL_REQUEST_TYPE;
-	dr->bRequest = request;
-	dr->wValue = cpu_to_le16((u16) value);
-	dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum);
-	dr->wLength = cpu_to_le16((u16) len);
-	
-	FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
-			  (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth);
-
-	/* send it down the pipe */
-	status = usb_submit_urb(urb, GFP_KERNEL);
-	if (status)
-		dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
-	
-	return status;
-}
-
-
-
-
-
-/*****************************************************************************
- * Driver tty interface functions
- *****************************************************************************/
-static int bluetooth_open (struct tty_struct *tty, struct file * filp)
-{
-	struct usb_bluetooth *bluetooth;
-	int result;
-
-	dbg(__FUNCTION__);
-
-	/* initialize the pointer incase something fails */
-	tty->driver_data = NULL;
-
-	/* get the bluetooth object associated with this tty pointer */
-	bluetooth = get_bluetooth_by_minor (minor(tty->device));
-
-	if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) {
-		return -ENODEV;
-	}
-
-	down (&bluetooth->lock);
- 
-	++bluetooth->open_count;
-	if (bluetooth->open_count == 1) {
-		/* set up our structure making the tty driver remember our object, and us it */
-		tty->driver_data = bluetooth;
-		bluetooth->tty = tty;
-
-		/* force low_latency on so that our tty_push actually forces the data through, 
-	 	* otherwise it is scheduled, and with high data rates (like with OHCI) data
-	 	* can get lost. */
-		bluetooth->tty->low_latency = 1;
-	
-		/* Reset the packet position counters */
-		bluetooth->int_packet_pos = 0;
-		bluetooth->bulk_packet_pos = 0;
-
-#ifndef BTBUGGYHARDWARE
-		/* Start reading from the device */
-		FILL_BULK_URB (bluetooth->read_urb, bluetooth->dev, 
-			       usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-			       bluetooth->bulk_in_buffer,
-			       bluetooth->bulk_in_buffer_size,
-			       bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-		if (result)
-			dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result);
-#endif
-		FILL_INT_URB (bluetooth->interrupt_in_urb, bluetooth->dev,
-			      usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress),
-			      bluetooth->interrupt_in_buffer,
-			      bluetooth->interrupt_in_buffer_size,
-			      bluetooth_int_callback, bluetooth,
-			      bluetooth->interrupt_in_interval);
-		result = usb_submit_urb(bluetooth->interrupt_in_urb, GFP_KERNEL);
-		if (result)
-			dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result);
-	}
-	
-	up(&bluetooth->lock);
-
-	return 0;
-}
-
-
-static void bluetooth_close (struct tty_struct *tty, struct file * filp)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-	int i;
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not opened");
-		return;
-	}
-
-	down (&bluetooth->lock);
- 
-	--bluetooth->open_count;
-	if (bluetooth->open_count <= 0) {
-		bluetooth->open_count = 0;
-
-		/* shutdown any bulk reads and writes that might be going on */
-		for (i = 0; i < NUM_BULK_URBS; ++i)
-			usb_unlink_urb (bluetooth->write_urb_pool[i]);
-		usb_unlink_urb (bluetooth->read_urb);
-		usb_unlink_urb (bluetooth->interrupt_in_urb);
-	}
-	up(&bluetooth->lock);
-}
-
-
-static int bluetooth_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-	struct urb *urb = NULL;
-	unsigned char *temp_buffer = NULL;
-	const unsigned char *current_buffer;
-	const unsigned char *current_position;
-	int bytes_sent;
-	int buffer_size;
-	int i;
-	int retval = 0;
-
-	if (!bluetooth) {
-		return -ENODEV;
-	}
-
-	dbg(__FUNCTION__ " - %d byte(s)", count);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not opened");
-		return -EINVAL;
-	}
-
-	if (count == 0) {
-		dbg(__FUNCTION__ " - write request of 0 bytes");
-		return 0;
-	}
-	if (count == 1) {
-		dbg(__FUNCTION__ " - write request only included type %d", buf[0]);
-		return 1;
-	}
-
-#ifdef DEBUG
-	printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
-	for (i = 0; i < count; ++i) {
-		printk ("%.2x ", buf[i]);
-	}
-	printk ("\n");
-#endif
-
-	if (from_user) {
-		temp_buffer = kmalloc (count, GFP_KERNEL);
-		if (temp_buffer == NULL) {
-			err (__FUNCTION__ "- out of memory.");
-			retval = -ENOMEM;
-			goto exit;
-		}
-		copy_from_user (temp_buffer, buf, count);
-		current_buffer = temp_buffer;
-	} else {
-		current_buffer = buf;
-	}
-
-	switch (*current_buffer) {
-		/* First byte indicates the type of packet */
-		case CMD_PKT:
-			/* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/
-
-			retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, &current_buffer[1], count-1);
-			if (retval) {
-				goto exit;
-			}
-			retval = count;
-			break;
-
-		case ACL_PKT:
-			current_position = current_buffer;
-			++current_position;
-			--count;
-			bytes_sent = 0;
-
-			while (count > 0) {
-				urb = NULL;
-
-				/* try to find a free urb in our list */
-				for (i = 0; i < NUM_BULK_URBS; ++i) {
-					if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
-						urb = bluetooth->write_urb_pool[i];
-						break;
-					}
-				}
-				if (urb == NULL) {
-					dbg (__FUNCTION__ " - no free urbs");
-					retval = bytes_sent;
-					goto exit;
-				}
-				
-
-				buffer_size = min (count, bluetooth->bulk_out_buffer_size);
-				memcpy (urb->transfer_buffer, current_position, buffer_size);
-
-				/* build up our urb */
-				FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress),
-						urb->transfer_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
-				urb->transfer_flags |= USB_QUEUE_BULK;
-
-				/* send it down the pipe */
-				retval = usb_submit_urb(urb, GFP_KERNEL);
-				if (retval) {
-					dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with error = %d", retval);
-					goto exit;
-				}
-#ifdef BTBUGGYHARDWARE
-				/* A workaround for the stalled data bug */
-				/* May or may not be needed...*/
-				if (count != 0) {
-					udelay(500);
-				}
-#endif
-				current_position += buffer_size;
-				bytes_sent += buffer_size;
-				count -= buffer_size;
-			}
-
-			retval = bytes_sent + 1;
-			break;
-		
-		default :
-			dbg(__FUNCTION__" - unsupported (at this time) write type");
-			retval = -EINVAL;
-			break;
-	}
-
-exit:
-	if (temp_buffer != NULL)
-		kfree (temp_buffer);
-
-	return retval;
-} 
-
-
-static int bluetooth_write_room (struct tty_struct *tty) 
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-	int room = 0;
-	int i;
-
-	if (!bluetooth) {
-		return -ENODEV;
-	}
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < NUM_BULK_URBS; ++i) {
-		if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
-			room += bluetooth->bulk_out_buffer_size;
-		}
-	}
-
-	dbg(__FUNCTION__ " - returns %d", room);
-	return room;
-}
-
-
-static int bluetooth_chars_in_buffer (struct tty_struct *tty) 
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-	int chars = 0;
-	int i;
-
-	if (!bluetooth) {
-		return -ENODEV;
-	}
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < NUM_BULK_URBS; ++i) {
-		if (bluetooth->write_urb_pool[i]->status == -EINPROGRESS) {
-			chars += bluetooth->write_urb_pool[i]->transfer_buffer_length;
-		}
-	}
-
-	dbg (__FUNCTION__ " - returns %d", chars);
-	return chars;
-}
-
-
-static void bluetooth_throttle (struct tty_struct * tty)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return;
-	}
-	
-	dbg(__FUNCTION__ " unsupported (at this time)");
-
-	return;
-}
-
-
-static void bluetooth_unthrottle (struct tty_struct * tty)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return;
-	}
-
-	dbg(__FUNCTION__ " unsupported (at this time)");
-}
-
-
-static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return -ENODEV;
-	}
-
-	dbg(__FUNCTION__ " - cmd 0x%.4x", cmd);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return -ENODEV;
-	}
-
-	/* FIXME!!! */
-	return -ENOIOCTLCMD;
-}
-
-
-static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return;
-	}
-
-	/* FIXME!!! */
-
-	return;
-}
-
-
-#ifdef BTBUGGYHARDWARE
-void btusb_enable_bulk_read(struct tty_struct *tty){
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-	int result;
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return;
-	}
-
-	if (bluetooth->read_urb) {
-		FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
-			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-			      bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-		if (result)
-			err (__FUNCTION__ " - failed submitting read urb, error %d", result);
-	}
-}
-
-void btusb_disable_bulk_read(struct tty_struct *tty){
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg (__FUNCTION__ " - device not open");
-		return;
-	}
-
-	if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length))
-		usb_unlink_urb(bluetooth->read_urb);
-}
-#endif
-
-
-/*****************************************************************************
- * urb callback functions
- *****************************************************************************/
-
-
-static void bluetooth_int_callback (struct urb *urb)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-	unsigned char *data = urb->transfer_buffer;
-	unsigned int i;
-	unsigned int count = urb->actual_length;
-	unsigned int packet_size;
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
-		return;
-	}
-
-	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status);
-		return;
-	}
-
-	if (!count) {
-		dbg(__FUNCTION__ " - zero length int");
-		return;
-	}
-
-
-#ifdef DEBUG
-	if (count) {
-		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
-		for (i = 0; i < count; ++i) {
-			printk ("%.2x ", data[i]);
-		}
-		printk ("\n");
-	}
-#endif
-
-#ifdef BTBUGGYHARDWARE
-	if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) {
-		data += 2;
-		count -= 2;
-	}
-	if (count == 0) {
-		urb->actual_length = 0;
-		return;
-	}
-#endif
-	/* We add  a packet type identifier to the beginning of each
-	   HCI frame.  This makes the data in the tty look like a
-	   serial USB devices.  Each HCI frame can be broken across
-	   multiple URBs so we buffer them until we have a full hci
-	   packet */
-
-	if (!bluetooth->int_packet_pos) {
-		bluetooth->int_buffer[0] = EVENT_PKT;
-		bluetooth->int_packet_pos++;
-	}
-	
-	if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) {
-		err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE");
-		bluetooth->int_packet_pos = 0;
-		return;
-	}
-
-	memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos],
-		urb->transfer_buffer, count);
-	bluetooth->int_packet_pos += count;
-	urb->actual_length = 0;
-
-	if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE)
-		packet_size = bluetooth->int_buffer[2];
-	else
-		return;
-
-	if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) {
-		err(__FUNCTION__ " - packet was too long");
-		bluetooth->int_packet_pos = 0;
-		return;
-	}
-
-	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) {
-		for (i = 0; i < bluetooth->int_packet_pos; ++i) {
-			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */
-			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
-				tty_flip_buffer_push(bluetooth->tty);
-			}
-			tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
-		}
-		tty_flip_buffer_push(bluetooth->tty);
-
-		bluetooth->int_packet_pos = 0;
-	}
-}
-
-
-static void bluetooth_ctrl_callback (struct urb *urb)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
-		return;
-	}
-
-	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
-		return;
-	}
-}
-
-
-static void bluetooth_read_bulk_callback (struct urb *urb)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-	unsigned char *data = urb->transfer_buffer;
-	unsigned int count = urb->actual_length;
-	unsigned int i;
-	unsigned int packet_size;
-	int result;
-
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
-		return;
-	}
-
-	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
-		if (urb->status == -ENOENT) {                   
-			dbg(__FUNCTION__ " - URB canceled, won't reschedule");
-			return;
-		}
-		goto exit;
-	}
-
-	if (!count) {
-		dbg(__FUNCTION__ " - zero length read bulk");
-		goto exit;
-	}
-
-#ifdef DEBUG
-	if (count) {
-		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
-		for (i = 0; i < count; ++i) {
-			printk ("%.2x ", data[i]);
-		}
-		printk ("\n");
-	}
-#endif
-#ifdef BTBUGGYHARDWARE
-	if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
-	    && (data[2] == 0x00) && (data[3] == 0x00)) {
-		urb->actual_length = 0;
-		FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
-			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-			      bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-		if (result)
-			err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
-
-		return;
-	}
-#endif
-	/* We add  a packet type identifier to the beginning of each
-	   HCI frame.  This makes the data in the tty look like a
-	   serial USB devices.  Each HCI frame can be broken across
-	   multiple URBs so we buffer them until we have a full hci
-	   packet */
-	
-	if (!bluetooth->bulk_packet_pos) {
-		bluetooth->bulk_buffer[0] = ACL_PKT;
-		bluetooth->bulk_packet_pos++;
-	}
-
-	if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
-		err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE");
-		bluetooth->bulk_packet_pos = 0;
-		goto exit;
-	}
-
-	memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos],
-		urb->transfer_buffer, count);
-	bluetooth->bulk_packet_pos += count;
-	urb->actual_length = 0;
-
-	if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) {
-		packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]);
-	} else {
-		goto exit;
-	}
-
-	if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
-		err(__FUNCTION__ " - packet was too long");
-		bluetooth->bulk_packet_pos = 0;
-		goto exit;
-	}
-
-	if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
-		for (i = 0; i < bluetooth->bulk_packet_pos; ++i) {
-			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
-			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
-				tty_flip_buffer_push(bluetooth->tty);
-			}
-			tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
-		}
-		tty_flip_buffer_push(bluetooth->tty);
-		bluetooth->bulk_packet_pos = 0;
-	}	
-
-exit:
-	if (!bluetooth || !bluetooth->open_count)
-		return;
-
-	FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
-		      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-		      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-		      bluetooth_read_bulk_callback, bluetooth);
-	result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-	if (result)
-		err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
-
-	return;
-}
-
-
-static void bluetooth_write_bulk_callback (struct urb *urb)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth) {
-		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
-		return;
-	}
-
-	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
-		return;
-	}
-
-	/* wake up our little function to let the tty layer know that something happened */
-	queue_task(&bluetooth->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-	return;
-}
-
-
-static void bluetooth_softint(void *private)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__);
-	struct tty_struct *tty;
-
-	dbg(__FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	tty = bluetooth->tty;
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-		dbg(__FUNCTION__ " - write wakeup call.");
-		(tty->ldisc.write_wakeup)(tty);
-	}
-
-	wake_up_interruptible(&tty->write_wait);
-}
-
-
-static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
-			 	  const struct usb_device_id *id)
-{
-	struct usb_bluetooth *bluetooth = NULL;
-	struct usb_interface_descriptor *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_endpoint_descriptor *interrupt_in_endpoint[8];
-	struct usb_endpoint_descriptor *bulk_in_endpoint[8];
-	struct usb_endpoint_descriptor *bulk_out_endpoint[8];
-	int control_out_endpoint;
-
-	int minor;
-	int buffer_size;
-	int i;
-	int num_interrupt_in = 0;
-	int num_bulk_in = 0;
-	int num_bulk_out = 0;
-
-	interface = &dev->actconfig->interface[ifnum].altsetting[0];
-	control_out_endpoint = interface->bInterfaceNumber;
-
-	/* find the endpoints that we need */
-	for (i = 0; i < interface->bNumEndpoints; ++i) {
-		endpoint = &interface->endpoint[i];
-
-		if ((endpoint->bEndpointAddress & 0x80) &&
-		    ((endpoint->bmAttributes & 3) == 0x02)) {
-			/* we found a bulk in endpoint */
-			dbg("found bulk in");
-			bulk_in_endpoint[num_bulk_in] = endpoint;
-			++num_bulk_in;
-		}
-
-		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-		    ((endpoint->bmAttributes & 3) == 0x02)) {
-			/* we found a bulk out endpoint */
-			dbg("found bulk out");
-			bulk_out_endpoint[num_bulk_out] = endpoint;
-			++num_bulk_out;
-		}
-
-		if ((endpoint->bEndpointAddress & 0x80) &&
-		    ((endpoint->bmAttributes & 3) == 0x03)) {
-			/* we found a interrupt in endpoint */
-			dbg("found interrupt in");
-			interrupt_in_endpoint[num_interrupt_in] = endpoint;
-			++num_interrupt_in;
-		}
-	}
-
-	/* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */
-	if ((num_bulk_in != 1) ||
-	    (num_bulk_out != 1) ||
-	    (num_interrupt_in != 1)) {
-		dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound.");
-		return NULL;
-	}
-
-	MOD_INC_USE_COUNT;
-	info("USB Bluetooth converter detected");
-
-	for (minor = 0; minor < BLUETOOTH_TTY_MINORS && bluetooth_table[minor]; ++minor)
-		;
-	if (bluetooth_table[minor]) {
-		err("No more free Bluetooth devices");
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
-
-	if (!(bluetooth = kmalloc(sizeof(struct usb_bluetooth), GFP_KERNEL))) {
-		err("Out of memory");
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
-
-	memset(bluetooth, 0, sizeof(struct usb_bluetooth));
-
-	bluetooth->magic = USB_BLUETOOTH_MAGIC;
-	bluetooth->dev = dev;
-	bluetooth->minor = minor;
-	bluetooth->tqueue.routine = bluetooth_softint;
-	bluetooth->tqueue.data = bluetooth;
-	init_MUTEX(&bluetooth->lock);
-
-	/* record the interface number for the control out */
-	bluetooth->control_out_bInterfaceNum = control_out_endpoint;
-	
-	/* create our control out urb pool */ 
-	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
-		struct urb  *urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (urb == NULL) {
-			err("No free urbs available");
-			goto probe_error;
-		}
-		urb->transfer_buffer = NULL;
-		bluetooth->control_urb_pool[i] = urb;
-	}
-
-	/* set up the endpoint information */
-	endpoint = bulk_in_endpoint[0];
-	bluetooth->read_urb = usb_alloc_urb (0, GFP_KERNEL);
-	if (!bluetooth->read_urb) {
-		err("No free urbs available");
-		goto probe_error;
-	}
-	bluetooth->bulk_in_buffer_size = buffer_size = endpoint->wMaxPacketSize;
-	bluetooth->bulk_in_endpointAddress = endpoint->bEndpointAddress;
-	bluetooth->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-	if (!bluetooth->bulk_in_buffer) {
-		err("Couldn't allocate bulk_in_buffer");
-		goto probe_error;
-	}
-	FILL_BULK_URB(bluetooth->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
-		      bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth);
-
-	endpoint = bulk_out_endpoint[0];
-	bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
-	
-	/* create our write urb pool */ 
-	for (i = 0; i < NUM_BULK_URBS; ++i) {
-		struct urb  *urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (urb == NULL) {
-			err("No free urbs available");
-			goto probe_error;
-		}
-		urb->transfer_buffer = kmalloc (bluetooth->bulk_out_buffer_size, GFP_KERNEL);
-		if (urb->transfer_buffer == NULL) {
-			err("out of memory");
-			goto probe_error;
-		}
-		bluetooth->write_urb_pool[i] = urb;
-	}
-	
-	bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
-
-	endpoint = interrupt_in_endpoint[0];
-	bluetooth->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!bluetooth->interrupt_in_urb) {
-		err("No free urbs available");
-		goto probe_error;
-	}
-	bluetooth->interrupt_in_buffer_size = buffer_size = endpoint->wMaxPacketSize;
-	bluetooth->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
-	bluetooth->interrupt_in_interval = endpoint->bInterval;
-	bluetooth->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-	if (!bluetooth->interrupt_in_buffer) {
-		err("Couldn't allocate interrupt_in_buffer");
-		goto probe_error;
-	}
-	FILL_INT_URB(bluetooth->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-		     bluetooth->interrupt_in_buffer, buffer_size, bluetooth_int_callback,
-		     bluetooth, endpoint->bInterval);
-
-	/* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
-	tty_register_devfs (&bluetooth_tty_driver, 0, minor);
-	info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor);
-
-	bluetooth_table[minor] = bluetooth;
-
-	return bluetooth; /* success */
-
-probe_error:
-	if (bluetooth->read_urb)
-		usb_free_urb (bluetooth->read_urb);
-	if (bluetooth->bulk_in_buffer)
-		kfree (bluetooth->bulk_in_buffer);
-	if (bluetooth->interrupt_in_urb)
-		usb_free_urb (bluetooth->interrupt_in_urb);
-	if (bluetooth->interrupt_in_buffer)
-		kfree (bluetooth->interrupt_in_buffer);
-	for (i = 0; i < NUM_BULK_URBS; ++i)
-		if (bluetooth->write_urb_pool[i]) {
-			if (bluetooth->write_urb_pool[i]->transfer_buffer)
-				kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
-			usb_free_urb (bluetooth->write_urb_pool[i]);
-		}
-	for (i = 0; i < NUM_CONTROL_URBS; ++i) 
-		if (bluetooth->control_urb_pool[i]) {
-			if (bluetooth->control_urb_pool[i]->transfer_buffer)
-				kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
-			usb_free_urb (bluetooth->control_urb_pool[i]);
-		}
-
-	bluetooth_table[minor] = NULL;
-
-	/* free up any memory that we allocated */
-	kfree (bluetooth);
-	MOD_DEC_USE_COUNT;
-	return NULL;
-}
-
-
-static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct usb_bluetooth *bluetooth = (struct usb_bluetooth *) ptr;
-	int i;
-
-	if (bluetooth) {
-		if ((bluetooth->open_count) && (bluetooth->tty))
-			tty_hangup(bluetooth->tty);
-
-		bluetooth->open_count = 0;
-
-		if (bluetooth->read_urb) {
-			usb_unlink_urb (bluetooth->read_urb);
-			usb_free_urb (bluetooth->read_urb);
-		}
-		if (bluetooth->bulk_in_buffer)
-			kfree (bluetooth->bulk_in_buffer);
-
-		if (bluetooth->interrupt_in_urb) {
-			usb_unlink_urb (bluetooth->interrupt_in_urb);
-			usb_free_urb (bluetooth->interrupt_in_urb);
-		}
-		if (bluetooth->interrupt_in_buffer)
-			kfree (bluetooth->interrupt_in_buffer);
-
-		tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor);
-
-		for (i = 0; i < NUM_BULK_URBS; ++i) {
-			if (bluetooth->write_urb_pool[i]) {
-				usb_unlink_urb (bluetooth->write_urb_pool[i]);
-				if (bluetooth->write_urb_pool[i]->transfer_buffer)
-					kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
-				usb_free_urb (bluetooth->write_urb_pool[i]);
-			}
-		}
-		for (i = 0; i < NUM_CONTROL_URBS; ++i) {
-			if (bluetooth->control_urb_pool[i]) {
-				usb_unlink_urb (bluetooth->control_urb_pool[i]);
-				if (bluetooth->control_urb_pool[i]->transfer_buffer)
-					kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
-				usb_free_urb (bluetooth->control_urb_pool[i]);
-			}
-		}
-		
-		info("Bluetooth converter now disconnected from ttyUB%d", bluetooth->minor);
-
-		bluetooth_table[bluetooth->minor] = NULL;
-
-		/* free up any memory that we allocated */
-		kfree (bluetooth);
-
-	} else {
-		info("device disconnected");
-	}
-
-	MOD_DEC_USE_COUNT;
-}
-
-
-static struct tty_driver bluetooth_tty_driver = {
-	magic:			TTY_DRIVER_MAGIC,
-	driver_name:		"usb-bluetooth",
-	name:			"usb/ttub/%d",
-	major:			BLUETOOTH_TTY_MAJOR,
-	minor_start:		0,
-	num:			BLUETOOTH_TTY_MINORS,
-	type:			TTY_DRIVER_TYPE_SERIAL,
-	subtype:		SERIAL_TYPE_NORMAL,
-	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-
-	refcount:		&bluetooth_refcount,
-	table:			bluetooth_tty,
-	termios:		bluetooth_termios,
-	termios_locked:		bluetooth_termios_locked,
-
-	open:			bluetooth_open,
-	close:			bluetooth_close,
-	write:			bluetooth_write,
-	write_room:		bluetooth_write_room,
-	ioctl:			bluetooth_ioctl,
-	set_termios:		bluetooth_set_termios,
-	throttle:		bluetooth_throttle,
-	unthrottle:		bluetooth_unthrottle,
-	chars_in_buffer:	bluetooth_chars_in_buffer,
-};
-
-
-int usb_bluetooth_init(void)
-{
-	int i;
-	int result;
-
-	/* Initalize our global data */
-	for (i = 0; i < BLUETOOTH_TTY_MINORS; ++i) {
-		bluetooth_table[i] = NULL;
-	}
-
-	info ("USB Bluetooth support registered");
-
-	/* register the tty driver */
-	bluetooth_tty_driver.init_termios          = tty_std_termios;
-	bluetooth_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	if (tty_register_driver (&bluetooth_tty_driver)) {
-		err(__FUNCTION__ " - failed to register tty driver");
-		return -1;
-	}
-
-	/* register the USB driver */
-	result = usb_register(&usb_bluetooth_driver);
-	if (result < 0) {
-		tty_unregister_driver(&bluetooth_tty_driver);
-		err("usb_register failed for the USB bluetooth driver. Error number %d", result);
-		return -1;
-	}
-
-	info(DRIVER_DESC " " DRIVER_VERSION);
-
-	return 0;
-}
-
-
-void usb_bluetooth_exit(void)
-{
-	usb_deregister(&usb_bluetooth_driver);
-	tty_unregister_driver(&bluetooth_tty_driver);
-}
-
-
-module_init(usb_bluetooth_init);
-module_exit(usb_bluetooth_exit);
-
-/* Module information */
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
diff -urN linux-2.5.8-pre2/drivers/usb/class/bluetty.c linux-2.5.8-pre3/drivers/usb/class/bluetty.c
--- linux-2.5.8-pre2/drivers/usb/class/bluetty.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/usb/class/bluetty.c	Tue Apr  9 18:35:19 2002
@@ -0,0 +1,1364 @@
+/*
+ * bluetty.c   Version 0.13
+ *
+ * Copyright (c) 2000, 2001 Greg Kroah-Hartman	<greg@kroah.com>
+ * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
+ *
+ * USB Bluetooth TTY driver, based on the Bluetooth Spec version 1.0B
+ * 
+ * (2001/11/30) Version 0.13 gkh
+ *	- added locking patch from Masoodur Rahman <rmasoodu@in.ibm.com>
+ *	- removed active variable, as open_count will do.
+ *
+ * (2001/07/09) Version 0.12 gkh
+ *	- removed in_interrupt() call, as it doesn't make sense to do 
+ *	  that anymore.
+ *
+ * (2001/06/05) Version 0.11 gkh
+ *	- Fixed problem with read urb status saying that we have shutdown,
+ *	  and that we shouldn't resubmit the urb.  Patch from unknown.
+ *
+ * (2001/05/28) Version 0.10 gkh
+ *	- Fixed problem with using data from userspace in the bluetooth_write
+ *	  function as found by the CHECKER project.
+ *	- Added a buffer to the write_urb_pool which reduces the number of
+ *	  buffers being created and destroyed for ever write.  Also cleans
+ *	  up the logic a bit.
+ *	- Added a buffer to the control_urb_pool which fixes a memory leak
+ *	  when the device is removed from the system.
+ *
+ * (2001/05/28) Version 0.9 gkh
+ *	Fixed problem with bluetooth==NULL for bluetooth_read_bulk_callback
+ *	which was found by both the CHECKER project and Mikko Rahkonen.
+ *
+ * (08/04/2001) gb
+ *	Identify version on module load.
+ *
+ * (2001/03/10) Version 0.8 gkh
+ *	Fixed problem with not unlinking interrupt urb on device close
+ *	and resubmitting the read urb on error with bluetooth struct.
+ *	Thanks to Narayan Mohanram <narayan@RovingNetworks.com> for the
+ *	fixes.
+ *
+ * (11/29/2000) Version 0.7 gkh
+ *	Fixed problem with overrunning the tty flip buffer.
+ *	Removed unneeded NULL pointer initialization.
+ *
+ * (10/05/2000) Version 0.6 gkh
+ *	Fixed bug with urb->dev not being set properly, now that the usb
+ *	core needs it.
+ *	Got a real major id number and name.
+ *
+ * (08/06/2000) Version 0.5 gkh
+ *	Fixed problem of not resubmitting the bulk read urb if there is
+ *	an error in the callback.  Ericsson devices seem to need this.
+ *
+ * (07/11/2000) Version 0.4 gkh
+ *	Fixed bug in disconnect for when we call tty_hangup
+ *	Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not
+ *	getting attached to the control urb properly.
+ *	Fixed bug in bluetooth_write where we pay attention to the result
+ *	of bluetooth_ctrl_msg.
+ *
+ * (08/03/2000) Version 0.3 gkh mdc
+ *	Merged in Mark's changes to make the driver play nice with the Axis
+ *	stack.
+ *	Made the write bulk use an urb pool to enable larger transfers with
+ *	fewer calls to the driver.
+ *	Fixed off by one bug in acl pkt receive
+ *	Made packet counters specific to each bluetooth device 
+ *	Added checks for zero length callbacks
+ *	Added buffers for int and bulk packets.  Had to do this otherwise 
+ *	packet types could intermingle.
+ *	Made a control urb pool for the control messages.
+ *
+ * (07/11/2000) Version 0.2 gkh
+ *	Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe 
+ *	function.
+ *
+ * (07/09/2000) Version 0.1 gkh
+ *	Initial release. Has support for sending ACL data (which is really just
+ *	a HCI frame.) Raw HCI commands and HCI events are not supported.
+ *	A ioctl will probably be needed for the HCI commands and events in the
+ *	future. All isoch endpoints are ignored at this time also.
+ *	This driver should work for all currently shipping USB Bluetooth 
+ *	devices at this time :)
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+
+#define DEBUG
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.13"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner"
+#define DRIVER_DESC "USB Bluetooth tty driver"
+
+/* define this if you have hardware that is not good */
+/*#define	BTBUGGYHARDWARE */
+
+/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
+#define WIRELESS_CLASS_CODE			0xe0
+#define RF_SUBCLASS_CODE			0x01
+#define BLUETOOTH_PROGRAMMING_PROTOCOL_CODE	0x01
+
+
+#define BLUETOOTH_TTY_MAJOR	216	/* real device node major id */
+#define BLUETOOTH_TTY_MINORS	256	/* whole lotta bluetooth devices */
+
+#define USB_BLUETOOTH_MAGIC	0x6d02	/* magic number for bluetooth struct */
+
+#define BLUETOOTH_CONTROL_REQUEST_TYPE	0x20
+
+/* Bluetooth packet types */
+#define CMD_PKT			0x01
+#define ACL_PKT			0x02
+#define SCO_PKT			0x03
+#define EVENT_PKT		0x04
+#define ERROR_PKT		0x05
+#define NEG_PKT			0x06
+
+/* Message sizes */
+#define MAX_EVENT_SIZE		0xFF
+#define EVENT_HDR_SIZE		3	/* 2 for the header + 1 for the type indicator */
+#define EVENT_BUFFER_SIZE	(MAX_EVENT_SIZE + EVENT_HDR_SIZE)
+
+#define MAX_ACL_SIZE		0xFFFF
+#define ACL_HDR_SIZE		5	/* 4 for the header + 1 for the type indicator */
+#define ACL_BUFFER_SIZE		(MAX_ACL_SIZE + ACL_HDR_SIZE)
+
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+#define CHAR2INT16(c1,c0)	(((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
+
+#define NUM_BULK_URBS		24
+#define NUM_CONTROL_URBS	16
+
+struct usb_bluetooth {
+	int			magic;
+	struct usb_device *	dev;
+	struct tty_driver *	tty_driver;	/* the tty_driver for this device */
+	struct tty_struct *	tty;		/* the coresponding tty for this port */
+
+	unsigned char		minor;		/* the starting minor number for this device */
+	int			throttle;	/* throttled by tty layer */
+	int			open_count;
+	
+	__u8			control_out_bInterfaceNum;
+	struct urb *		control_urb_pool[NUM_CONTROL_URBS];
+	struct usb_ctrlrequest	dr[NUM_CONTROL_URBS];
+
+	unsigned char *		interrupt_in_buffer;
+	struct urb *		interrupt_in_urb;
+	__u8			interrupt_in_endpointAddress;
+	__u8			interrupt_in_interval;
+	int			interrupt_in_buffer_size;
+
+	unsigned char *		bulk_in_buffer;
+	struct urb *		read_urb;
+	__u8			bulk_in_endpointAddress;
+	int			bulk_in_buffer_size;
+
+	int			bulk_out_buffer_size;
+	struct urb *		write_urb_pool[NUM_BULK_URBS];
+	__u8			bulk_out_endpointAddress;
+
+	wait_queue_head_t	write_wait;
+
+	struct tq_struct	tqueue;		/* task queue for line discipline waking up */
+	
+	unsigned int		int_packet_pos;
+	unsigned char		int_buffer[EVENT_BUFFER_SIZE];
+	unsigned int		bulk_packet_pos;
+	unsigned char		bulk_buffer[ACL_BUFFER_SIZE];	/* 64k preallocated, fix? */
+	struct semaphore	lock;
+};
+
+
+/* local function prototypes */
+static int  bluetooth_open		(struct tty_struct *tty, struct file *filp);
+static void bluetooth_close		(struct tty_struct *tty, struct file *filp);
+static int  bluetooth_write		(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
+static int  bluetooth_write_room	(struct tty_struct *tty);
+static int  bluetooth_chars_in_buffer	(struct tty_struct *tty);
+static void bluetooth_throttle		(struct tty_struct *tty);
+static void bluetooth_unthrottle	(struct tty_struct *tty);
+static int  bluetooth_ioctl		(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
+static void bluetooth_set_termios	(struct tty_struct *tty, struct termios *old);
+
+static void bluetooth_int_callback		(struct urb *urb);
+static void bluetooth_ctrl_callback		(struct urb *urb);
+static void bluetooth_read_bulk_callback	(struct urb *urb);
+static void bluetooth_write_bulk_callback	(struct urb *urb);
+
+static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
+			 	  const struct usb_device_id *id);
+static void usb_bluetooth_disconnect	(struct usb_device *dev, void *ptr);
+
+
+static struct usb_device_id usb_bluetooth_ids [] = {
+	{ USB_DEVICE_INFO(WIRELESS_CLASS_CODE, RF_SUBCLASS_CODE, BLUETOOTH_PROGRAMMING_PROTOCOL_CODE) },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
+
+static struct usb_driver usb_bluetooth_driver = {
+	name:		"bluetty",
+	probe:		usb_bluetooth_probe,
+	disconnect:	usb_bluetooth_disconnect,
+	id_table:	usb_bluetooth_ids,
+};
+
+static int			bluetooth_refcount;
+static struct tty_driver	bluetooth_tty_driver;
+static struct tty_struct *	bluetooth_tty[BLUETOOTH_TTY_MINORS];
+static struct termios *		bluetooth_termios[BLUETOOTH_TTY_MINORS];
+static struct termios *		bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
+static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS];
+
+
+static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
+{
+	if (!bluetooth) {
+		dbg("%s - bluetooth == NULL", function);
+		return -1;
+	}
+	if (bluetooth->magic != USB_BLUETOOTH_MAGIC) {
+		dbg("%s - bad magic number for bluetooth", function);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function)
+{
+	if (!bluetooth || 
+	    bluetooth_paranoia_check (bluetooth, function)) { 
+		/* then say that we dont have a valid usb_bluetooth thing, which will
+		 * end up generating -ENODEV return values */
+		return NULL;
+	}
+
+	return bluetooth;
+}
+
+
+static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor)
+{
+	return bluetooth_table[minor];
+}
+
+
+static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len)
+{
+	struct urb *urb = NULL;
+	struct usb_ctrlrequest *dr = NULL;
+	int i;
+	int status;
+
+	dbg (__FUNCTION__);
+
+	/* try to find a free urb in our list */
+	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+		if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) {
+			urb = bluetooth->control_urb_pool[i];
+			dr = &bluetooth->dr[i];
+			break;
+		}
+	}
+	if (urb == NULL) {
+		dbg (__FUNCTION__ " - no free urbs");
+		return -ENOMEM;
+	}
+
+	/* keep increasing the urb transfer buffer to fit the size of the message */
+	if (urb->transfer_buffer == NULL) {
+		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
+		if (urb->transfer_buffer == NULL) {
+			err (__FUNCTION__" - out of memory");
+			return -ENOMEM;
+		}
+	}
+	if (urb->transfer_buffer_length < len) {
+		kfree (urb->transfer_buffer);
+		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
+		if (urb->transfer_buffer == NULL) {
+			err (__FUNCTION__" - out of memory");
+			return -ENOMEM;
+		}
+	}
+	memcpy (urb->transfer_buffer, buf, len);
+
+	dr->bRequestType= BLUETOOTH_CONTROL_REQUEST_TYPE;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16((u16) value);
+	dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum);
+	dr->wLength = cpu_to_le16((u16) len);
+	
+	FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
+			  (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth);
+
+	/* send it down the pipe */
+	status = usb_submit_urb(urb, GFP_KERNEL);
+	if (status)
+		dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
+	
+	return status;
+}
+
+
+
+
+
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
+static int bluetooth_open (struct tty_struct *tty, struct file * filp)
+{
+	struct usb_bluetooth *bluetooth;
+	int result;
+
+	dbg(__FUNCTION__);
+
+	/* initialize the pointer incase something fails */
+	tty->driver_data = NULL;
+
+	/* get the bluetooth object associated with this tty pointer */
+	bluetooth = get_bluetooth_by_minor (minor(tty->device));
+
+	if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) {
+		return -ENODEV;
+	}
+
+	down (&bluetooth->lock);
+ 
+	++bluetooth->open_count;
+	if (bluetooth->open_count == 1) {
+		/* set up our structure making the tty driver remember our object, and us it */
+		tty->driver_data = bluetooth;
+		bluetooth->tty = tty;
+
+		/* force low_latency on so that our tty_push actually forces the data through, 
+	 	* otherwise it is scheduled, and with high data rates (like with OHCI) data
+	 	* can get lost. */
+		bluetooth->tty->low_latency = 1;
+	
+		/* Reset the packet position counters */
+		bluetooth->int_packet_pos = 0;
+		bluetooth->bulk_packet_pos = 0;
+
+#ifndef BTBUGGYHARDWARE
+		/* Start reading from the device */
+		FILL_BULK_URB (bluetooth->read_urb, bluetooth->dev, 
+			       usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
+			       bluetooth->bulk_in_buffer,
+			       bluetooth->bulk_in_buffer_size,
+			       bluetooth_read_bulk_callback, bluetooth);
+		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
+		if (result)
+			dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result);
+#endif
+		FILL_INT_URB (bluetooth->interrupt_in_urb, bluetooth->dev,
+			      usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress),
+			      bluetooth->interrupt_in_buffer,
+			      bluetooth->interrupt_in_buffer_size,
+			      bluetooth_int_callback, bluetooth,
+			      bluetooth->interrupt_in_interval);
+		result = usb_submit_urb(bluetooth->interrupt_in_urb, GFP_KERNEL);
+		if (result)
+			dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result);
+	}
+	
+	up(&bluetooth->lock);
+
+	return 0;
+}
+
+
+static void bluetooth_close (struct tty_struct *tty, struct file * filp)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	int i;
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not opened");
+		return;
+	}
+
+	down (&bluetooth->lock);
+ 
+	--bluetooth->open_count;
+	if (bluetooth->open_count <= 0) {
+		bluetooth->open_count = 0;
+
+		/* shutdown any bulk reads and writes that might be going on */
+		for (i = 0; i < NUM_BULK_URBS; ++i)
+			usb_unlink_urb (bluetooth->write_urb_pool[i]);
+		usb_unlink_urb (bluetooth->read_urb);
+		usb_unlink_urb (bluetooth->interrupt_in_urb);
+	}
+	up(&bluetooth->lock);
+}
+
+
+static int bluetooth_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	struct urb *urb = NULL;
+	unsigned char *temp_buffer = NULL;
+	const unsigned char *current_buffer;
+	const unsigned char *current_position;
+	int bytes_sent;
+	int buffer_size;
+	int i;
+	int retval = 0;
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - %d byte(s)", count);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not opened");
+		return -EINVAL;
+	}
+
+	if (count == 0) {
+		dbg(__FUNCTION__ " - write request of 0 bytes");
+		return 0;
+	}
+	if (count == 1) {
+		dbg(__FUNCTION__ " - write request only included type %d", buf[0]);
+		return 1;
+	}
+
+#ifdef DEBUG
+	printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+	for (i = 0; i < count; ++i) {
+		printk ("%.2x ", buf[i]);
+	}
+	printk ("\n");
+#endif
+
+	if (from_user) {
+		temp_buffer = kmalloc (count, GFP_KERNEL);
+		if (temp_buffer == NULL) {
+			err (__FUNCTION__ "- out of memory.");
+			retval = -ENOMEM;
+			goto exit;
+		}
+		copy_from_user (temp_buffer, buf, count);
+		current_buffer = temp_buffer;
+	} else {
+		current_buffer = buf;
+	}
+
+	switch (*current_buffer) {
+		/* First byte indicates the type of packet */
+		case CMD_PKT:
+			/* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/
+
+			retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, &current_buffer[1], count-1);
+			if (retval) {
+				goto exit;
+			}
+			retval = count;
+			break;
+
+		case ACL_PKT:
+			current_position = current_buffer;
+			++current_position;
+			--count;
+			bytes_sent = 0;
+
+			while (count > 0) {
+				urb = NULL;
+
+				/* try to find a free urb in our list */
+				for (i = 0; i < NUM_BULK_URBS; ++i) {
+					if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+						urb = bluetooth->write_urb_pool[i];
+						break;
+					}
+				}
+				if (urb == NULL) {
+					dbg (__FUNCTION__ " - no free urbs");
+					retval = bytes_sent;
+					goto exit;
+				}
+				
+
+				buffer_size = min (count, bluetooth->bulk_out_buffer_size);
+				memcpy (urb->transfer_buffer, current_position, buffer_size);
+
+				/* build up our urb */
+				FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress),
+						urb->transfer_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
+				urb->transfer_flags |= USB_QUEUE_BULK;
+
+				/* send it down the pipe */
+				retval = usb_submit_urb(urb, GFP_KERNEL);
+				if (retval) {
+					dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with error = %d", retval);
+					goto exit;
+				}
+#ifdef BTBUGGYHARDWARE
+				/* A workaround for the stalled data bug */
+				/* May or may not be needed...*/
+				if (count != 0) {
+					udelay(500);
+				}
+#endif
+				current_position += buffer_size;
+				bytes_sent += buffer_size;
+				count -= buffer_size;
+			}
+
+			retval = bytes_sent + 1;
+			break;
+		
+		default :
+			dbg(__FUNCTION__" - unsupported (at this time) write type");
+			retval = -EINVAL;
+			break;
+	}
+
+exit:
+	if (temp_buffer != NULL)
+		kfree (temp_buffer);
+
+	return retval;
+} 
+
+
+static int bluetooth_write_room (struct tty_struct *tty) 
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	int room = 0;
+	int i;
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < NUM_BULK_URBS; ++i) {
+		if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+			room += bluetooth->bulk_out_buffer_size;
+		}
+	}
+
+	dbg(__FUNCTION__ " - returns %d", room);
+	return room;
+}
+
+
+static int bluetooth_chars_in_buffer (struct tty_struct *tty) 
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	int chars = 0;
+	int i;
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < NUM_BULK_URBS; ++i) {
+		if (bluetooth->write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += bluetooth->write_urb_pool[i]->transfer_buffer_length;
+		}
+	}
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+	return chars;
+}
+
+
+static void bluetooth_throttle (struct tty_struct * tty)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+	
+	dbg(__FUNCTION__ " unsupported (at this time)");
+
+	return;
+}
+
+
+static void bluetooth_unthrottle (struct tty_struct * tty)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	dbg(__FUNCTION__ " unsupported (at this time)");
+}
+
+
+static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - cmd 0x%.4x", cmd);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return -ENODEV;
+	}
+
+	/* FIXME!!! */
+	return -ENOIOCTLCMD;
+}
+
+
+static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	/* FIXME!!! */
+
+	return;
+}
+
+
+#ifdef BTBUGGYHARDWARE
+void btusb_enable_bulk_read(struct tty_struct *tty){
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	int result;
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	if (bluetooth->read_urb) {
+		FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
+			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
+			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
+			      bluetooth_read_bulk_callback, bluetooth);
+		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
+		if (result)
+			err (__FUNCTION__ " - failed submitting read urb, error %d", result);
+	}
+}
+
+void btusb_disable_bulk_read(struct tty_struct *tty){
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->open_count) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length))
+		usb_unlink_urb(bluetooth->read_urb);
+}
+#endif
+
+
+/*****************************************************************************
+ * urb callback functions
+ *****************************************************************************/
+
+
+static void bluetooth_int_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+	unsigned char *data = urb->transfer_buffer;
+	unsigned int i;
+	unsigned int count = urb->actual_length;
+	unsigned int packet_size;
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status);
+		return;
+	}
+
+	if (!count) {
+		dbg(__FUNCTION__ " - zero length int");
+		return;
+	}
+
+
+#ifdef DEBUG
+	if (count) {
+		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+		for (i = 0; i < count; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+#ifdef BTBUGGYHARDWARE
+	if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) {
+		data += 2;
+		count -= 2;
+	}
+	if (count == 0) {
+		urb->actual_length = 0;
+		return;
+	}
+#endif
+	/* We add  a packet type identifier to the beginning of each
+	   HCI frame.  This makes the data in the tty look like a
+	   serial USB devices.  Each HCI frame can be broken across
+	   multiple URBs so we buffer them until we have a full hci
+	   packet */
+
+	if (!bluetooth->int_packet_pos) {
+		bluetooth->int_buffer[0] = EVENT_PKT;
+		bluetooth->int_packet_pos++;
+	}
+	
+	if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) {
+		err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE");
+		bluetooth->int_packet_pos = 0;
+		return;
+	}
+
+	memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos],
+		urb->transfer_buffer, count);
+	bluetooth->int_packet_pos += count;
+	urb->actual_length = 0;
+
+	if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE)
+		packet_size = bluetooth->int_buffer[2];
+	else
+		return;
+
+	if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) {
+		err(__FUNCTION__ " - packet was too long");
+		bluetooth->int_packet_pos = 0;
+		return;
+	}
+
+	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) {
+		for (i = 0; i < bluetooth->int_packet_pos; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */
+			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(bluetooth->tty);
+			}
+			tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
+		}
+		tty_flip_buffer_push(bluetooth->tty);
+
+		bluetooth->int_packet_pos = 0;
+	}
+}
+
+
+static void bluetooth_ctrl_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+}
+
+
+static void bluetooth_read_bulk_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+	unsigned char *data = urb->transfer_buffer;
+	unsigned int count = urb->actual_length;
+	unsigned int i;
+	unsigned int packet_size;
+	int result;
+
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		if (urb->status == -ENOENT) {                   
+			dbg(__FUNCTION__ " - URB canceled, won't reschedule");
+			return;
+		}
+		goto exit;
+	}
+
+	if (!count) {
+		dbg(__FUNCTION__ " - zero length read bulk");
+		goto exit;
+	}
+
+#ifdef DEBUG
+	if (count) {
+		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+		for (i = 0; i < count; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+#ifdef BTBUGGYHARDWARE
+	if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
+	    && (data[2] == 0x00) && (data[3] == 0x00)) {
+		urb->actual_length = 0;
+		FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
+			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
+			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
+			      bluetooth_read_bulk_callback, bluetooth);
+		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
+		if (result)
+			err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+
+		return;
+	}
+#endif
+	/* We add  a packet type identifier to the beginning of each
+	   HCI frame.  This makes the data in the tty look like a
+	   serial USB devices.  Each HCI frame can be broken across
+	   multiple URBs so we buffer them until we have a full hci
+	   packet */
+	
+	if (!bluetooth->bulk_packet_pos) {
+		bluetooth->bulk_buffer[0] = ACL_PKT;
+		bluetooth->bulk_packet_pos++;
+	}
+
+	if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
+		err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE");
+		bluetooth->bulk_packet_pos = 0;
+		goto exit;
+	}
+
+	memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos],
+		urb->transfer_buffer, count);
+	bluetooth->bulk_packet_pos += count;
+	urb->actual_length = 0;
+
+	if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) {
+		packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]);
+	} else {
+		goto exit;
+	}
+
+	if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
+		err(__FUNCTION__ " - packet was too long");
+		bluetooth->bulk_packet_pos = 0;
+		goto exit;
+	}
+
+	if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
+		for (i = 0; i < bluetooth->bulk_packet_pos; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(bluetooth->tty);
+			}
+			tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
+		}
+		tty_flip_buffer_push(bluetooth->tty);
+		bluetooth->bulk_packet_pos = 0;
+	}	
+
+exit:
+	if (!bluetooth || !bluetooth->open_count)
+		return;
+
+	FILL_BULK_URB(bluetooth->read_urb, bluetooth->dev, 
+		      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
+		      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
+		      bluetooth_read_bulk_callback, bluetooth);
+	result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
+	if (result)
+		err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+
+	return;
+}
+
+
+static void bluetooth_write_bulk_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	/* wake up our little function to let the tty layer know that something happened */
+	queue_task(&bluetooth->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	return;
+}
+
+
+static void bluetooth_softint(void *private)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__);
+	struct tty_struct *tty;
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	tty = bluetooth->tty;
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+		dbg(__FUNCTION__ " - write wakeup call.");
+		(tty->ldisc.write_wakeup)(tty);
+	}
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+
+static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
+			 	  const struct usb_device_id *id)
+{
+	struct usb_bluetooth *bluetooth = NULL;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_endpoint_descriptor *interrupt_in_endpoint[8];
+	struct usb_endpoint_descriptor *bulk_in_endpoint[8];
+	struct usb_endpoint_descriptor *bulk_out_endpoint[8];
+	int control_out_endpoint;
+
+	int minor;
+	int buffer_size;
+	int i;
+	int num_interrupt_in = 0;
+	int num_bulk_in = 0;
+	int num_bulk_out = 0;
+
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	control_out_endpoint = interface->bInterfaceNumber;
+
+	/* find the endpoints that we need */
+	for (i = 0; i < interface->bNumEndpoints; ++i) {
+		endpoint = &interface->endpoint[i];
+
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk in endpoint */
+			dbg("found bulk in");
+			bulk_in_endpoint[num_bulk_in] = endpoint;
+			++num_bulk_in;
+		}
+
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk out endpoint */
+			dbg("found bulk out");
+			bulk_out_endpoint[num_bulk_out] = endpoint;
+			++num_bulk_out;
+		}
+
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found a interrupt in endpoint */
+			dbg("found interrupt in");
+			interrupt_in_endpoint[num_interrupt_in] = endpoint;
+			++num_interrupt_in;
+		}
+	}
+
+	/* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */
+	if ((num_bulk_in != 1) ||
+	    (num_bulk_out != 1) ||
+	    (num_interrupt_in != 1)) {
+		dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound.");
+		return NULL;
+	}
+
+	MOD_INC_USE_COUNT;
+	info("USB Bluetooth converter detected");
+
+	for (minor = 0; minor < BLUETOOTH_TTY_MINORS && bluetooth_table[minor]; ++minor)
+		;
+	if (bluetooth_table[minor]) {
+		err("No more free Bluetooth devices");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+
+	if (!(bluetooth = kmalloc(sizeof(struct usb_bluetooth), GFP_KERNEL))) {
+		err("Out of memory");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+
+	memset(bluetooth, 0, sizeof(struct usb_bluetooth));
+
+	bluetooth->magic = USB_BLUETOOTH_MAGIC;
+	bluetooth->dev = dev;
+	bluetooth->minor = minor;
+	bluetooth->tqueue.routine = bluetooth_softint;
+	bluetooth->tqueue.data = bluetooth;
+	init_MUTEX(&bluetooth->lock);
+
+	/* record the interface number for the control out */
+	bluetooth->control_out_bInterfaceNum = control_out_endpoint;
+	
+	/* create our control out urb pool */ 
+	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+		struct urb  *urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (urb == NULL) {
+			err("No free urbs available");
+			goto probe_error;
+		}
+		urb->transfer_buffer = NULL;
+		bluetooth->control_urb_pool[i] = urb;
+	}
+
+	/* set up the endpoint information */
+	endpoint = bulk_in_endpoint[0];
+	bluetooth->read_urb = usb_alloc_urb (0, GFP_KERNEL);
+	if (!bluetooth->read_urb) {
+		err("No free urbs available");
+		goto probe_error;
+	}
+	bluetooth->bulk_in_buffer_size = buffer_size = endpoint->wMaxPacketSize;
+	bluetooth->bulk_in_endpointAddress = endpoint->bEndpointAddress;
+	bluetooth->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+	if (!bluetooth->bulk_in_buffer) {
+		err("Couldn't allocate bulk_in_buffer");
+		goto probe_error;
+	}
+	FILL_BULK_URB(bluetooth->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+		      bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth);
+
+	endpoint = bulk_out_endpoint[0];
+	bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
+	
+	/* create our write urb pool */ 
+	for (i = 0; i < NUM_BULK_URBS; ++i) {
+		struct urb  *urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (urb == NULL) {
+			err("No free urbs available");
+			goto probe_error;
+		}
+		urb->transfer_buffer = kmalloc (bluetooth->bulk_out_buffer_size, GFP_KERNEL);
+		if (urb->transfer_buffer == NULL) {
+			err("out of memory");
+			goto probe_error;
+		}
+		bluetooth->write_urb_pool[i] = urb;
+	}
+	
+	bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
+
+	endpoint = interrupt_in_endpoint[0];
+	bluetooth->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!bluetooth->interrupt_in_urb) {
+		err("No free urbs available");
+		goto probe_error;
+	}
+	bluetooth->interrupt_in_buffer_size = buffer_size = endpoint->wMaxPacketSize;
+	bluetooth->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
+	bluetooth->interrupt_in_interval = endpoint->bInterval;
+	bluetooth->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+	if (!bluetooth->interrupt_in_buffer) {
+		err("Couldn't allocate interrupt_in_buffer");
+		goto probe_error;
+	}
+	FILL_INT_URB(bluetooth->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+		     bluetooth->interrupt_in_buffer, buffer_size, bluetooth_int_callback,
+		     bluetooth, endpoint->bInterval);
+
+	/* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
+	tty_register_devfs (&bluetooth_tty_driver, 0, minor);
+	info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor);
+
+	bluetooth_table[minor] = bluetooth;
+
+	return bluetooth; /* success */
+
+probe_error:
+	if (bluetooth->read_urb)
+		usb_free_urb (bluetooth->read_urb);
+	if (bluetooth->bulk_in_buffer)
+		kfree (bluetooth->bulk_in_buffer);
+	if (bluetooth->interrupt_in_urb)
+		usb_free_urb (bluetooth->interrupt_in_urb);
+	if (bluetooth->interrupt_in_buffer)
+		kfree (bluetooth->interrupt_in_buffer);
+	for (i = 0; i < NUM_BULK_URBS; ++i)
+		if (bluetooth->write_urb_pool[i]) {
+			if (bluetooth->write_urb_pool[i]->transfer_buffer)
+				kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
+			usb_free_urb (bluetooth->write_urb_pool[i]);
+		}
+	for (i = 0; i < NUM_CONTROL_URBS; ++i) 
+		if (bluetooth->control_urb_pool[i]) {
+			if (bluetooth->control_urb_pool[i]->transfer_buffer)
+				kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
+			usb_free_urb (bluetooth->control_urb_pool[i]);
+		}
+
+	bluetooth_table[minor] = NULL;
+
+	/* free up any memory that we allocated */
+	kfree (bluetooth);
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+
+static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_bluetooth *bluetooth = (struct usb_bluetooth *) ptr;
+	int i;
+
+	if (bluetooth) {
+		if ((bluetooth->open_count) && (bluetooth->tty))
+			tty_hangup(bluetooth->tty);
+
+		bluetooth->open_count = 0;
+
+		if (bluetooth->read_urb) {
+			usb_unlink_urb (bluetooth->read_urb);
+			usb_free_urb (bluetooth->read_urb);
+		}
+		if (bluetooth->bulk_in_buffer)
+			kfree (bluetooth->bulk_in_buffer);
+
+		if (bluetooth->interrupt_in_urb) {
+			usb_unlink_urb (bluetooth->interrupt_in_urb);
+			usb_free_urb (bluetooth->interrupt_in_urb);
+		}
+		if (bluetooth->interrupt_in_buffer)
+			kfree (bluetooth->interrupt_in_buffer);
+
+		tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor);
+
+		for (i = 0; i < NUM_BULK_URBS; ++i) {
+			if (bluetooth->write_urb_pool[i]) {
+				usb_unlink_urb (bluetooth->write_urb_pool[i]);
+				if (bluetooth->write_urb_pool[i]->transfer_buffer)
+					kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
+				usb_free_urb (bluetooth->write_urb_pool[i]);
+			}
+		}
+		for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+			if (bluetooth->control_urb_pool[i]) {
+				usb_unlink_urb (bluetooth->control_urb_pool[i]);
+				if (bluetooth->control_urb_pool[i]->transfer_buffer)
+					kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
+				usb_free_urb (bluetooth->control_urb_pool[i]);
+			}
+		}
+		
+		info("Bluetooth converter now disconnected from ttyUB%d", bluetooth->minor);
+
+		bluetooth_table[bluetooth->minor] = NULL;
+
+		/* free up any memory that we allocated */
+		kfree (bluetooth);
+
+	} else {
+		info("device disconnected");
+	}
+
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct tty_driver bluetooth_tty_driver = {
+	magic:			TTY_DRIVER_MAGIC,
+	driver_name:		"usb-bluetooth",
+	name:			"usb/ttub/%d",
+	major:			BLUETOOTH_TTY_MAJOR,
+	minor_start:		0,
+	num:			BLUETOOTH_TTY_MINORS,
+	type:			TTY_DRIVER_TYPE_SERIAL,
+	subtype:		SERIAL_TYPE_NORMAL,
+	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+	refcount:		&bluetooth_refcount,
+	table:			bluetooth_tty,
+	termios:		bluetooth_termios,
+	termios_locked:		bluetooth_termios_locked,
+
+	open:			bluetooth_open,
+	close:			bluetooth_close,
+	write:			bluetooth_write,
+	write_room:		bluetooth_write_room,
+	ioctl:			bluetooth_ioctl,
+	set_termios:		bluetooth_set_termios,
+	throttle:		bluetooth_throttle,
+	unthrottle:		bluetooth_unthrottle,
+	chars_in_buffer:	bluetooth_chars_in_buffer,
+};
+
+
+int usb_bluetooth_init(void)
+{
+	int i;
+	int result;
+
+	/* Initalize our global data */
+	for (i = 0; i < BLUETOOTH_TTY_MINORS; ++i) {
+		bluetooth_table[i] = NULL;
+	}
+
+	info ("USB Bluetooth support registered");
+
+	/* register the tty driver */
+	bluetooth_tty_driver.init_termios          = tty_std_termios;
+	bluetooth_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	if (tty_register_driver (&bluetooth_tty_driver)) {
+		err(__FUNCTION__ " - failed to register tty driver");
+		return -1;
+	}
+
+	/* register the USB driver */
+	result = usb_register(&usb_bluetooth_driver);
+	if (result < 0) {
+		tty_unregister_driver(&bluetooth_tty_driver);
+		err("usb_register failed for the USB bluetooth driver. Error number %d", result);
+		return -1;
+	}
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+
+	return 0;
+}
+
+
+void usb_bluetooth_exit(void)
+{
+	usb_deregister(&usb_bluetooth_driver);
+	tty_unregister_driver(&bluetooth_tty_driver);
+}
+
+
+module_init(usb_bluetooth_init);
+module_exit(usb_bluetooth_exit);
+
+/* Module information */
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
diff -urN linux-2.5.8-pre2/drivers/usb/core/devio.c linux-2.5.8-pre3/drivers/usb/core/devio.c
--- linux-2.5.8-pre2/drivers/usb/core/devio.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/core/devio.c	Tue Apr  9 18:35:19 2002
@@ -597,33 +597,31 @@
 	if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
 		return -EINVAL;
 	len1 = bulk.len;
-	if (len1 > PAGE_SIZE)
-		return -EINVAL;
-	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+	if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
 		return -ENOMEM;
 	tmo = (bulk.timeout * HZ + 999) / 1000;
 	if (bulk.ep & 0x80) {
 		if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
-			free_page((unsigned long)tbuf);
+			kfree(tbuf);
 			return -EINVAL;
 		}
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		if (!i && len2) {
 			if (copy_to_user(bulk.data, tbuf, len2)) {
-				free_page((unsigned long)tbuf);
+				kfree(tbuf);
 				return -EFAULT;
 			}
 		}
 	} else {
 		if (len1) {
 			if (copy_from_user(tbuf, bulk.data, len1)) {
-				free_page((unsigned long)tbuf);
+				kfree(tbuf);
 				return -EFAULT;
 			}
 		}
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 	}
-	free_page((unsigned long)tbuf);
+	kfree(tbuf);
 	if (i < 0) {
 		printk(KERN_WARNING "usbfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n", 
 		       dev->devnum, bulk.ep, bulk.len, i);
@@ -1059,6 +1057,8 @@
 	int			size;
 	void			*buf = 0;
 	int			retval = 0;
+       struct usb_interface    *ifp = 0;
+       struct usb_driver       *driver = 0;
 
 	/* get input parameters and alloc buffer */
 	if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl)))
@@ -1076,33 +1076,41 @@
 		}
 	}
 
-	/* ioctl to device */
-	if (ctrl.ifno < 0) {
-		switch (ctrl.ioctl_code) {
-		/* access/release token for issuing control messages
-		 * ask a particular driver to bind/unbind, ... etc
-		 */
-		}
-		retval = -ENOSYS;
-
-	/* ioctl to the driver which has claimed a given interface */
-	} else {
-		struct usb_interface	*ifp = 0;
-		if (!ps->dev)
-			retval = -ENODEV;
-		else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces)
+       if (!ps->dev)
+               retval = -ENODEV;
+       else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+               retval = -EINVAL;
+       else switch (ctrl.ioctl_code) {
+
+       /* disconnect kernel driver from interface, leaving it unbound.  */
+       case USBDEVFS_DISCONNECT:
+               driver = ifp->driver;
+               if (driver) {
+                       down (&driver->serialize);
+                       dbg ("disconnect '%s' from dev %d interface %d",
+                               driver->name, ps->dev->devnum, ctrl.ifno);
+                       driver->disconnect (ps->dev, ifp->private_data);
+                       usb_driver_release_interface (driver, ifp);
+                       up (&driver->serialize);
+               } else
 			retval = -EINVAL;
+               break;
+
+       /* let kernel drivers try to (re)bind to the interface */
+       case USBDEVFS_CONNECT:
+               usb_find_interface_driver_for_ifnum (ps->dev, ctrl.ifno);
+               break;
+
+       /* talk directly to the interface's driver */
+       default:
+               driver = ifp->driver;
+               if (driver == 0 || driver->ioctl == 0)
+                       retval = -ENOSYS;
 		else {
-			if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
-				retval = -EINVAL;
-			else if (ifp->driver == 0 || ifp->driver->ioctl == 0)
-				retval = -ENOSYS;
-		}
-		if (retval == 0) {
 			if (ifp->driver->owner)
 				__MOD_INC_USE_COUNT(ifp->driver->owner);
 			/* ifno might usefully be passed ... */
-			retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
+                       retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
 			/* size = min_t(int, size, retval)? */
 			if (ifp->driver->owner)
 				__MOD_DEC_USE_COUNT(ifp->driver->owner);
diff -urN linux-2.5.8-pre2/drivers/usb/core/hcd.h linux-2.5.8-pre3/drivers/usb/core/hcd.h
--- linux-2.5.8-pre2/drivers/usb/core/hcd.h	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/core/hcd.h	Tue Apr  9 18:35:19 2002
@@ -181,6 +181,24 @@
 
 #endif /* CONFIG_PCI */
 
+/* -------------------------------------------------------------------------- */
+
+/* Enumeration is only for the hub driver, or HCD virtual root hubs */
+extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
+	struct usb_bus *);
+extern void usb_free_dev(struct usb_device *);
+extern int usb_new_device(struct usb_device *dev);
+extern void usb_connect(struct usb_device *dev);
+extern void usb_disconnect(struct usb_device **);
+
+#ifndef _LINUX_HUB_H
+/* exported to hub driver ONLY to support usb_reset_device () */
+extern int usb_get_configuration(struct usb_device *dev);
+extern void usb_set_maxpacket(struct usb_device *dev);
+extern void usb_destroy_configuration(struct usb_device *dev);
+extern int usb_set_address(struct usb_device *dev);
+#endif /* _LINUX_HUB_H */
+
 /*-------------------------------------------------------------------------*/
 
 /*
diff -urN linux-2.5.8-pre2/drivers/usb/core/hub.c linux-2.5.8-pre3/drivers/usb/core/hub.c
--- linux-2.5.8-pre2/drivers/usb/core/hub.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/core/hub.c	Tue Apr  9 18:35:19 2002
@@ -29,6 +29,7 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
+#include "hcd.h"
 #include "hub.h"
 
 /* Wakes up khubd */
diff -urN linux-2.5.8-pre2/drivers/usb/core/usb.c linux-2.5.8-pre3/drivers/usb/core/usb.c
--- linux-2.5.8-pre2/drivers/usb/core/usb.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/core/usb.c	Tue Apr  9 18:35:19 2002
@@ -197,6 +197,28 @@
 }
 
 /**
+ * usb_ifnum_to_ifpos - convert the interface number to the interface position
+ * @dev: the device to use
+ * @ifnum: the interface number (bInterfaceNumber); not interface position
+ *
+ * This is used to convert the interface _number_ (as in
+ * interface.bInterfaceNumber) to the interface _position_ (as in
+ * dev->actconfig->interface + position).  Note that the number is the same as
+ * the position for all interfaces _except_ devices with interfaces not
+ * sequentially numbered (e.g., 0, 2, 3, etc).
+ */
+int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum)
+{
+	int i;
+
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+		if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
+			return i;
+
+	return -EINVAL;
+}
+
+/**
  * usb_ifnum_to_if - get the interface object with a given interface number
  * @dev: the device whose current configuration is considered
  * @ifnum: the desired interface
@@ -570,6 +592,24 @@
 	return -1;
 }
 
+/**
+ * usb_find_interface_driver_for_ifnum - finds a usb interface driver for the specified ifnum
+ * @dev: the device to use
+ * @ifnum: the interface number (bInterfaceNumber); not interface position!
+ *
+ * This converts a ifnum to ifpos via a call to usb_ifnum_to_ifpos and then
+ * calls usb_find_interface_driver() with the found ifpos.  Note
+ * usb_find_interface_driver's ifnum parameter is actually interface position.
+ */
+int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned ifnum)
+{
+	int ifpos = usb_ifnum_to_ifpos(dev, ifnum);
+
+	if (0 > ifpos)
+		return -EINVAL;
+
+	return usb_find_interface_driver(dev, ifpos);
+}
 
 #ifdef	CONFIG_HOTPLUG
 
@@ -789,50 +829,32 @@
 	return dev;
 }
 
-// usbcore-internal ...
-// but usb_dec_dev_use() is #defined to this, and that's public!!
-// FIXME the public call should BUG() whenever count goes to zero,
-// the usbcore-internal one should do so _unless_ it does so...
+/**
+ * usb_free_dev - free a usb device structure (usbcore-internal)
+ * @dev: device that's been disconnected
+ * Context: !in_interrupt ()
+ *
+ * Used by hub and virtual root hub drivers.  The device is completely
+ * gone, everything is cleaned up, so it's time to get rid of these last
+ * records of this device.
+ */
 void usb_free_dev(struct usb_device *dev)
 {
-	if (atomic_dec_and_test(&dev->refcnt)) {
-		/* Normally only goes to zero in usb_disconnect(), from
-		 * khubd or from roothub shutdown (rmmod/apmd/... thread).
-		 * Abnormally, roothub init errors can happen, so HCDs
-		 * call this directly.
-		 *
-		 * Otherwise this is a nasty device driver bug, often in
-		 * disconnect processing.
+	if (in_interrupt ())
+		BUG ();
+	if (!atomic_dec_and_test (&dev->refcnt)) {
+		/* MUST go to zero here, else someone's hanging on to
+		 * a device that's supposed to have been cleaned up!!
 		 */
-		if (in_interrupt ())
-			BUG ();
-
-		dev->bus->op->deallocate(dev);
-		usb_destroy_configuration(dev);
-
-		usb_bus_put(dev->bus);
-
-		kfree(dev);
+		BUG ();
 	}
-}
 
-/**
- * usb_inc_dev_use - record another reference to a device
- * @dev: the device being referenced
- *
- * Each live reference to a device should be refcounted.
- *
- * Device drivers should normally record such references in their
- * open() methods.
- * Drivers should then release them, using usb_dec_dev_use(), in their
- * close() methods.
- */
-void usb_inc_dev_use(struct usb_device *dev)
-{
-	atomic_inc(&dev->refcnt);
+	dev->bus->op->deallocate (dev);
+	usb_destroy_configuration (dev);
+	usb_bus_put (dev->bus);
+	kfree (dev);
 }
 
-
 /**
  * usb_alloc_urb - creates a new urb for a USB driver to use
  * @iso_packets: number of iso packets for this urb
@@ -2636,6 +2658,7 @@
  * into the kernel, and other device drivers are built as modules,
  * then these symbols need to be exported for the modules to use.
  */
+EXPORT_SYMBOL(usb_ifnum_to_ifpos);
 EXPORT_SYMBOL(usb_ifnum_to_if);
 EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
@@ -2647,6 +2670,7 @@
 EXPORT_SYMBOL(usb_free_dev);
 EXPORT_SYMBOL(usb_inc_dev_use);
 
+EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
 EXPORT_SYMBOL(usb_driver_claim_interface);
 EXPORT_SYMBOL(usb_interface_claimed);
 EXPORT_SYMBOL(usb_driver_release_interface);
diff -urN linux-2.5.8-pre2/drivers/usb/host/uhci.c linux-2.5.8-pre3/drivers/usb/host/uhci.c
--- linux-2.5.8-pre2/drivers/usb/host/uhci.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/host/uhci.c	Tue Apr  9 18:35:20 2002
@@ -749,7 +749,7 @@
 
 	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
 		urbp->fsbr = 1;
-		if (!uhci->fsbr++)
+		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
 			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
 	}
 
@@ -1631,8 +1631,7 @@
 
 	if (urb->status != -EINPROGRESS) {
 		info("uhci_transfer_result: called for URB %p not in flight?", urb);
-		spin_unlock_irqrestore(&urb->lock, flags);
-		return;
+		goto out;
 	}
 
 	switch (usb_pipetype(urb->pipe)) {
@@ -1652,10 +1651,8 @@
 
 	urbp->status = ret;
 
-	if (ret == -EINPROGRESS) {
-		spin_unlock_irqrestore(&urb->lock, flags);
-		return;
-	}
+	if (ret == -EINPROGRESS)
+		goto out;
 
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
@@ -1669,11 +1666,8 @@
 		break;
 	case PIPE_INTERRUPT:
 		/* Interrupts are an exception */
-		if (urb->interval) {
-			uhci_add_complete(urb);
-			spin_unlock_irqrestore(&urb->lock, flags);
-			return;		/* <-- note return */
-		}
+		if (urb->interval)
+			goto out_complete;
 
 		/* Release bandwidth for Interrupt or Isoc. transfers */
 		/* Spinlock needed ? */
@@ -1689,8 +1683,10 @@
 	/* Remove it from uhci->urb_list */
 	list_del_init(&urb->urb_list);
 
+out_complete:
 	uhci_add_complete(urb);
 
+out:
 	spin_unlock_irqrestore(&urb->lock, flags);
 }
 
@@ -1820,6 +1816,9 @@
 		} else {
 			urb->status = -ENOENT;
 
+			spin_unlock(&urb->lock);
+			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
 			if (in_interrupt()) {	/* wait at least 1 frame */
 				static int errorcount = 10;
 
@@ -1829,9 +1828,6 @@
 			} else
 				schedule_timeout(1+1*HZ/1000); 
 
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
 			uhci_call_completion(urb);
 		}
 	}
@@ -1846,10 +1842,6 @@
 
 	uhci_dec_fsbr(uhci, urb);
 
-	/* There is a race with updating IOC in here, but it's not worth */
-	/*  trying to fix since this is merely an optimization. The only */
-	/*  time we'd lose is if the status of the packet got updated */
-	/*  and we'd be turning on FSBR next frame anyway, so it's a wash */
 	urbp->fsbr_timeout = 1;
 
 	head = &urbp->td_list;
@@ -2013,23 +2005,23 @@
 	tmp = head->next;
 	while (tmp != head) {
 		struct urb *u = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *urbp = (struct urb_priv *)u->hcpriv;
+		struct urb_priv *up = (struct urb_priv *)u->hcpriv;
 
 		tmp = tmp->next;
 
-		spin_lock(&urb->lock);
+		spin_lock(&u->lock);
 
 		/* Check if the FSBR timed out */
-		if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT))
+		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
 			uhci_fsbr_timeout(uhci, u);
 
 		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
+		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
 			list_del(&u->urb_list);
 			list_add_tail(&u->urb_list, &list);
 		}
 
-		spin_unlock(&urb->lock);
+		spin_unlock(&u->lock);
 	}
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
@@ -2202,12 +2194,12 @@
 			OK(0);
 		case RH_PORT_RESET:
 			SET_RH_PORTSTAT(USBPORTSC_PR);
-			wait_ms(50);	/* USB v1.1 7.1.7.3 */
+			mdelay(50);	/* USB v1.1 7.1.7.3 */
 			uhci->rh.c_p_r[wIndex - 1] = 1;
 			CLR_RH_PORTSTAT(USBPORTSC_PR);
 			udelay(10);
 			SET_RH_PORTSTAT(USBPORTSC_PE);
-			wait_ms(10);
+			mdelay(10);
 			SET_RH_PORTSTAT(0xa);
 			OK(0);
 		case RH_PORT_POWER:
@@ -2724,6 +2716,7 @@
 	}
 
 	uhci->dev = dev;
+	uhci->irq = dev->irq;
 	uhci->io_addr = io_addr;
 	uhci->io_size = io_size;
 	pci_set_drvdata(dev, uhci);
@@ -2750,6 +2743,11 @@
 	/*  or broken setup */
 	reset_hc(uhci);
 
+	uhci->fsbr = 0;
+	uhci->fsbrtimeout = 0;
+
+	uhci->is_suspended = 0;
+
 	spin_lock_init(&uhci->qh_remove_list_lock);
 	INIT_LIST_HEAD(&uhci->qh_remove_list);
 
@@ -2932,8 +2930,6 @@
 	if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
 		goto err_request_irq;
 
-	uhci->irq = dev->irq;
-
 	/* disable legacy emulation */
 	pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT);
 
diff -urN linux-2.5.8-pre2/drivers/usb/host/uhci.h linux-2.5.8-pre3/drivers/usb/host/uhci.h
--- linux-2.5.8-pre2/drivers/usb/host/uhci.h	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/host/uhci.h	Tue Apr  9 18:35:20 2002
@@ -287,17 +287,17 @@
 struct uhci {
 	struct pci_dev *dev;
 
+#ifdef CONFIG_PROC_FS
 	/* procfs */
 	int num;
 	struct proc_dir_entry *proc_entry;
+#endif
 
 	/* Grabbed from PCI */
 	int irq;
 	unsigned int io_addr;
 	unsigned int io_size;
 
-	struct list_head uhci_list;
-
 	struct pci_pool *qh_pool;
 	struct pci_pool *td_pool;
 
diff -urN linux-2.5.8-pre2/drivers/usb/host/usb-uhci.h linux-2.5.8-pre3/drivers/usb/host/usb-uhci.h
--- linux-2.5.8-pre2/drivers/usb/host/usb-uhci.h	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/host/usb-uhci.h	Tue Apr  9 18:35:20 2002
@@ -11,7 +11,7 @@
 {
 	if(!in_interrupt())
 	{
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1 + ms * HZ / 1000);
 	}
 	else
diff -urN linux-2.5.8-pre2/drivers/usb/image/Config.help linux-2.5.8-pre3/drivers/usb/image/Config.help
--- linux-2.5.8-pre2/drivers/usb/image/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/usb/image/Config.help	Tue Apr  9 18:35:20 2002
@@ -0,0 +1,47 @@
+CONFIG_USB_DC2XX
+  Say Y here if you want to connect this type of still camera to your
+  computer's USB port.  See <file:Documentation/usb/dc2xx.txt> for
+  more information; some non-Kodak cameras may also work with this
+  driver, given application support (such as <http://www.gphoto.org/>).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dc2xx.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_MDC800
+  Say Y here if you want to connect this type of still camera to
+  your computer's USB port. This driver can be used with gphoto 0.4.3
+  and higher (look at <http://www.gphoto.org/>).
+  To use it create a device node with "mknod /dev/mustek c 180 32" and
+  configure it in your software.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mdc800.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_HPUSBSCSI
+  Say Y here if you want support for the HP 53xx series of scanners
+  and the Minolta Scan Dual. This driver is experimental.
+  The scanner will be accessible as a SCSI device.
+  This can be compiled as a module, called hpusbscsi.o.
+
+CONFIG_USB_MICROTEK
+  Say Y here if you want support for the Microtek X6USB and
+  possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L.
+  Support for anything but the X6 is experimental.
+  Please report failures and successes.
+  The scanner will appear as a scsi generic device to the rest
+  of the system. Scsi support is required.
+  This driver can be compiled as a module, called microtek.o.
+
+CONFIG_USB_SCANNER
+  Say Y here if you want to connect a USB scanner to your computer's
+  USB port. Please read <file:Documentation/usb/scanner.txt> and
+  <file:Documentation/usb/scanner-hp-sane.txt> for more information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called scanner.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
diff -urN linux-2.5.8-pre2/drivers/usb/input/Config.help linux-2.5.8-pre3/drivers/usb/input/Config.help
--- linux-2.5.8-pre2/drivers/usb/input/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/usb/input/Config.help	Tue Apr  9 18:35:20 2002
@@ -0,0 +1,74 @@
+CONFIG_USB_HID
+  Say Y here if you want full HID support to connect keyboards,
+  mice, joysticks, graphic tablets, or any other HID based devices
+  to your computer via USB. You also need to select HID Input layer
+  support (below) if you want to use keyboards, mice, joysticks and
+  the like.
+
+  You can't use this driver and the HIDBP (Boot Protocol) keyboard
+  and mouse drivers at the same time. More information is available:
+  <file:Documentation/input/input.txt>.
+
+  If unsure, say Y.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called hid.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_HIDINPUT
+  Say Y here if you want to use a USB keyboard, mouse or joystick,
+  or any other HID input device. You also need Input layer support, 
+  (CONFIG_INPUT) which you select under "Input core support".
+
+  If unsure, say Y.
+
+CONFIG_USB_HIDDEV
+  Say Y here if you want to support HID devices (from the USB
+  specification standpoint) that aren't strictly user interface
+  devices, like monitor controls and Uninterruptable Power Supplies.
+
+  This module supports these devices separately using a separate
+  event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
+  This driver requires CONFIG_USB_HID.
+
+  If unsure, say Y.
+
+CONFIG_USB_KBD
+  Say Y here only if you are absolutely sure that you don't want
+  to use the generic HID driver for your USB keyboard and prefer
+  to use the keyboard in its limited Boot Protocol mode instead.
+
+  This is almost certainly not what you want.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbkbd.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If even remotely unsure, say N.
+
+CONFIG_USB_MOUSE
+  Say Y here only if you are absolutely sure that you don't want
+  to use the generic HID driver for your USB keyboard and prefer
+  to use the keyboard in its limited Boot Protocol mode instead.
+
+  This is almost certainly not what you want.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbmouse.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+  If even remotely unsure, say N.
+
+CONFIG_USB_WACOM
+  Say Y here if you want to use the USB version of the Wacom Intuos
+  or Graphire tablet.  Make sure to say Y to "Mouse support"
+  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+  (CONFIG_INPUT_EVDEV) as well.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called wacom.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -urN linux-2.5.8-pre2/drivers/usb/media/Config.help linux-2.5.8-pre3/drivers/usb/media/Config.help
--- linux-2.5.8-pre2/drivers/usb/media/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/usb/media/Config.help	Tue Apr  9 18:35:20 2002
@@ -0,0 +1,148 @@
+CONFIG_USB_DABUSB
+  A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
+  brought to you by the DAB-Team (<http://dab.in.tum.de/>).  This
+  driver can be taken as an example for URB-based bulk, control, and
+  isochronous transactions. URB's are explained in
+  <file:Documentation/usb/URB.txt>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dabusb.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_DSBR
+  Say Y here if you want to connect this type of radio to your
+  computer's USB port. Note that the audio is not digital, and
+  you must connect the line out connector to a sound card or a
+  set of speakers.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dsbr100.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_IBMCAM
+  Say Y here if you want to connect a IBM "C-It" camera, also known as
+  "Xirlink PC Camera" to your computer's USB port.  For more
+  information, read <file:Documentation/usb/ibmcam.txt>.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ibmcam.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>. This
+  camera has several configuration options which can be specified when
+  you load the module.  Read <file:Documentation/usb/ibmcam.txt> to
+  learn more.
+
+CONFIG_USB_KONICAWC
+  Say Y here if you want support for webcams based on a Konica
+  chipset. This is known to work with the Intel YC76 webcam.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called konicawc.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_OV511
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. See <file:Documentation/usb/ov511.txt> for more
+  information and for a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Character Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ov511.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_PWC
+  Say Y or M here if you want to use one of these Philips USB webcams:
+  PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or
+  the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported
+  by this driver and never will be.
+
+  This driver has an optional plugin, which is distributed as a binary
+  module only.  It contains code that allow you to use higher
+  resolutions and framerates but may not be distributed as source.
+  But even without this plugin you can these cams for most
+  applications.
+
+  See <file:Documentation/usb/philips.txt> for more information and
+  installation instructions.
+
+  The built-in microphone is enabled by selecting USB Audio support.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Character Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pwc.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_SE401
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. See <file:Documentation/usb/se401.txt> for more
+  information and for a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called se401.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_STV680
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. This includes the Pencam line of cameras.
+  See <file:Documentation/usb/stv680.txt> for more information and for
+  a list of supported cameras.
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called stv680.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_VICAM
+  Say Y here if you have 3com homeconnect camera (vicam).
+
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called vicam.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -urN linux-2.5.8-pre2/drivers/usb/misc/Config.help linux-2.5.8-pre3/drivers/usb/misc/Config.help
--- linux-2.5.8-pre2/drivers/usb/misc/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/usb/misc/Config.help	Tue Apr  9 18:35:20 2002
@@ -0,0 +1,76 @@
+CONFIG_USB_AUERSWALD
+  Say Y here if you want to connect an Auerswald USB ISDN Device
+  to your computer's USB port.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called auerswald.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_EMI26
+  This driver loads firmware to Emagic EMI 2|6 low latency USB
+  Audio interface.
+
+  After firmware load the device is handled with standard linux
+  USB Audio driver.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called audio.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_RIO500
+  Say Y here if you want to connect a USB Rio500 mp3 player to your
+  computer's USB port. Please read <file:Documentation/usb/rio.txt>
+  for more information.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called rio500.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_TIGL
+  If you own a Texas Instruments graphing calculator and use a 
+  TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
+  interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tiglusb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+  If you don't know what the SilverLink cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
+
+CONFIG_USB_USS720
+  This driver is for USB parallel port adapters that use the Lucent
+  Technologies USS-720 chip. These cables are plugged into your USB
+  port and provide USB compatibility to peripherals designed with
+  parallel port interfaces.
+
+  The chip has two modes: automatic mode and manual mode. In automatic
+  mode, it looks to the computer like a standard USB printer. Only
+  printers may be connected to the USS-720 in this mode. The generic
+  USB printer driver ("USB Printer support", above) may be used in
+  that mode, and you can say N here if you want to use the chip only
+  in this mode.
+
+  Manual mode is not limited to printers, any parallel port
+  device should work. This driver utilizes manual mode.
+  Note however that some operations are three orders of magnitude
+  slower than on a PCI/ISA Parallel Port, so timing critical
+  applications might not work.
+
+  Say Y here if you own an USS-720 USB->Parport cable and intend to
+  connect anything other than a printer to it.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called uss720.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -urN linux-2.5.8-pre2/drivers/usb/net/Config.help linux-2.5.8-pre3/drivers/usb/net/Config.help
--- linux-2.5.8-pre2/drivers/usb/net/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/drivers/usb/net/Config.help	Tue Apr  9 18:35:20 2002
@@ -0,0 +1,118 @@
+CONFIG_USB_CATC
+  Say Y if you want to use one of the following 10Mbps USB Ethernet
+  device based on the EL1210A chip. Supported devices are:
+    Belkin F5U011
+    Belkin F5U111
+    CATC NetMate
+    CATC NetMate II
+    smartBridges smartNIC
+
+  This driver makes the adapter appear as a normal Ethernet interface,
+  typically on eth0, if it is the only ethernet device, or perhaps on
+  eth1, if you have a PCI or ISA ethernet card installed.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called catc.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_CDCETHER
+  This driver supports devices conforming to the Communication Device
+  Class Ethernet Control Model.  This is used in some cable modems.
+  For more details on the specification, get the Communication Device
+  Class specification from <http://www.usb.org/>.
+
+  This driver should work with the following devices:
+        * Ericsson PipeRider (all variants)
+        * Motorola (DM100 and SB4100)
+        * Broadcom Cable Modem (reference design)
+        * Toshiba PCX1100U and possibly other cable modems
+
+  The device creates a network device (ethX, where X depends on what
+  other networking devices you have in use), as for a normal PCI
+  or ISA based ethernet network card.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cdc-ether.o.  If you want to compile it 
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_KAWETH
+  Say Y here if you want to use one of the following 10Mbps only
+  USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
+       3Com 3C19250
+       ADS USB-10BT
+       ATEN USB Ethernet
+       ASANTE USB To Ethernet Adapter
+       AOX Endpoints USB Ethernet
+       Correga K.K.
+       D-Link DSB-650C and DU-E10
+       Entrega / Portgear E45
+       I-O DATA USB-ET/T
+       Jaton USB Ethernet Device Adapter
+       Kingston Technology USB Ethernet Adapter
+       Linksys USB10T
+       Mobility USB-Ethernet Adapter
+       NetGear EA-101
+       Peracom Enet and Enet2
+       Portsmith Express Ethernet Adapter
+       Shark Pocket Adapter
+       SMC 2202USB
+       Sony Vaio port extender
+
+  This driver is likely to work with most 10Mbps only USB Ethernet
+  adapters, including some "no brand" devices. It does NOT work on
+  SmartBridges smartNIC or on Belkin F5U111 devices - you should use
+  the CATC NetMate driver for those. If you are not sure which one
+  you need, select both, and the correct one should be selected for
+  you.
+
+  This driver makes the adapter appear as a normal Ethernet interface,
+  typically on eth0, if it is the only ethernet device, or perhaps on
+  eth1, if you have a PCI or ISA ethernet card installed.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kaweth.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_PEGASUS
+  Say Y here if you know you have Pegasus or Pegasus-II based adapter.
+  If in doubt then look at linux/drivers/usb/pegasus.h for the complete
+  list of supported devices.
+  If your particular adapter is not in the list and you are _sure_ it
+  is Pegasus or Pegasus II based then send me (petkan@users.sourceforge.net)
+  vendor and device IDs.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pegasus.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_RTL8150
+  Say Y here if you have RTL8150 based usb-ethernet adapter.
+  Send me (petkan@users.sourceforge.net) any comments you may have.
+  You can also check for updates at http://pegasus2.sourceforge.net/
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called rtl8150.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_USB_USBNET
+  This driver supports network links over USB with USB "Network"
+  or "data transfer" cables, often used to network laptops to PCs.
+  Such cables have chips from suppliers such as Belkin/eTEK, GeneSys
+  (GeneLink), NetChip and Prolific. Intelligent USB devices could also
+  use this approach to provide Internet access, using standard USB
+  cabling. You can find these chips also on some motherboards with
+  USB PC2PC support.
+
+  These links will have names like "usb0", "usb1", etc.  They act
+  like two-node Ethernets, so you can use 802.1d Ethernet Bridging
+  (CONFIG_BRIDGE) to simplify your network routing.
+
+  This code is also available as a kernel module (code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbnet.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
diff -urN linux-2.5.8-pre2/drivers/usb/net/usbnet.c linux-2.5.8-pre3/drivers/usb/net/usbnet.c
--- linux-2.5.8-pre2/drivers/usb/net/usbnet.c	Tue Apr  9 18:35:01 2002
+++ linux-2.5.8-pre3/drivers/usb/net/usbnet.c	Tue Apr  9 18:35:20 2002
@@ -1,6 +1,6 @@
 /*
  * USB Host-to-Host Links
- * Copyright (C) 2000-2001 by David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2000-2002 by David Brownell <dbrownell@users.sourceforge.net>
  */
 
 /*
@@ -62,6 +62,7 @@
  * 18-dec-2000	(db) tx watchdog, "net1080" renaming to "usbnet", device_info
  *		and prolific support, isolate net1080-specific bits, cleanup.
  *		fix unlink_urbs oops in D3 PM resume code path.
+ *
  * 02-feb-2001	(db) fix tx skb sharing, packet length, match_flags, ...
  * 08-feb-2001	stubbed in "linuxdev", maybe the SA-1100 folk can use it;
  *		AnchorChips 2720 support (from spec) for testing;
@@ -83,6 +84,11 @@
  *		tie mostly to (sub)driver info.  Workaround some PL-2302
  *		chips that seem to reject SET_INTERFACE requests.
  *
+ * 06-apr-2002	Added ethtool support, based on a patch from Brad Hards.
+ *		Level of diagnostics is more configurable; they use device
+ *		location (usb_device->devpath) instead of address (2.5).
+ *		For tx_fixup, memflags can't be NOIO.
+ *
  *-------------------------------------------------------------------------*/
 
 #include <linux/config.h>
@@ -93,6 +99,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/random.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
 // #define	DEBUG			// error path messages, extra info
@@ -113,6 +121,8 @@
 #define	CONFIG_USB_PL2301
 
 
+#define DRIVER_VERSION		"06-Apr-2002"
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -164,6 +174,7 @@
 	// protocol/interface state
 	struct net_device	net;
 	struct net_device_stats	stats;
+	int			msg_level;
 
 #ifdef CONFIG_USB_NET1080
 	u16			packet_id;
@@ -224,6 +235,13 @@
 	size_t			length;
 };
 
+static const char driver_name [] = "usbnet";
+
+/* use ethtool to change the level for any given device */
+static int msg_level = 1;
+MODULE_PARM (msg_level, "i");
+MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)");
+
 
 #define	mutex_lock(x)	down(x)
 #define	mutex_unlock(x)	up(x)
@@ -241,7 +259,9 @@
 #endif
 
 #define devinfo(usbnet, fmt, arg...) \
-	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
+	do { if ((usbnet)->msg_level >= 1) \
+	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \
+	} while (0)
 
 
 #ifdef	CONFIG_USB_AN2720
@@ -948,10 +968,11 @@
 			MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) );
 	dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL_MS);
 
-	devdbg (dev, "port %c, peer %sconnected",
-		(status & STATUS_PORT_A) ? 'A' : 'B',
-		(status & STATUS_CONN_OTHER) ? "" : "dis"
-		);
+	if (dev->msg_level >= 2)
+		devinfo (dev, "port %c, peer %sconnected",
+			(status & STATUS_PORT_A) ? 'A' : 'B',
+			(status & STATUS_CONN_OTHER) ? "" : "dis"
+			);
 	retval = 0;
 
 done:
@@ -1441,10 +1462,11 @@
 	mutex_lock (&dev->mutex);
 	netif_stop_queue (net);
 
-	devdbg (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
-		dev->stats.rx_packets, dev->stats.tx_packets, 
-		dev->stats.rx_errors, dev->stats.tx_errors
-		);
+	if (dev->msg_level >= 2)
+		devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
+			dev->stats.rx_packets, dev->stats.tx_packets, 
+			dev->stats.rx_errors, dev->stats.tx_errors
+			);
 
 	// ensure there are no more active urbs
 	add_wait_queue (&unlink_wakeup, &wait);
@@ -1482,9 +1504,10 @@
 
 	// put into "known safe" state
 	if (info->reset && (retval = info->reset (dev)) < 0) {
-		devinfo (dev, "open reset fail (%d) usbnet %03d/%03d, %s",
+		devinfo (dev, "open reset fail (%d) usbnet bus%d%s, %s",
 			retval,
-			dev->udev->bus->busnum, dev->udev->devnum,
+			// FIXME busnum is unstable
+			dev->udev->bus->busnum, dev->udev->devpath,
 			info->description);
 		goto done;
 	}
@@ -1496,14 +1519,16 @@
 	}
 
 	netif_start_queue (net);
-	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing",
-		RX_QLEN, TX_QLEN, dev->net.mtu,
-		(info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL))
-		    ? ((info->flags & FLAG_FRAMING_NC)
-			? "NetChip"
-			: "GeneSys")
-		    : "raw"
-		);
+	if (dev->msg_level >= 2)
+		devinfo (dev, "open: enable queueing "
+				"(rx %d, tx %d) mtu %d %s framing",
+			RX_QLEN, TX_QLEN, dev->net.mtu,
+			(info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL))
+			    ? ((info->flags & FLAG_FRAMING_NC)
+				? "NetChip"
+				: "GeneSys")
+			    : "raw"
+			);
 
 	// delay posting reads until we're fully open
 	tasklet_schedule (&dev->bh);
@@ -1514,6 +1539,80 @@
 
 /*-------------------------------------------------------------------------*/
 
+static int usbnet_ethtool_ioctl (struct net_device *net, void *useraddr)
+{
+	struct usbnet	*dev = (struct usbnet *) net->priv;
+	u32		cmd;
+
+	if (get_user (cmd, (u32 *)useraddr))
+		return -EFAULT;
+	switch (cmd) {
+
+	case ETHTOOL_GDRVINFO: {	/* get driver info */
+		struct ethtool_drvinfo		info;
+
+		memset (&info, 0, sizeof info);
+		info.cmd = ETHTOOL_GDRVINFO;
+		strncpy (info.driver, driver_name, sizeof info.driver);
+		strncpy (info.version, DRIVER_VERSION, sizeof info.version);
+		strncpy (info.fw_version, dev->driver_info->description,
+			sizeof info.fw_version);
+		snprintf (info.bus_info, sizeof info.bus_info, "USB bus%d%s",
+			/* FIXME busnums are bogus/unstable IDs */
+			dev->udev->bus->busnum, dev->udev->devpath);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+		}
+
+	case ETHTOOL_GLINK: 		/* get link status */
+		if (dev->driver_info->check_connect) {
+			struct ethtool_value	edata = { ETHTOOL_GLINK };
+
+			edata.data = dev->driver_info->check_connect (dev);
+			if (copy_to_user (useraddr, &edata, sizeof (edata)))
+				return -EFAULT;
+			return 0;
+		}
+		break;
+
+	case ETHTOOL_GMSGLVL: {		/* get message-level */
+		struct ethtool_value	edata = {ETHTOOL_GMSGLVL};
+
+		edata.data = dev->msg_level;
+		if (copy_to_user (useraddr, &edata, sizeof (edata)))
+			return -EFAULT;
+		return 0;
+		}
+
+	case ETHTOOL_SMSGLVL: {		/* set message-level */
+		struct ethtool_value	edata;
+
+		if (copy_from_user (&edata, useraddr, sizeof (edata)))
+			return -EFAULT;
+		dev->msg_level = edata.data;
+		return 0;
+		}
+	
+	/* could also map RINGPARAM to RX/TX QLEN */
+
+	}
+        /* Note that the ethtool user space code requires EOPNOTSUPP */
+	return -EOPNOTSUPP;
+}
+
+static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return usbnet_ethtool_ioctl (net, (void *)rq->ifr_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
 /* usb_clear_halt cannot be called in interrupt context */
 
 static void
@@ -1576,12 +1675,10 @@
 	struct nc_trailer	*trailer = 0;
 #endif	/* CONFIG_USB_NET1080 */
 
-	flags = in_interrupt () ? GFP_ATOMIC : GFP_NOIO; /* might be used for nfs */
-
 	// some devices want funky USB-level framing, for
 	// win32 driver (usually) and/or hardware quirks
 	if (info->tx_fixup) {
-		skb = info->tx_fixup (dev, skb, flags);
+		skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
 		if (!skb) {
 			dbg ("can't tx_fixup skb");
 			goto drop;
@@ -1750,8 +1847,9 @@
 {
 	struct usbnet	*dev = (struct usbnet *) ptr;
 
-	devinfo (dev, "unregister usbnet %03d/%03d, %s",
-		udev->bus->busnum, udev->devnum,
+	devinfo (dev, "unregister usbnet bus%d%s, %s",
+		// FIXME busnum is unstable
+		udev->bus->busnum, udev->devpath,
 		dev->driver_info->description);
 	
 	unregister_netdev (&dev->net);
@@ -1811,6 +1909,7 @@
 	usb_inc_dev_use (udev);
 	dev->udev = udev;
 	dev->driver_info = info;
+	dev->msg_level = msg_level;
 	INIT_LIST_HEAD (&dev->dev_list);
 	skb_queue_head_init (&dev->rxq);
 	skb_queue_head_init (&dev->txq);
@@ -1836,10 +1935,12 @@
 	net->stop = usbnet_stop;
 	net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
 	net->tx_timeout = usbnet_tx_timeout;
+	net->do_ioctl = usbnet_ioctl;
 
 	register_netdev (&dev->net);
-	devinfo (dev, "register usbnet %03d/%03d, %s",
-		udev->bus->busnum, udev->devnum,
+	devinfo (dev, "register usbnet bus%d%s, %s",
+		// FIXME busnum is unstable
+		udev->bus->busnum, udev->devpath,
 		dev->driver_info->description);
 
 	// ok, it's ready to go.
@@ -1936,7 +2037,7 @@
 MODULE_DEVICE_TABLE (usb, products);
 
 static struct usb_driver usbnet_driver = {
-	name:		"usbnet",
+	name:		driver_name,
 	id_table:	products,
 	probe:		usbnet_probe,
 	disconnect:	usbnet_disconnect,
diff -urN linux-2.5.8-pre2/fs/affs/super.c linux-2.5.8-pre3/fs/affs/super.c
--- linux-2.5.8-pre2/fs/affs/super.c	Tue Apr  9 18:35:03 2002
+++ linux-2.5.8-pre3/fs/affs/super.c	Tue Apr  9 18:35:20 2002
@@ -29,7 +29,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-extern int *blk_size[];
 extern struct timezone sys_tz;
 
 static int affs_statfs(struct super_block *sb, struct statfs *buf);
@@ -321,7 +320,7 @@
 	 */
 
 	size = sb->s_bdev->bd_inode->i_size >> 9;
-	pr_debug("AFFS: initial blksize=%d, blocks=%d\n", 512, blocks);
+	pr_debug("AFFS: initial blocksize=%d, #blocks=%d\n", 512, size);
 
 	affs_set_blocksize(sb, PAGE_SIZE);
 	/* Try to find root block. Its location depends on the block size. */
diff -urN linux-2.5.8-pre2/fs/attr.c linux-2.5.8-pre3/fs/attr.c
--- linux-2.5.8-pre2/fs/attr.c	Tue Apr  9 18:35:03 2002
+++ linux-2.5.8-pre3/fs/attr.c	Tue Apr  9 18:35:20 2002
@@ -119,6 +119,7 @@
 int notify_change(struct dentry * dentry, struct iattr * attr)
 {
 	struct inode *inode = dentry->d_inode;
+	mode_t mode = inode->i_mode;
 	int error;
 	time_t now = CURRENT_TIME;
 	unsigned int ia_valid = attr->ia_valid;
@@ -131,8 +132,25 @@
 		attr->ia_atime = now;
 	if (!(ia_valid & ATTR_MTIME_SET))
 		attr->ia_mtime = now;
+	if (ia_valid & ATTR_KILL_SUID) {
+		if (mode & S_ISUID) {
+			if (!ia_valid & ATTR_MODE) {
+				ia_valid = attr->ia_valid |= ATTR_MODE;
+				attr->ia_mode = inode->i_mode;
+			}
+			attr->ia_mode &= ~S_ISUID;
+		}
+	}
+	if (ia_valid & ATTR_KILL_SGID) {
+		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+			if (!ia_valid & ATTR_MODE) {
+				ia_valid = attr->ia_valid |= ATTR_MODE;
+				attr->ia_mode = inode->i_mode;
+			}
+			attr->ia_mode &= ~S_ISGID;
+		}
+	}
 
-	down(&inode->i_sem);
 	if (inode->i_op && inode->i_op->setattr) 
 		error = inode->i_op->setattr(dentry, attr);
 	else {
@@ -145,7 +163,6 @@
 				error = inode_setattr(inode, attr);
 		}
 	}
-	up(&inode->i_sem);
 	if (!error) {
 		unsigned long dn_mask = setattr_mask(ia_valid);
 		if (dn_mask)
diff -urN linux-2.5.8-pre2/fs/block_dev.c linux-2.5.8-pre3/fs/block_dev.c
--- linux-2.5.8-pre2/fs/block_dev.c	Tue Apr  9 18:35:04 2002
+++ linux-2.5.8-pre3/fs/block_dev.c	Tue Apr  9 18:35:20 2002
@@ -27,33 +27,22 @@
 static unsigned long max_block(kdev_t dev)
 {
 	unsigned int retval = ~0U;
-	int major = major(dev);
+	loff_t sz = blkdev_size_in_bytes(dev);
 
-	if (blk_size[major]) {
-		int minor = minor(dev);
-		unsigned int blocks = blk_size[major][minor];
-		if (blocks) {
-			unsigned int size = block_size(dev);
-			unsigned int sizebits = blksize_bits(size);
-			blocks += (size-1) >> BLOCK_SIZE_BITS;
-			retval = blocks << (BLOCK_SIZE_BITS - sizebits);
-			if (sizebits > BLOCK_SIZE_BITS)
-				retval = blocks >> (sizebits - BLOCK_SIZE_BITS);
-		}
+	if (sz) {
+		unsigned int size = block_size(dev);
+		unsigned int sizebits = blksize_bits(size);
+		retval = (sz >> sizebits);
 	}
 	return retval;
 }
 
 static loff_t blkdev_size(kdev_t dev)
 {
-	unsigned int blocks = ~0U;
-	int major = major(dev);
-
-	if (blk_size[major]) {
-		int minor = minor(dev);
-		blocks = blk_size[major][minor];
-	}
-	return (loff_t) blocks << BLOCK_SIZE_BITS;
+	loff_t sz = blkdev_size_in_bytes(dev);
+	if (sz)
+		return sz;
+	return ~0ULL;
 }
 
 /* Kill _all_ buffers, dirty or not.. */
diff -urN linux-2.5.8-pre2/fs/buffer.c linux-2.5.8-pre3/fs/buffer.c
--- linux-2.5.8-pre2/fs/buffer.c	Tue Apr  9 18:35:04 2002
+++ linux-2.5.8-pre3/fs/buffer.c	Tue Apr  9 18:35:20 2002
@@ -995,7 +995,7 @@
 
 	/* First, check for the "real" dirty limit. */
 	if (dirty > soft_dirty_limit) {
-		if (dirty > hard_dirty_limit)
+		if (dirty > hard_dirty_limit && !(current->flags & PF_NOIO))
 			return 1;
 		return 0;
 	}
diff -urN linux-2.5.8-pre2/fs/cramfs/inode.c linux-2.5.8-pre3/fs/cramfs/inode.c
--- linux-2.5.8-pre2/fs/cramfs/inode.c	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/fs/cramfs/inode.c	Tue Apr  9 18:35:21 2002
@@ -112,8 +112,6 @@
 	struct buffer_head * read_array[BLKS_PER_BUF];
 	unsigned i, blocknr, buffer, unread;
 	unsigned long devsize;
-	unsigned int major, minor;
-
 	char *data;
 
 	if (!len)
@@ -136,12 +134,9 @@
 		return read_buffers[i] + blk_offset;
 	}
 
-	devsize = ~0UL;
-	major = major(sb->s_dev);
-	minor = minor(sb->s_dev);
-
-	if (blk_size[major])
-		devsize = blk_size[major][minor] >> 2;
+	devsize = blkdev_size_in_bytes(sb->s_dev) >> 12;
+	if (!devsize)
+		devsize = ~0UL;
 
 	/* Ok, read in BLKS_PER_BUF pages completely first. */
 	unread = 0;
diff -urN linux-2.5.8-pre2/fs/devfs/base.c linux-2.5.8-pre3/fs/devfs/base.c
--- linux-2.5.8-pre2/fs/devfs/base.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/fs/devfs/base.c	Tue Apr  9 18:35:21 2002
@@ -612,6 +612,14 @@
 	       Added KERN_* to remaining messages.
 	       Cleaned up declaration of <stat_read>.
   v1.11
+    20020219   Richard Gooch <rgooch@atnf.csiro.au>
+	       Changed <devfs_rmdir> to allow later additions if not yet empty.
+  v1.12
+    20020406   Richard Gooch <rgooch@atnf.csiro.au>
+	       Removed silently introduced calls to lock_kernel() and
+	       unlock_kernel() due to recent VFS locking changes. BKL isn't
+	       required in devfs.
+  v1.13
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -644,7 +652,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "1.11 (20020129)"
+#define DEVFS_VERSION            "1.13 (20020406)"
 
 #define DEVFS_NAME "devfs"
 
@@ -2667,7 +2675,7 @@
       case 0:
 	scan_dir_for_removable (parent);
 	err = (*filldir) (dirent, "..", 2, file->f_pos,
-			  parent_ino(file->f_dentry), DT_DIR);
+			  parent_ino (file->f_dentry), DT_DIR);
 	if (err == -EINVAL) break;
 	if (err < 0) return err;
 	file->f_pos++;
@@ -2933,14 +2941,10 @@
 	up on any error  */
     dentry->d_op = &devfs_dops;
     /*  First try to get the devfs entry for this directory  */
-    lock_kernel();
     parent = get_devfs_entry_from_vfs_inode (dir);
     DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n",
 	     dentry->d_name.name, dentry, parent, current->comm);
-    if (parent == NULL) {
-	unlock_kernel();
-	return ERR_PTR (-ENOENT);
-    }
+    if (parent == NULL) return ERR_PTR (-ENOENT);
     read_lock (&parent->u.dir.lock);
     de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
     read_unlock (&parent->u.dir.lock);
@@ -2965,7 +2969,6 @@
 	if (try_modload (parent, fs_info,
 			 dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
 	{   /*  Lookup event was not queued to devfsd  */
-	    unlock_kernel();
 	    d_add (dentry, NULL);
 	    return NULL;
 	}
@@ -3008,7 +3011,6 @@
     wake_up (&lookup_info.wait_queue);
     write_unlock (&parent->u.dir.lock);
     devfs_put (de);
-    unlock_kernel();
     return retval;
 }   /*  End Function devfs_lookup  */
 
@@ -3019,30 +3021,19 @@
     struct inode *inode = dentry->d_inode;
     struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
 
-    lock_kernel();
     de = get_devfs_entry_from_vfs_inode (inode);
     DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
-    if (de == NULL) {
-	unlock_kernel();
-	return -ENOENT;
-    }
-    if (!de->vfs_deletable) {
-	unlock_kernel();
-	return -EPERM;
-    }
+    if (de == NULL) return -ENOENT;
+    if (!de->vfs_deletable) return -EPERM;
     write_lock (&de->parent->u.dir.lock);
     unhooked = _devfs_unhook (de);
     write_unlock (&de->parent->u.dir.lock);
-    if (!unhooked) {
-	unlock_kernel();
-	return -ENOENT;
-    }
+    if (!unhooked) return -ENOENT;
     if ( !is_devfsd_or_child (fs_info) )
 	devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
 			  inode->i_uid, inode->i_gid, fs_info, 0);
     free_dentry (de);
     devfs_put (de);
-    unlock_kernel();
     return 0;
 }   /*  End Function devfs_unlink  */
 
@@ -3055,37 +3046,27 @@
     struct inode *inode;
 
     /*  First try to get the devfs entry for this directory  */
-    lock_kernel();
     parent = get_devfs_entry_from_vfs_inode (dir);
-    if (parent == NULL) {
-	unlock_kernel();
-	return -ENOENT;
-    }
+    if (parent == NULL) return -ENOENT;
     err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
 			    symname, &de, NULL);
     DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
 	     dentry->d_name.name, err);
-    if (err < 0) {
-	unlock_kernel();
-	return err;
-    }
+    if (err < 0) return err;
     de->vfs_deletable = TRUE;
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) {
-	unlock_kernel();
+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
-    }
     DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
 	     dentry->d_name.name, de->inode.ino, inode, dentry);
     d_instantiate (dentry, inode);
     if ( !is_devfsd_or_child (fs_info) )
 	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
 			  inode->i_uid, inode->i_gid, fs_info, 0);
-    unlock_kernel();
     return 0;
 }   /*  End Function devfs_symlink  */
 
@@ -3097,38 +3078,26 @@
     struct inode *inode;
 
     mode = (mode & ~S_IFMT) | S_IFDIR;  /*  VFS doesn't pass S_IFMT part  */
-    lock_kernel();
     parent = get_devfs_entry_from_vfs_inode (dir);
-    if (parent == NULL) {
-	unlock_kernel();
-	return -ENOENT;
-    }
+    if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
-    if (!de) {
-	unlock_kernel();
-	return -ENOMEM;
-    }
+    if (!de) return -ENOMEM;
     de->vfs_deletable = TRUE;
-    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 ) {
-	unlock_kernel();
+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
 	return err;
-    }
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) {
-	unlock_kernel();
+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
-    }
     DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p  dentry: %p\n",
 	     dentry->d_name.name, de->inode.ino, inode, dentry);
     d_instantiate (dentry, inode);
     if ( !is_devfsd_or_child (fs_info) )
 	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
 			  inode->i_uid, inode->i_gid, fs_info, 0);
-    unlock_kernel();
     return 0;
 }   /*  End Function devfs_mkdir  */
 
@@ -3139,45 +3108,27 @@
     struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
     struct inode *inode = dentry->d_inode;
 
-    /* WTF??? */
     if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
-    lock_kernel();
     de = get_devfs_entry_from_vfs_inode (inode);
-    if (de == NULL) {
-	unlock_kernel();
-	return -ENOENT;
-    }
-    if ( !S_ISDIR (de->mode) ) {
-	unlock_kernel();
-	return -ENOTDIR;
-    }
-    if (!de->vfs_deletable) {
-	unlock_kernel();
-	return -EPERM;
-    }
-    /*  First ensure the directory is empty and will stay thay way  */
+    if (de == NULL) return -ENOENT;
+    if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
+    if (!de->vfs_deletable) return -EPERM;
+    /*  First ensure the directory is empty and will stay that way  */
     write_lock (&de->u.dir.lock);
-    de->u.dir.no_more_additions = TRUE;
     if (de->u.dir.first) err = -ENOTEMPTY;
+    else de->u.dir.no_more_additions = TRUE;
     write_unlock (&de->u.dir.lock);
-    if (err) {
-	unlock_kernel();
-	return err;
-    }
+    if (err) return err;
     /*  Now unhook the directory from it's parent  */
     write_lock (&de->parent->u.dir.lock);
     if ( !_devfs_unhook (de) ) err = -ENOENT;
     write_unlock (&de->parent->u.dir.lock);
-    if (err) {
-	unlock_kernel();
-	return err;
-    }
+    if (err) return err;
     if ( !is_devfsd_or_child (fs_info) )
 	devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
 			  inode->i_uid, inode->i_gid, fs_info, 0);
     free_dentry (de);
     devfs_put (de);
-    unlock_kernel();
     return 0;
 }   /*  End Function devfs_rmdir  */
 
@@ -3191,43 +3142,31 @@
 
     DPRINTK (DEBUG_I_MKNOD, "(%s): mode: 0%o  dev: %d\n",
 	     dentry->d_name.name, mode, rdev);
-    lock_kernel();
     parent = get_devfs_entry_from_vfs_inode (dir);
-    if (parent == NULL) {
-	unlock_kernel();
-	return -ENOENT;
-    }
+    if (parent == NULL) return -ENOENT;
     de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
-    if (!de) {
-	unlock_kernel();
-	return -ENOMEM;
-    }
+    if (!de) return -ENOMEM;
     de->vfs_deletable = TRUE;
     if ( S_ISBLK (mode) || S_ISCHR (mode) )
     {
 	de->u.fcb.u.device.major = MAJOR (rdev);
 	de->u.fcb.u.device.minor = MINOR (rdev);
     }
-    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 ) {
-	unlock_kernel();
+    if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
 	return err;
-    }
     de->inode.uid = current->euid;
     de->inode.gid = current->egid;
     de->inode.atime = CURRENT_TIME;
     de->inode.mtime = CURRENT_TIME;
     de->inode.ctime = CURRENT_TIME;
-    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) {
-	unlock_kernel();
+    if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
 	return -ENOMEM;
-    }
     DPRINTK (DEBUG_I_MKNOD, ":   new VFS inode(%u): %p  dentry: %p\n",
 	     de->inode.ino, inode, dentry);
     d_instantiate (dentry, inode);
     if ( !is_devfsd_or_child (fs_info) )
 	devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
 			  inode->i_uid, inode->i_gid, fs_info, 0);
-    unlock_kernel();
     return 0;
 }   /*  End Function devfs_mknod  */
 
@@ -3301,18 +3240,19 @@
     PRINTK ("(): get root inode failed\n");
     if (root_inode) iput (root_inode);
     return -EINVAL;
-}   /*  End Function devfs_read_super  */
+}   /*  End Function devfs_fill_super  */
 
-static struct super_block *devfs_get_sb(struct file_system_type *fs_type,
-	int flags, char *dev_name, void *data)
+static struct super_block *devfs_get_sb (struct file_system_type *fs_type,
+					 int flags, char *dev_name, void *data)
 {
-	return get_sb_single(fs_type, flags, data, devfs_fill_super);
+    return get_sb_single (fs_type, flags, data, devfs_fill_super);
 }
 
-static struct file_system_type devfs_fs_type = {
-	name:		DEVFS_NAME,
-	get_sb:		devfs_get_sb,
-	kill_sb:	kill_anon_super,
+static struct file_system_type devfs_fs_type =
+{
+    name:	DEVFS_NAME,
+    get_sb:	devfs_get_sb,
+    kill_sb:	kill_anon_super,
 };
 
 /*  File operations for devfsd follow  */
diff -urN linux-2.5.8-pre2/fs/devfs/util.c linux-2.5.8-pre3/fs/devfs/util.c
--- linux-2.5.8-pre2/fs/devfs/util.c	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/fs/devfs/util.c	Tue Apr  9 18:35:21 2002
@@ -1,6 +1,6 @@
 /*  devfs (Device FileSystem) utilities.
 
-    Copyright (C) 1999-2001  Richard Gooch
+    Copyright (C) 1999-2002  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -48,6 +48,12 @@
     20010818   Richard Gooch <rgooch@atnf.csiro.au>
                Updated major masks up to Linus' "no new majors" proclamation.
 	       Block: were 126 now 122 free, char: were 26 now 19 free.
+    20020324   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixed bug in <devfs_alloc_unique_number>: was clearing beyond
+	       bitfield.
+    20020326   Richard Gooch <rgooch@atnf.csiro.au>
+               Fixed bitfield data type for <devfs_*alloc_devnum>.
+               Made major bitfield type and initialiser 64 bit safe.
 */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -125,8 +131,13 @@
 struct major_list
 {
     spinlock_t lock;
-    __u32 bits[8];
+    unsigned long bits[256 / BITS_PER_LONG];
 };
+#if BITS_PER_LONG == 32
+#  define INITIALISER64(low,high) (low), (high)
+#else
+#  define INITIALISER64(low,high) ( (high) << 32 | (low) )
+#endif
 
 /*  Block majors already assigned:
     0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
@@ -134,14 +145,11 @@
 */
 static struct major_list block_major_list =
 {SPIN_LOCK_UNLOCKED,
-    {0xfffffb8f,  /*  Majors 0   to 31   */
-     0xffffffff,  /*  Majors 32  to 63   */
-     0xfffffffe,  /*  Majors 64  to 95   */
-     0xff03ffef,  /*  Majors 96  to 127  */
-     0x00000000,  /*  Majors 128 to 159  */
-     0x00000000,  /*  Majors 160 to 191  */
-     0x00000280,  /*  Majors 192 to 223  */
-     0xffff0000}  /*  Majors 224 to 255  */
+    {INITIALISER64 (0xfffffb8f, 0xffffffff),  /*  Majors 0-31,    32-63    */
+     INITIALISER64 (0xfffffffe, 0xff03ffef),  /*  Majors 64-95,   96-127   */
+     INITIALISER64 (0x00000000, 0x00000000),  /*  Majors 128-159, 160-191  */
+     INITIALISER64 (0x00000280, 0xffff0000),  /*  Majors 192-223, 224-255  */
+    }
 };
 
 /*  Char majors already assigned:
@@ -150,14 +158,11 @@
 */
 static struct major_list char_major_list =
 {SPIN_LOCK_UNLOCKED,
-    {0xfffffeff,  /*  Majors 0   to 31   */
-     0xffffffff,  /*  Majors 32  to 63   */
-     0xffffffff,  /*  Majors 64  to 95   */
-     0xffffffff,  /*  Majors 96  to 127  */
-     0x7cffffff,  /*  Majors 128 to 159  */
-     0xffffffff,  /*  Majors 160 to 191  */
-     0x3f0fffff,  /*  Majors 192 to 223  */
-     0xffff007f}  /*  Majors 224 to 255  */
+    {INITIALISER64 (0xfffffeff, 0xffffffff),  /*  Majors 0-31,    32-63    */
+     INITIALISER64 (0xffffffff, 0xffffffff),  /*  Majors 64-95,   96-127   */
+     INITIALISER64 (0x7cffffff, 0xffffffff),  /*  Majors 128-159, 160-191  */
+     INITIALISER64 (0x3f0fffff, 0xffff007f),  /*  Majors 192-223, 224-255  */
+    }
 };
 
 
@@ -212,7 +217,7 @@
 struct minor_list
 {
     int major;
-    __u32 bits[8];
+    unsigned long bits[256 / BITS_PER_LONG];
     struct minor_list *next;
 };
 
@@ -267,7 +272,7 @@
 	if (minor >= 256) continue;
 	__set_bit (minor, entry->bits);
 	up (semaphore);
-	return mk_kdev(entry->major, minor);
+	return mk_kdev (entry->major, minor);
     }
     /*  Need to allocate a new major  */
     if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL )
@@ -289,7 +294,7 @@
     else list->last->next = entry;
     list->last = entry;
     up (semaphore);
-    return mk_kdev(entry->major, 0);
+    return mk_kdev (entry->major, 0);
 }   /*  End Function devfs_alloc_devnum  */
 EXPORT_SYMBOL(devfs_alloc_devnum);
 
@@ -309,7 +314,7 @@
     struct device_list *list;
     struct minor_list *entry;
 
-    if (kdev_none(devnum)) return;
+    if ( kdev_none (devnum) ) return;
     if (type == DEVFS_SPECIAL_CHR)
     {
 	semaphore = &char_semaphore;
@@ -355,7 +360,6 @@
 {
     int number;
     unsigned int length;
-    __u32 *bits;
 
     /*  Get around stupid lack of semaphore initialiser  */
     spin_lock (&space->init_lock);
@@ -368,6 +372,8 @@
     down (&space->semaphore);
     if (space->num_free < 1)
     {
+	void *bits;
+
 	if (space->length < 16) length = 16;
 	else length = space->length << 1;
 	if ( ( bits = vmalloc (length) ) == NULL )
diff -urN linux-2.5.8-pre2/fs/dquot.c linux-2.5.8-pre3/fs/dquot.c
--- linux-2.5.8-pre2/fs/dquot.c	Tue Apr  9 18:35:04 2002
+++ linux-2.5.8-pre3/fs/dquot.c	Tue Apr  9 18:35:21 2002
@@ -429,7 +429,8 @@
 	count = nr_free_dquots / priority;
 	prune_dqcache(count);
 	unlock_kernel();
-	return kmem_cache_shrink_nr(dquot_cachep);
+	kmem_cache_shrink(dquot_cachep);
+	return 0;
 }
 
 /* NOTE: If you change this function please check whether dqput_blocks() works right... */
diff -urN linux-2.5.8-pre2/fs/ext3/inode.c linux-2.5.8-pre3/fs/ext3/inode.c
--- linux-2.5.8-pre2/fs/ext3/inode.c	Tue Apr  9 18:35:04 2002
+++ linux-2.5.8-pre3/fs/ext3/inode.c	Tue Apr  9 18:35:21 2002
@@ -2377,6 +2377,8 @@
 			return error;
 	}
 
+	lock_kernel();
+
 	if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
 		handle_t *handle;
 
@@ -2404,6 +2406,7 @@
 
 err_out:
 	ext3_std_error(inode->i_sb, error);
+	unlock_kernel();
 	if (!error)
 		error = rc;
 	return error;
diff -urN linux-2.5.8-pre2/fs/fat/inode.c linux-2.5.8-pre3/fs/fat/inode.c
--- linux-2.5.8-pre2/fs/fat/inode.c	Tue Apr  9 18:35:04 2002
+++ linux-2.5.8-pre3/fs/fat/inode.c	Tue Apr  9 18:35:21 2002
@@ -1086,7 +1086,8 @@
 			error = 0;
 		goto out;
 	}
-	if( error = inode_setattr(inode, attr) )
+	error = inode_setattr(inode, attr);
+	if (error)
 		goto out;
 
 	if (S_ISDIR(inode->i_mode))
diff -urN linux-2.5.8-pre2/fs/hpfs/namei.c linux-2.5.8-pre3/fs/hpfs/namei.c
--- linux-2.5.8-pre2/fs/hpfs/namei.c	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/fs/hpfs/namei.c	Tue Apr  9 18:35:21 2002
@@ -365,11 +365,9 @@
 			goto ret;
 		}
 		/*printk("HPFS: truncating file before delete.\n");*/
-		down(&inode->i_sem);
 		newattrs.ia_size = 0;
 		newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 		err = notify_change(dentry, &newattrs);
-		up(&inode->i_sem);
 		put_write_access(inode);
 		if (err)
 			goto ret;
diff -urN linux-2.5.8-pre2/fs/jffs2/file.c linux-2.5.8-pre3/fs/jffs2/file.c
--- linux-2.5.8-pre2/fs/jffs2/file.c	Tue Apr  9 18:35:05 2002
+++ linux-2.5.8-pre3/fs/jffs2/file.c	Tue Apr  9 18:35:21 2002
@@ -43,6 +43,7 @@
 #include <linux/pagemap.h>
 #include <linux/crc32.h>
 #include <linux/jffs2.h>
+#include <linux/smp_lock.h>
 #include "nodelist.h"
 
 extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
diff -urN linux-2.5.8-pre2/fs/namei.c linux-2.5.8-pre3/fs/namei.c
--- linux-2.5.8-pre2/fs/namei.c	Tue Apr  9 18:35:06 2002
+++ linux-2.5.8-pre3/fs/namei.c	Tue Apr  9 18:35:22 2002
@@ -988,6 +988,80 @@
 	return error;
 }
 
+int may_open(struct nameidata *nd, int acc_mode, int flag)
+{
+	struct dentry *dentry = nd->dentry;
+	struct inode *inode = dentry->d_inode;
+	int error;
+
+	if (!inode)
+		return -ENOENT;
+
+	if (S_ISLNK(inode->i_mode))
+		return -ELOOP;
+	
+	if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
+		return -EISDIR;
+
+	error = permission(inode, acc_mode);
+	if (error)
+		return error;
+
+	/*
+	 * FIFO's, sockets and device files are special: they don't
+	 * actually live on the filesystem itself, and as such you
+	 * can write to them even if the filesystem is read-only.
+	 */
+	if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
+	    	flag &= ~O_TRUNC;
+	} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+		if (nd->mnt->mnt_flags & MNT_NODEV)
+			return -EACCES;
+
+		flag &= ~O_TRUNC;
+	} else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
+		return -EROFS;
+	/*
+	 * An append-only file must be opened in append mode for writing.
+	 */
+	if (IS_APPEND(inode)) {
+		if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))
+			return -EPERM;
+		if (flag & O_TRUNC)
+			return -EPERM;
+	}
+
+	/*
+	 * Ensure there are no outstanding leases on the file.
+	 */
+	error = get_lease(inode, flag);
+	if (error)
+		return error;
+
+	if (flag & O_TRUNC) {
+		error = get_write_access(inode);
+		if (error)
+			return error;
+
+		/*
+		 * Refuse to truncate files with mandatory locks held on them.
+		 */
+		error = locks_verify_locked(inode);
+		if (!error) {
+			DQUOT_INIT(inode);
+			
+			error = do_truncate(dentry, 0);
+		}
+		put_write_access(inode);
+		if (error)
+			return error;
+	} else
+		if (flag & FMODE_WRITE)
+			DQUOT_INIT(inode);
+
+	return 0;
+}
+
 /*
  *	open_namei()
  *
@@ -1005,7 +1079,6 @@
 int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
 {
 	int acc_mode, error = 0;
-	struct inode *inode;
 	struct dentry *dentry;
 	struct dentry *dir;
 	int count = 0;
@@ -1092,80 +1165,9 @@
 	if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
 		goto exit;
 ok:
-	error = -ENOENT;
-	inode = dentry->d_inode;
-	if (!inode)
-		goto exit;
-
-	error = -ELOOP;
-	if (S_ISLNK(inode->i_mode))
-		goto exit;
-	
-	error = -EISDIR;
-	if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
-		goto exit;
-
-	error = permission(inode,acc_mode);
-	if (error)
-		goto exit;
-
-	/*
-	 * FIFO's, sockets and device files are special: they don't
-	 * actually live on the filesystem itself, and as such you
-	 * can write to them even if the filesystem is read-only.
-	 */
-	if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
-	    	flag &= ~O_TRUNC;
-	} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-		error = -EACCES;
-		if (nd->mnt->mnt_flags & MNT_NODEV)
-			goto exit;
-
-		flag &= ~O_TRUNC;
-	} else {
-		error = -EROFS;
-		if (IS_RDONLY(inode) && (flag & 2))
-			goto exit;
-	}
-	/*
-	 * An append-only file must be opened in append mode for writing.
-	 */
-	error = -EPERM;
-	if (IS_APPEND(inode)) {
-		if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))
-			goto exit;
-		if (flag & O_TRUNC)
-			goto exit;
-	}
-
-	/*
-	 * Ensure there are no outstanding leases on the file.
-	 */
-	error = get_lease(inode, flag);
+	error = may_open(nd, acc_mode, flag);
 	if (error)
 		goto exit;
-
-	if (flag & O_TRUNC) {
-		error = get_write_access(inode);
-		if (error)
-			goto exit;
-
-		/*
-		 * Refuse to truncate files with mandatory locks held on them.
-		 */
-		error = locks_verify_locked(inode);
-		if (!error) {
-			DQUOT_INIT(inode);
-			
-			error = do_truncate(dentry, 0);
-		}
-		put_write_access(inode);
-		if (error)
-			goto exit;
-	} else
-		if (flag & FMODE_WRITE)
-			DQUOT_INIT(inode);
-
 	return 0;
 
 exit_dput:
diff -urN linux-2.5.8-pre2/fs/ncpfs/inode.c linux-2.5.8-pre3/fs/ncpfs/inode.c
--- linux-2.5.8-pre2/fs/ncpfs/inode.c	Tue Apr  9 18:35:06 2002
+++ linux-2.5.8-pre3/fs/ncpfs/inode.c	Tue Apr  9 18:35:22 2002
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <linux/ncp_fs.h>
 
diff -urN linux-2.5.8-pre2/fs/nfsctl.c linux-2.5.8-pre3/fs/nfsctl.c
--- linux-2.5.8-pre2/fs/nfsctl.c	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/fs/nfsctl.c	Tue Apr  9 18:35:22 2002
@@ -37,7 +37,16 @@
 	if (error)
 		return ERR_PTR(error);
 
-	return dentry_open(nd.dentry, nd.mnt, flags);
+	if (flags == O_RDWR)
+		error = may_open(&nd,MAY_READ|MAY_WRITE,FMODE_READ|FMODE_WRITE);
+	else
+		error = may_open(&nd, MAY_WRITE, FMODE_WRITE);
+
+	if (!error)
+		return dentry_open(nd.dentry, nd.mnt, flags);
+
+	path_release(&nd);
+	return ERR_PTR(error);
 }
 
 static struct {
diff -urN linux-2.5.8-pre2/fs/nfsd/nfsctl.c linux-2.5.8-pre3/fs/nfsd/nfsctl.c
--- linux-2.5.8-pre2/fs/nfsd/nfsctl.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/fs/nfsd/nfsctl.c	Tue Apr  9 18:35:22 2002
@@ -22,6 +22,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/pagemap.h>
+#include <linux/init.h>
 
 #include <linux/nfs.h>
 #include <linux/sunrpc/svc.h>
diff -urN linux-2.5.8-pre2/fs/nfsd/vfs.c linux-2.5.8-pre3/fs/nfsd/vfs.c
--- linux-2.5.8-pre2/fs/nfsd/vfs.c	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/fs/nfsd/vfs.c	Tue Apr  9 18:35:22 2002
@@ -264,6 +264,7 @@
 		if (err)
 			goto out_nfserr;
 
+		size_change = 1;
 		err = locks_verify_truncate(inode, NULL, iap->ia_size);
 		if (err) {
 			put_write_access(inode);
@@ -279,35 +280,24 @@
 	}
 
 	/* Revoke setuid/setgid bit on chown/chgrp */
-	if ((iap->ia_valid & ATTR_UID) && (imode & S_ISUID)
-	 && iap->ia_uid != inode->i_uid) {
-		iap->ia_valid |= ATTR_MODE;
-		iap->ia_mode = imode &= ~S_ISUID;
-	}
-	if ((iap->ia_valid & ATTR_GID) && (imode & S_ISGID)
-	 && iap->ia_gid != inode->i_gid) {
-		iap->ia_valid |= ATTR_MODE;
-		iap->ia_mode = imode &= ~S_ISGID;
-	}
+	if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid)
+		iap->ia_valid |= ATTR_KILL_SUID;
+	if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
+		iap->ia_valid |= ATTR_KILL_SGID;
 
 	/* Change the attributes. */
 
-
 	iap->ia_valid |= ATTR_CTIME;
 
-	if (iap->ia_valid & ATTR_SIZE) {
-		fh_lock(fhp);
-		size_change = 1;
-	}
 	err = nfserr_notsync;
 	if (!check_guard || guardtime == inode->i_ctime) {
+		fh_lock(fhp);
 		err = notify_change(dentry, iap);
 		err = nfserrno(err);
-	}
-	if (size_change) {
 		fh_unlock(fhp);
-		put_write_access(inode);
 	}
+	if (size_change)
+		put_write_access(inode);
 	if (!err)
 		if (EX_ISSYNC(fhp->fh_export))
 			write_inode_now(inode, 1);
@@ -725,10 +715,11 @@
 	/* clear setuid/setgid flag after write */
 	if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
 		struct iattr	ia;
+		ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID;
 
-		ia.ia_valid = ATTR_MODE;
-		ia.ia_mode  = inode->i_mode & ~(S_ISUID | S_ISGID);
+		down(&inode->i_sem);
 		notify_change(dentry, &ia);
+		up(&inode->i_sem);
 	}
 
 	if (err >= 0 && stable) {
@@ -1157,7 +1148,9 @@
 				iap->ia_valid |= ATTR_CTIME;
 				iap->ia_mode = (iap->ia_mode&S_IALLUGO)
 					| S_IFLNK;
+				down(&dentry->d_inode->i_sem);
 				err = notify_change(dnew, iap);
+				up(&dentry->d_inode->i_sem);
 				if (!err && EX_ISSYNC(fhp->fh_export))
 					write_inode_now(dentry->d_inode, 1);
 		       }
diff -urN linux-2.5.8-pre2/fs/open.c linux-2.5.8-pre3/fs/open.c
--- linux-2.5.8-pre2/fs/open.c	Tue Apr  9 18:35:10 2002
+++ linux-2.5.8-pre3/fs/open.c	Tue Apr  9 18:35:24 2002
@@ -73,6 +73,7 @@
 
 int do_truncate(struct dentry *dentry, loff_t length)
 {
+	int err;
 	struct iattr newattrs;
 
 	/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
@@ -81,7 +82,10 @@
 
 	newattrs.ia_size = length;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-	return notify_change(dentry, &newattrs);
+	down(&dentry->d_inode->i_sem);
+	err = notify_change(dentry, &newattrs);
+	up(&dentry->d_inode->i_sem);
+	return err;
 }
 
 static inline long do_sys_truncate(const char * path, loff_t length)
@@ -255,7 +259,9 @@
 		    (error = permission(inode,MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
+	down(&inode->i_sem);
 	error = notify_change(nd.dentry, &newattrs);
+	up(&inode->i_sem);
 dput_and_out:
 	path_release(&nd);
 out:
@@ -299,7 +305,9 @@
 		if ((error = permission(inode,MAY_WRITE)) != 0)
 			goto dput_and_out;
 	}
+	down(&inode->i_sem);
 	error = notify_change(nd.dentry, &newattrs);
+	up(&inode->i_sem);
 dput_and_out:
 	path_release(&nd);
 out:
@@ -449,11 +457,13 @@
 	err = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		goto out_putf;
+	down(&inode->i_sem);
 	if (mode == (mode_t) -1)
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 	err = notify_change(dentry, &newattrs);
+	up(&inode->i_sem);
 
 out_putf:
 	fput(file);
@@ -481,11 +491,13 @@
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		goto dput_and_out;
 
+	down(&inode->i_sem);
 	if (mode == (mode_t) -1)
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 	error = notify_change(nd.dentry, &newattrs);
+	up(&inode->i_sem);
 
 dput_and_out:
 	path_release(&nd);
@@ -510,45 +522,20 @@
 	error = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		goto out;
-	if (user == (uid_t) -1)
-		user = inode->i_uid;
-	if (group == (gid_t) -1)
-		group = inode->i_gid;
-	newattrs.ia_mode = inode->i_mode;
-	newattrs.ia_uid = user;
-	newattrs.ia_gid = group;
-	newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
-	/*
-	 * If the user or group of a non-directory has been changed by a
-	 * non-root user, remove the setuid bit.
-	 * 19981026	David C Niemi <niemi@tux.org>
-	 *
-	 * Changed this to apply to all users, including root, to avoid
-	 * some races. This is the behavior we had in 2.0. The check for
-	 * non-root was definitely wrong for 2.2 anyway, as it should
-	 * have been using CAP_FSETID rather than fsuid -- 19990830 SD.
-	 */
-	if ((inode->i_mode & S_ISUID) == S_ISUID &&
-		!S_ISDIR(inode->i_mode))
-	{
-		newattrs.ia_mode &= ~S_ISUID;
-		newattrs.ia_valid |= ATTR_MODE;
+	newattrs.ia_valid =  ATTR_CTIME;
+	if (user != (uid_t) -1) {
+		newattrs.ia_valid =  ATTR_UID;
+		newattrs.ia_uid = user;
 	}
-	/*
-	 * Likewise, if the user or group of a non-directory has been changed
-	 * by a non-root user, remove the setgid bit UNLESS there is no group
-	 * execute bit (this would be a file marked for mandatory locking).
-	 * 19981026	David C Niemi <niemi@tux.org>
-	 *
-	 * Removed the fsuid check (see the comment above) -- 19990830 SD.
-	 */
-	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 
-		&& !S_ISDIR(inode->i_mode))
-	{
-		newattrs.ia_mode &= ~S_ISGID;
-		newattrs.ia_valid |= ATTR_MODE;
+	if (group != (gid_t) -1) {
+		newattrs.ia_valid =  ATTR_GID;
+		newattrs.ia_gid = group;
 	}
+	if (!S_ISDIR(inode->i_mode))
+		newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
+	down(&inode->i_sem);
 	error = notify_change(dentry, &newattrs);
+	up(&inode->i_sem);
 out:
 	return error;
 }
diff -urN linux-2.5.8-pre2/include/asm-alpha/tlbflush.h linux-2.5.8-pre3/include/asm-alpha/tlbflush.h
--- linux-2.5.8-pre2/include/asm-alpha/tlbflush.h	Tue Apr  9 18:35:11 2002
+++ linux-2.5.8-pre3/include/asm-alpha/tlbflush.h	Tue Apr  9 18:35:24 2002
@@ -152,4 +152,6 @@
 
 #endif /* CONFIG_SMP */
 
+#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+
 #endif /* _ALPHA_TLBFLUSH_H */
diff -urN linux-2.5.8-pre2/include/asm-alpha/unistd.h linux-2.5.8-pre3/include/asm-alpha/unistd.h
--- linux-2.5.8-pre2/include/asm-alpha/unistd.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/include/asm-alpha/unistd.h	Tue Apr  9 18:35:24 2002
@@ -597,4 +597,12 @@
 
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ALPHA_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-arm/unistd.h linux-2.5.8-pre3/include/asm-arm/unistd.h
--- linux-2.5.8-pre2/include/asm-arm/unistd.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/include/asm-arm/unistd.h	Tue Apr  9 18:35:25 2002
@@ -466,4 +466,13 @@
 static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp);
 
 #endif
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* __ASM_ARM_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-cris/unistd.h linux-2.5.8-pre3/include/asm-cris/unistd.h
--- linux-2.5.8-pre2/include/asm-cris/unistd.h	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/include/asm-cris/unistd.h	Tue Apr  9 18:35:25 2002
@@ -395,4 +395,12 @@
 
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_CRIS_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-generic/percpu.h linux-2.5.8-pre3/include/asm-generic/percpu.h
--- linux-2.5.8-pre2/include/asm-generic/percpu.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-generic/percpu.h	Tue Apr  9 18:35:25 2002
@@ -0,0 +1,13 @@
+#ifndef _ASM_GENERIC_PERCPU_H_
+#define _ASM_GENERIC_PERCPU_H_
+
+#define __GENERIC_PER_CPU
+#include <linux/compiler.h>
+
+extern unsigned long __per_cpu_offset[NR_CPUS];
+
+/* var is in discarded region: offset to particular copy we want */
+#define per_cpu(var, cpu) (*RELOC_HIDE(&var, __per_cpu_offset[cpu]))
+#define this_cpu(var) per_cpu(var, smp_processor_id())
+
+#endif /* _ASM_GENERIC_PERCPU_H_ */
diff -urN linux-2.5.8-pre2/include/asm-i386/acpi.h linux-2.5.8-pre3/include/asm-i386/acpi.h
--- linux-2.5.8-pre2/include/asm-i386/acpi.h	Mon Mar 18 12:37:11 2002
+++ linux-2.5.8-pre3/include/asm-i386/acpi.h	Tue Apr  9 18:35:25 2002
@@ -33,10 +33,15 @@
 /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
 #define FIX_ACPI_PAGES		4
 
+extern int acpi_mp_config;
+
 char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
 extern int acpi_find_rsdp (unsigned long *phys_addr);
 extern int acpi_parse_madt (unsigned long phys_addr, unsigned long size);
+extern int acpi_boot_init (char *cmdline);
 
+#else
+#define acpi_mp_config 0
 #endif /*CONFIG_ACPI_BOOT*/
 
 #ifdef CONFIG_ACPI_PCI
diff -urN linux-2.5.8-pre2/include/asm-i386/bugs.h linux-2.5.8-pre3/include/asm-i386/bugs.h
--- linux-2.5.8-pre2/include/asm-i386/bugs.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/include/asm-i386/bugs.h	Tue Apr  9 18:35:25 2002
@@ -194,7 +194,7 @@
  */
 #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
-	    && test_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability)
+	    && test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability)
 	    && boot_cpu_data.x86 == 5
 	    && boot_cpu_data.x86_model == 2
 	    && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
diff -urN linux-2.5.8-pre2/include/asm-i386/hw_irq.h linux-2.5.8-pre3/include/asm-i386/hw_irq.h
--- linux-2.5.8-pre2/include/asm-i386/hw_irq.h	Tue Apr  9 18:35:11 2002
+++ linux-2.5.8-pre3/include/asm-i386/hw_irq.h	Tue Apr  9 18:35:25 2002
@@ -17,57 +17,28 @@
 #include <asm/irq.h>
 
 /*
- * IDT vectors usable for external interrupt sources start
- * at 0x20:
- */
-#define FIRST_EXTERNAL_VECTOR	0x20
-
-#define SYSCALL_VECTOR		0x80
-
-/*
- * Vectors 0x20-0x2f are used for ISA interrupts.
- */
-
-/*
- * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
- *
- *  some of the following vectors are 'rare', they are merged
- *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
- *  TLB, reschedule and local APIC vectors are performance-critical.
+ * Various low-level irq details needed by irq.c, process.c,
+ * time.c, io_apic.c and smp.c
  *
- *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
- */
-#define SPURIOUS_APIC_VECTOR	0xff
-#define ERROR_APIC_VECTOR	0xfe
-#define INVALIDATE_TLB_VECTOR	0xfd
-#define RESCHEDULE_VECTOR	0xfc
-#define CALL_FUNCTION_VECTOR	0xfb
-
-#define THERMAL_APIC_VECTOR	0xf0
-/*
- * Local APIC timer IRQ vector is on a different priority level,
- * to work around the 'lost local interrupt if more than 2 IRQ
- * sources per level' errata.
- */
-#define LOCAL_TIMER_VECTOR	0xef
-
-/*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
- * we start at 0x31 to spread out vectors evenly between priority
- * levels. (0x80 is the syscall vector)
+ * Interrupt entry/exit code at both C and assembly level
  */
-#define FIRST_DEVICE_VECTOR	0x31
-#define FIRST_SYSTEM_VECTOR	0xef
 
 extern int irq_vector[NR_IRQS];
 #define IO_APIC_VECTOR(irq)	irq_vector[irq]
 
-/*
- * Various low-level irq details needed by irq.c, process.c,
- * time.c, io_apic.c and smp.c
- *
- * Interrupt entry/exit code at both C and assembly level
- */
+extern void (*interrupt[NR_IRQS])(void);
+
+#ifdef CONFIG_SMP
+extern asmlinkage void reschedule_interrupt(void);
+extern asmlinkage void invalidate_interrupt(void);
+extern asmlinkage void call_function_interrupt(void);
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+extern asmlinkage void apic_timer_interrupt(void);
+extern asmlinkage void error_interrupt(void);
+extern asmlinkage void spurious_interrupt(void);
+#endif
 
 extern void mask_irq(unsigned int irq);
 extern void unmask_irq(unsigned int irq);
@@ -93,92 +64,6 @@
 
 #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 
-#define __STR(x) #x
-#define STR(x) __STR(x)
-
-#define GET_THREAD_INFO \
-	"movl $-8192, %ebx\n\t" \
-	"andl %esp, %ebx\n\t"
-
-#ifdef CONFIG_PREEMPT
-#define BUMP_LOCK_COUNT \
-	GET_THREAD_INFO \
-	"incl 16(%ebx)\n\t"
-#else
-#define BUMP_LOCK_COUNT
-#endif
-
-#define SAVE_ALL \
-	"cld\n\t" \
-	"pushl %es\n\t" \
-	"pushl %ds\n\t" \
-	"pushl %eax\n\t" \
-	"pushl %ebp\n\t" \
-	"pushl %edi\n\t" \
-	"pushl %esi\n\t" \
-	"pushl %edx\n\t" \
-	"pushl %ecx\n\t" \
-	"pushl %ebx\n\t" \
-	"movl $" STR(__KERNEL_DS) ",%edx\n\t" \
-	"movl %edx,%ds\n\t" \
-	"movl %edx,%es\n\t" \
-	BUMP_LOCK_COUNT
-
-#define IRQ_NAME2(nr) nr##_interrupt(void)
-#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
-
-#define GET_CURRENT \
-	"movl %esp, %ebx\n\t" \
-	"andl $-8192, %ebx\n\t" \
-	"movl (%ebx),%ebx\n\t"
-
-/*
- *	SMP has a few special interrupts for IPI messages
- */
-
-	/* there is a second layer of macro just to get the symbolic
-	   name for the vector evaluated. This change is for RTLinux */
-#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
-#define XBUILD_SMP_INTERRUPT(x,v)\
-asmlinkage void x(void); \
-asmlinkage void call_##x(void); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(x) ":\n\t" \
-	"pushl $"#v"-256\n\t" \
-	SAVE_ALL \
-	SYMBOL_NAME_STR(call_##x)":\n\t" \
-	"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
-	"jmp ret_from_intr\n");
-
-#define BUILD_COMMON_IRQ() \
-asmlinkage void call_do_IRQ(void); \
-__asm__( \
-	"\n" __ALIGN_STR"\n" \
-	"common_interrupt:\n\t" \
-	SAVE_ALL \
-	SYMBOL_NAME_STR(call_do_IRQ)":\n\t" \
-	"call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \
-	"jmp ret_from_intr\n");
-
-/* 
- * subtle. orig_eax is used by the signal code to distinct between
- * system calls and interrupted 'random user-space'. Thus we have
- * to put a negative value into orig_eax here. (the problem is that
- * both system calls and IRQs want to have small integer numbers in
- * orig_eax, and the syscall code has won the optimization conflict ;)
- *
- * Subtle as a pigs ear.  VY
- */
-
-#define BUILD_IRQ(nr) \
-asmlinkage void IRQ_NAME(nr); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
-	"pushl $"#nr"-256\n\t" \
-	"jmp common_interrupt");
-
 extern unsigned long prof_cpu_mask;
 extern unsigned int * prof_buffer;
 extern unsigned long prof_len;
diff -urN linux-2.5.8-pre2/include/asm-i386/irq.h linux-2.5.8-pre3/include/asm-i386/irq.h
--- linux-2.5.8-pre2/include/asm-i386/irq.h	Tue Apr  9 18:35:11 2002
+++ linux-2.5.8-pre3/include/asm-i386/irq.h	Tue Apr  9 18:35:25 2002
@@ -12,23 +12,7 @@
 
 #include <linux/config.h>
 #include <linux/sched.h>
-
-#define TIMER_IRQ 0
-
-/*
- * 16 8259A IRQ's, 208 potential APIC interrupt sources.
- * Right now the APIC is mostly only used for SMP.
- * 256 vectors is an architectural limit. (we can have
- * more than 256 devices theoretically, but they will
- * have to use shared interrupts)
- * Since vectors 0x00-0x1f are used/reserved for the CPU,
- * the usable vector space is 0x20-0xff (224 vectors)
- */
-#ifdef CONFIG_X86_IO_APIC
-#define NR_IRQS 224
-#else
-#define NR_IRQS 16
-#endif
+#include <asm/irq_vectors.h>
 
 static __inline__ int irq_cannonicalize(int irq)
 {
diff -urN linux-2.5.8-pre2/include/asm-i386/irq_vectors.h linux-2.5.8-pre3/include/asm-i386/irq_vectors.h
--- linux-2.5.8-pre2/include/asm-i386/irq_vectors.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-i386/irq_vectors.h	Tue Apr  9 18:35:25 2002
@@ -0,0 +1,64 @@
+#ifndef _ASM_IRQ_VECTORS_H
+#define _ASM_IRQ_VECTORS_H
+
+/*
+ * IDT vectors usable for external interrupt sources start
+ * at 0x20:
+ */
+#define FIRST_EXTERNAL_VECTOR	0x20
+
+#define SYSCALL_VECTOR		0x80
+
+/*
+ * Vectors 0x20-0x2f are used for ISA interrupts.
+ */
+
+/*
+ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
+ *
+ *  some of the following vectors are 'rare', they are merged
+ *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.
+ *
+ *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
+ */
+#define SPURIOUS_APIC_VECTOR	0xff
+#define ERROR_APIC_VECTOR	0xfe
+#define INVALIDATE_TLB_VECTOR	0xfd
+#define RESCHEDULE_VECTOR	0xfc
+#define CALL_FUNCTION_VECTOR	0xfb
+
+#define THERMAL_APIC_VECTOR	0xf0
+/*
+ * Local APIC timer IRQ vector is on a different priority level,
+ * to work around the 'lost local interrupt if more than 2 IRQ
+ * sources per level' errata.
+ */
+#define LOCAL_TIMER_VECTOR	0xef
+
+/*
+ * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * we start at 0x31 to spread out vectors evenly between priority
+ * levels. (0x80 is the syscall vector)
+ */
+#define FIRST_DEVICE_VECTOR	0x31
+#define FIRST_SYSTEM_VECTOR	0xef
+
+#define TIMER_IRQ 0
+
+/*
+ * 16 8259A IRQ's, 208 potential APIC interrupt sources.
+ * Right now the APIC is mostly only used for SMP.
+ * 256 vectors is an architectural limit. (we can have
+ * more than 256 devices theoretically, but they will
+ * have to use shared interrupts)
+ * Since vectors 0x00-0x1f are used/reserved for the CPU,
+ * the usable vector space is 0x20-0xff (224 vectors)
+ */
+#ifdef CONFIG_X86_IO_APIC
+#define NR_IRQS 224
+#else
+#define NR_IRQS 16
+#endif
+
+#endif /* _ASM_IRQ_VECTORS_H */
diff -urN linux-2.5.8-pre2/include/asm-i386/percpu.h linux-2.5.8-pre3/include/asm-i386/percpu.h
--- linux-2.5.8-pre2/include/asm-i386/percpu.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-i386/percpu.h	Tue Apr  9 18:35:25 2002
@@ -0,0 +1,6 @@
+#ifndef __ARCH_I386_PERCPU__
+#define __ARCH_I386_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_I386_PERCPU__ */
diff -urN linux-2.5.8-pre2/include/asm-i386/processor.h linux-2.5.8-pre3/include/asm-i386/processor.h
--- linux-2.5.8-pre2/include/asm-i386/processor.h	Tue Apr  9 18:35:11 2002
+++ linux-2.5.8-pre3/include/asm-i386/processor.h	Tue Apr  9 18:35:25 2002
@@ -40,7 +40,7 @@
 	char	hard_math;
 	char	rfu;
        	int	cpuid_level;	/* Maximum supported CPUID level, -1=no CPUID */
-	__u32	x86_capability[NCAPINTS];
+	unsigned long	x86_capability[NCAPINTS];
 	char	x86_vendor_id[16];
 	char	x86_model_id[64];
 	int 	x86_cache_size;  /* in KB - valid for CPUS which support this
diff -urN linux-2.5.8-pre2/include/asm-i386/tlbflush.h linux-2.5.8-pre3/include/asm-i386/tlbflush.h
--- linux-2.5.8-pre2/include/asm-i386/tlbflush.h	Tue Apr  9 18:35:11 2002
+++ linux-2.5.8-pre3/include/asm-i386/tlbflush.h	Tue Apr  9 18:35:25 2002
@@ -67,6 +67,7 @@
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
  *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  *
  * ..but the i386 has somewhat limited tlb flushing capabilities,
@@ -132,6 +133,8 @@
 
 #endif
 
+#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
 {
diff -urN linux-2.5.8-pre2/include/asm-i386/unistd.h linux-2.5.8-pre3/include/asm-i386/unistd.h
--- linux-2.5.8-pre2/include/asm-i386/unistd.h	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/include/asm-i386/unistd.h	Tue Apr  9 18:35:25 2002
@@ -245,6 +245,8 @@
 #define __NR_tkill		238
 #define __NR_sendfile64		239
 #define __NR_futex		240
+#define __NR_sched_setaffinity	241
+#define __NR_sched_getaffinity	242
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
@@ -371,4 +373,12 @@
 
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_I386_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-ia64/unistd.h linux-2.5.8-pre3/include/asm-ia64/unistd.h
--- linux-2.5.8-pre2/include/asm-ia64/unistd.h	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/include/asm-ia64/unistd.h	Tue Apr  9 18:35:25 2002
@@ -325,5 +325,14 @@
 }
 
 #endif /* __KERNEL_SYSCALLS__ */
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_IA64_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-m68k/unistd.h linux-2.5.8-pre3/include/asm-m68k/unistd.h
--- linux-2.5.8-pre2/include/asm-m68k/unistd.h	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/include/asm-m68k/unistd.h	Tue Apr  9 18:35:25 2002
@@ -357,4 +357,12 @@
 
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_M68K_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-mips/unistd.h linux-2.5.8-pre3/include/asm-mips/unistd.h
--- linux-2.5.8-pre2/include/asm-mips/unistd.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/include/asm-mips/unistd.h	Tue Apr  9 18:35:26 2002
@@ -488,4 +488,12 @@
 #endif /* !defined (__KERNEL_SYSCALLS__) */
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-mips64/unistd.h linux-2.5.8-pre3/include/asm-mips64/unistd.h
--- linux-2.5.8-pre2/include/asm-mips64/unistd.h	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/include/asm-mips64/unistd.h	Tue Apr  9 18:35:26 2002
@@ -814,4 +814,12 @@
 #endif /* !defined (__KERNEL_SYSCALLS__) */
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-parisc/unistd.h linux-2.5.8-pre3/include/asm-parisc/unistd.h
--- linux-2.5.8-pre2/include/asm-parisc/unistd.h	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/include/asm-parisc/unistd.h	Tue Apr  9 18:35:26 2002
@@ -900,4 +900,12 @@
 
 #undef STR
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_PARISC_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-ppc/cacheflush.h linux-2.5.8-pre3/include/asm-ppc/cacheflush.h
--- linux-2.5.8-pre2/include/asm-ppc/cacheflush.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-ppc/cacheflush.h	Tue Apr  9 18:35:26 2002
@@ -0,0 +1,41 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * include/asm-ppc/cacheflush.h
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+#ifdef __KERNEL__
+#ifndef _PPC_CACHEFLUSH_H
+#define _PPC_CACHEFLUSH_H
+
+#include <linux/mm.h>
+
+/*
+ * No cache flushing is required when address mappings are
+ * changed, because the caches on PowerPCs are physically
+ * addressed.  -- paulus
+ * Also, when SMP we use the coherency (M) bit of the
+ * BATs and PTEs.  -- Cort
+ */
+#define flush_cache_all()		do { } while (0)
+#define flush_cache_mm(mm)		do { } while (0)
+#define flush_cache_range(vma, a, b)	do { } while (0)
+#define flush_cache_page(vma, p)	do { } while (0)
+#define flush_page_to_ram(page)		do { } while (0)
+
+extern void flush_dcache_page(struct page *page);
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+extern void flush_icache_range(unsigned long, unsigned long);
+extern void flush_icache_user_range(struct vm_area_struct *vma,
+		struct page *page, unsigned long addr, int len);
+
+extern void __flush_dcache_icache(void *page_va);
+extern void __flush_dcache_icache_phys(unsigned long physaddr);
+
+#endif _PPC_CACHEFLUSH_H
+#endif __KERNEL__
diff -urN linux-2.5.8-pre2/include/asm-ppc/highmem.h linux-2.5.8-pre3/include/asm-ppc/highmem.h
--- linux-2.5.8-pre2/include/asm-ppc/highmem.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/include/asm-ppc/highmem.h	Tue Apr  9 18:35:26 2002
@@ -28,7 +28,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/kmap_types.h>
-#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
 
 /* undef for production */
 #define HIGHMEM_DEBUG 1
diff -urN linux-2.5.8-pre2/include/asm-ppc/percpu.h linux-2.5.8-pre3/include/asm-ppc/percpu.h
--- linux-2.5.8-pre2/include/asm-ppc/percpu.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-ppc/percpu.h	Tue Apr  9 18:35:26 2002
@@ -0,0 +1,6 @@
+#ifndef __ARCH_PPC_PERCPU__
+#define __ARCH_PPC_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_PPC_PERCPU__ */
diff -urN linux-2.5.8-pre2/include/asm-ppc/pgalloc.h linux-2.5.8-pre3/include/asm-ppc/pgalloc.h
--- linux-2.5.8-pre2/include/asm-ppc/pgalloc.h	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/include/asm-ppc/pgalloc.h	Tue Apr  9 18:35:26 2002
@@ -7,24 +7,12 @@
 
 #include <linux/config.h>
 #include <linux/threads.h>
-#include <linux/highmem.h>
 #include <asm/processor.h>
 
 extern void __bad_pte(pmd_t *pmd);
 
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
-{
-	pgd_t *ret;
-
-	if ((ret = (pgd_t *)__get_free_page(GFP_KERNEL)) != NULL)
-		clear_page(ret);
-	return ret;
-}
-
-extern __inline__ void pgd_free(pgd_t *pgd)
-{
-	free_page((unsigned long)pgd);
-}
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+extern void pgd_free(pgd_t *pgd);
 
 /*
  * We don't have any real pmd's, and this code never triggers because
@@ -34,64 +22,17 @@
 #define pmd_free(x)                     do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
 
-static inline pte_t *
-pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
-	pte_t *pte;
-	extern int mem_init_done;
-	extern void *early_get_page(void);
-	int timeout = 0;
-
-	if (mem_init_done) {
-		while ((pte = (pte_t *) __get_free_page(GFP_KERNEL)) == NULL
-		       && ++timeout < 10) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ);
-		}
-	} else
-		pte = (pte_t *) early_get_page();
-	if (pte != NULL)
-		clear_page(pte);
-	return pte;
-}
-
-static inline struct page *
-pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
-	struct page *pte;
-	int timeout = 0;
-#ifdef CONFIG_HIGHPTE
-	int flags = GFP_KERNEL | __GFP_HIGHMEM;
-#else
-	int flags = GFP_KERNEL;
-#endif
-
-	while ((pte = alloc_pages(flags, 0)) == NULL) {
-		if (++timeout >= 10)
-			return NULL;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ);
-	}
-	clear_highpage(pte);
-	return pte;
-}
-
-static inline void pte_free_kernel(pte_t *pte)
-{
-	free_page((unsigned long)pte);
-}
-
-static inline void pte_free(struct page *pte)
-{
-	__free_page(pte);
-}
-
 #define pmd_populate_kernel(mm, pmd, pte)	\
 		(pmd_val(*(pmd)) = __pa(pte))
 #define pmd_populate(mm, pmd, pte)	\
 		(pmd_val(*(pmd)) = ((pte) - mem_map) << PAGE_SHIFT)
 
-extern int do_check_pgt_cache(int, int);
+extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
+extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
+extern void pte_free_kernel(pte_t *pte);
+extern void pte_free(struct page *pte);
+
+#define check_pgt_cache()	do { } while (0)
 
 #endif /* _PPC_PGALLOC_H */
 #endif /* __KERNEL__ */
diff -urN linux-2.5.8-pre2/include/asm-ppc/pgtable.h linux-2.5.8-pre3/include/asm-ppc/pgtable.h
--- linux-2.5.8-pre2/include/asm-ppc/pgtable.h	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/include/asm-ppc/pgtable.h	Tue Apr  9 18:35:26 2002
@@ -13,95 +13,6 @@
 #include <asm/processor.h>		/* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
-#include <asm/kmap_types.h>
-
-extern void _tlbie(unsigned long address);
-extern void _tlbia(void);
-
-#if defined(CONFIG_4xx)
-#define __tlbia()	asm volatile ("tlbia; sync" : : : "memory")
-
-static inline void local_flush_tlb_all(void)
-	{ __tlbia(); }
-static inline void local_flush_tlb_mm(struct mm_struct *mm)
-	{ __tlbia(); }
-static inline void local_flush_tlb_page(struct vm_area_struct *vma,
-				unsigned long vmaddr)
-	{ _tlbie(vmaddr); }
-static inline void local_flush_tlb_range(struct mm_struct *mm,
-				unsigned long start, unsigned long end)
-	{ __tlbia(); }
-#define update_mmu_cache(vma, addr, pte)	do { } while (0)
-
-#elif defined(CONFIG_8xx)
-#define __tlbia()	asm volatile ("tlbia; sync" : : : "memory")
-
-static inline void local_flush_tlb_all(void)
-	{ __tlbia(); }
-static inline void local_flush_tlb_mm(struct mm_struct *mm)
-	{ __tlbia(); }
-static inline void local_flush_tlb_page(struct vm_area_struct *vma,
-				unsigned long vmaddr)
-	{ _tlbie(vmaddr); }
-static inline void local_flush_tlb_range(struct mm_struct *mm,
-				unsigned long start, unsigned long end)
-	{ __tlbia(); }
-#define update_mmu_cache(vma, addr, pte)	do { } while (0)
-
-#else	/* 6xx, 7xx, 7xxx cpus */
-struct mm_struct;
-struct vm_area_struct;
-extern void local_flush_tlb_all(void);
-extern void local_flush_tlb_mm(struct mm_struct *mm);
-extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-			    unsigned long end);
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to put a corresponding HPTE into the hash table
- * ahead of time, instead of waiting for the inevitable extra
- * hash-table miss exception.
- */
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-#endif
-
-#define flush_tlb_all local_flush_tlb_all
-#define flush_tlb_mm local_flush_tlb_mm
-#define flush_tlb_page local_flush_tlb_page
-#define flush_tlb_range local_flush_tlb_range
-
-/*
- * This is called in munmap when we have freed up some page-table
- * pages.  We don't need to do anything here, there's nothing special
- * about our page-table pages.  -- paulus
- */
-static inline void flush_tlb_pgtables(struct mm_struct *mm,
-				      unsigned long start, unsigned long end)
-{
-}
-
-/*
- * No cache flushing is required when address mappings are
- * changed, because the caches on PowerPCs are physically
- * addressed.  -- paulus
- * Also, when SMP we use the coherency (M) bit of the
- * BATs and PTEs.  -- Cort
- */
-#define flush_cache_all()		do { } while (0)
-#define flush_cache_mm(mm)		do { } while (0)
-#define flush_cache_range(vma, a, b)	do { } while (0)
-#define flush_cache_page(vma, p)	do { } while (0)
-#define flush_page_to_ram(page)		do { } while (0)
-
-extern void flush_icache_user_range(struct vm_area_struct *vma,
-		struct page *page, unsigned long addr, int len);
-extern void flush_icache_range(unsigned long, unsigned long);
-extern void __flush_dcache_icache(void *page_va);
-extern void __flush_dcache_icache_phys(unsigned long physaddr);
-extern void flush_dcache_page(struct page *page);
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
 
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(unsigned long address);
diff -urN linux-2.5.8-pre2/include/asm-ppc/thread_info.h linux-2.5.8-pre3/include/asm-ppc/thread_info.h
--- linux-2.5.8-pre2/include/asm-ppc/thread_info.h	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/include/asm-ppc/thread_info.h	Tue Apr  9 18:35:26 2002
@@ -68,6 +68,8 @@
 #define TI_FLAGS	8
 #define TI_CPU		12
 
+#define PREEMPT_ACTIVE		0x4000000
+
 /*
  * thread information flag bit numbers
  */
diff -urN linux-2.5.8-pre2/include/asm-ppc/tlbflush.h linux-2.5.8-pre3/include/asm-ppc/tlbflush.h
--- linux-2.5.8-pre2/include/asm-ppc/tlbflush.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-ppc/tlbflush.h	Tue Apr  9 18:35:26 2002
@@ -0,0 +1,88 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * include/asm-ppc/tlbflush.h
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+#ifdef __KERNEL__
+#ifndef _PPC_TLBFLUSH_H
+#define _PPC_TLBFLUSH_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <asm/processor.h>
+
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+#if defined(CONFIG_4xx)
+#define __tlbia()	asm volatile ("tlbia; sync" : : : "memory")
+
+static inline void local_flush_tlb_all(void)
+	{ __tlbia(); }
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+	{ __tlbia(); }
+static inline void local_flush_tlb_page(struct vm_area_struct *vma,
+				unsigned long vmaddr)
+	{ _tlbie(vmaddr); }
+static inline void local_flush_tlb_range(struct mm_struct *mm,
+				unsigned long start, unsigned long end)
+	{ __tlbia(); }
+#define update_mmu_cache(vma, addr, pte)	do { } while (0)
+
+#elif defined(CONFIG_8xx)
+#define __tlbia()	asm volatile ("tlbia; sync" : : : "memory")
+
+static inline void local_flush_tlb_all(void)
+	{ __tlbia(); }
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
+	{ __tlbia(); }
+static inline void local_flush_tlb_page(struct vm_area_struct *vma,
+				unsigned long vmaddr)
+	{ _tlbie(vmaddr); }
+static inline void local_flush_tlb_range(struct mm_struct *mm,
+				unsigned long start, unsigned long end)
+	{ __tlbia(); }
+#define update_mmu_cache(vma, addr, pte)	do { } while (0)
+
+#else	/* 6xx, 7xx, 7xxx cpus */
+struct mm_struct;
+struct vm_area_struct;
+extern void local_flush_tlb_all(void);
+extern void local_flush_tlb_mm(struct mm_struct *mm);
+extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+			    unsigned long end);
+
+/*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to put a corresponding HPTE into the hash table
+ * ahead of time, instead of waiting for the inevitable extra
+ * hash-table miss exception.
+ */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+#endif
+
+#define flush_tlb_all local_flush_tlb_all
+#define flush_tlb_mm local_flush_tlb_mm
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_range local_flush_tlb_range
+
+/*
+ * This is called in munmap when we have freed up some page-table
+ * pages.  We don't need to do anything here, there's nothing special
+ * about our page-table pages.  -- paulus
+ */
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+}
+
+#endif _PPC_TLBFLUSH_H
+#endif __KERNEL__
diff -urN linux-2.5.8-pre2/include/asm-ppc/unistd.h linux-2.5.8-pre3/include/asm-ppc/unistd.h
--- linux-2.5.8-pre2/include/asm-ppc/unistd.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/include/asm-ppc/unistd.h	Tue Apr  9 18:35:26 2002
@@ -437,4 +437,12 @@
 
 #endif /* __KERNEL_SYSCALLS__ */
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_PPC_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/Paca.h linux-2.5.8-pre3/include/asm-ppc64/Paca.h
--- linux-2.5.8-pre2/include/asm-ppc64/Paca.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/Paca.h	Tue Apr  9 18:35:26 2002
@@ -92,10 +92,10 @@
  * CACHE_LINE_2 0x0080 - 0x00FF
  *=====================================================================================
  */
-	u64 *pgd_cache;			/*					0x00 */
-	u64 *pmd_cache;			/*					0x08 */
-	u64 *pte_cache;			/*					0x10 */
-	u64 pgtable_cache_sz;		/*					0x18 */
+	u64 spare1;			/*					0x00 */
+	u64 spare2;			/*					0x08 */
+	u64 spare3;			/*					0x10 */
+	u64 spare4;		/*					0x18 */
 	u64 next_jiffy_update_tb;	/* TB value for next jiffy update	0x20 */
 	u32 lpEvent_count;		/* lpEvents processed			0x28 */
 	u32 prof_multiplier;		/*					0x2C */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/abs_addr.h linux-2.5.8-pre3/include/asm-ppc64/abs_addr.h
--- linux-2.5.8-pre2/include/asm-ppc64/abs_addr.h	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/abs_addr.h	Tue Apr  9 18:35:26 2002
@@ -103,7 +103,7 @@
 #define physRpn_to_absRpn(rpn) (rpn)
 #define absolute_to_phys(aa) (aa)
 
-#endif /* CONFIG_MSCHUNKS */
+#endif /* !CONFIG_MSCHUNKS */
 
 
 static inline unsigned long
diff -urN linux-2.5.8-pre2/include/asm-ppc64/cacheflush.h linux-2.5.8-pre3/include/asm-ppc64/cacheflush.h
--- linux-2.5.8-pre2/include/asm-ppc64/cacheflush.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-ppc64/cacheflush.h	Tue Apr  9 18:35:26 2002
@@ -0,0 +1,26 @@
+#ifndef _PPC64_CACHEFLUSH_H
+#define _PPC64_CACHEFLUSH_H
+
+/* Keep includes the same across arches.  */
+#include <linux/mm.h>
+
+/*
+ * No cache flushing is required when address mappings are
+ * changed, because the caches on PowerPCs are physically
+ * addressed.
+ */
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
+#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
+
+extern void flush_dcache_page(struct page *page);
+extern void flush_icache_range(unsigned long, unsigned long);
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+extern void flush_icache_user_range(struct vm_area_struct *vma,
+				    struct page *page, unsigned long addr,
+				    int len);
+extern void __flush_dcache_icache(void *page_va);
+
+#endif /* _PPC64_CACHEFLUSH_H */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/floppy.h linux-2.5.8-pre3/include/asm-ppc64/floppy.h
--- linux-2.5.8-pre2/include/asm-ppc64/floppy.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/floppy.h	Tue Apr  9 18:35:26 2002
@@ -36,8 +36,6 @@
 
 #define fd_dma_setup(addr,size,mode,io) ppc64_fd_dma_setup(addr,size,mode,io)
 
-extern struct pci_dev *ppc64_floppy_dev;
-
 static __inline__ int 
 ppc64_fd_dma_setup(char *addr, unsigned long size, int mode, int io)
 {
@@ -52,12 +50,12 @@
 	if (bus_addr 
 	    && (addr != prev_addr || size != prev_size || dir != prev_dir)) {
 		/* different from last time -- unmap prev */
-		pci_unmap_single(ppc64_floppy_dev, bus_addr, prev_size, prev_dir);
+		pci_unmap_single(NULL, bus_addr, prev_size, prev_dir);
 		bus_addr = 0;
 	}
 
 	if (!bus_addr)	/* need to map it */ {
-		bus_addr = pci_map_single(ppc64_floppy_dev, addr, size, dir);
+		bus_addr = pci_map_single(NULL, addr, size, dir);
 	}
 
 	/* remember this one as prev */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/hw_irq.h linux-2.5.8-pre3/include/asm-ppc64/hw_irq.h
--- linux-2.5.8-pre2/include/asm-ppc64/hw_irq.h	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/hw_irq.h	Tue Apr  9 18:35:26 2002
@@ -35,13 +35,13 @@
 #else
 
 #define __save_flags(flags)	((flags) = mfmsr())
-#define __restore_flags(flags)	mtmsrd(flags)
+#define __restore_flags(flags)	__mtmsrd((flags), 1)
 
 static inline void __cli(void)
 {
 	unsigned long msr;
 	msr = mfmsr();
-	mtmsrd(msr & ~MSR_EE);
+	__mtmsrd(msr & ~MSR_EE, 1);
 	__asm__ __volatile__("": : :"memory");
 }
 
@@ -50,7 +50,7 @@
 	unsigned long msr;
 	__asm__ __volatile__("": : :"memory");
 	msr = mfmsr();
-	mtmsrd(msr | MSR_EE);
+	__mtmsrd(msr | MSR_EE, 1);
 }
 
 static inline void __do_save_and_cli(unsigned long *flags)
@@ -58,7 +58,7 @@
 	unsigned long msr;
 	msr = mfmsr();
 	*flags = msr;
-	mtmsrd(msr & ~MSR_EE);
+	__mtmsrd(msr & ~MSR_EE, 1);
 	__asm__ __volatile__("": : :"memory");
 }
 
diff -urN linux-2.5.8-pre2/include/asm-ppc64/iSeries/HvCallPci.h linux-2.5.8-pre3/include/asm-ppc64/iSeries/HvCallPci.h
--- linux-2.5.8-pre2/include/asm-ppc64/iSeries/HvCallPci.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/iSeries/HvCallPci.h	Tue Apr  9 18:35:26 2002
@@ -97,6 +97,8 @@
 	struct HvCallPci_BusUnitInfo busUnitInfo;  // Generic bus unit info
 	u8		subBusNumber;		// Bus number of secondary bus
 	u8		maxAgents;		// Max idsels on secondary bus
+        u8              maxSubBusNumber;        // Max Sub Bus
+	u8		logicalSlotNumber;	// Logical Slot Number for IOA 
 };
     
 
diff -urN linux-2.5.8-pre2/include/asm-ppc64/linux_logo.h linux-2.5.8-pre3/include/asm-ppc64/linux_logo.h
--- linux-2.5.8-pre2/include/asm-ppc64/linux_logo.h	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/linux_logo.h	Tue Apr  9 18:35:26 2002
@@ -22,25 +22,5 @@
 
 #define LINUX_LOGO_HEIGHT	80
 #define LINUX_LOGO_WIDTH	80
-#define LINUX_LOGO_COLORS	214
 
-#ifdef INCLUDE_LINUX_LOGO_DATA
-
-#define INCLUDE_LINUX_LOGOBW
-#define INCLUDE_LINUX_LOGO16
 #include <linux/linux_logo.h>
-
-#else
-
-/* prototypes only */
-extern unsigned char linux_logo_red[];
-extern unsigned char linux_logo_green[];
-extern unsigned char linux_logo_blue[];
-extern unsigned char linux_logo[];
-extern unsigned char linux_logo_bw[];
-extern unsigned char linux_logo16_red[];
-extern unsigned char linux_logo16_green[];
-extern unsigned char linux_logo16_blue[];
-extern unsigned char linux_logo16[];
-
-#endif
diff -urN linux-2.5.8-pre2/include/asm-ppc64/lmb.h linux-2.5.8-pre3/include/asm-ppc64/lmb.h
--- linux-2.5.8-pre2/include/asm-ppc64/lmb.h	Mon Mar 18 12:37:09 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/lmb.h	Tue Apr  9 18:35:26 2002
@@ -17,7 +17,7 @@
 
 extern unsigned long reloc_offset(void);
 
-#define MAX_LMB_REGIONS 32
+#define MAX_LMB_REGIONS 64
 
 union lmb_reg_property { 
 	struct reg_property32 addr32[MAX_LMB_REGIONS];
@@ -37,6 +37,7 @@
 struct lmb_region {
 	unsigned long cnt;
 	unsigned long size;
+	unsigned long iosize;
 	unsigned long lcd_size;		/* Least Common Denominator */
 	struct lmb_property region[MAX_LMB_REGIONS+1];
 };
@@ -52,7 +53,9 @@
 extern void lmb_init(void);
 extern void lmb_analyze(void);
 extern long lmb_add(unsigned long, unsigned long);
+#ifdef CONFIG_MSCHUNKS
 extern long lmb_add_io(unsigned long base, unsigned long size);
+#endif /* CONFIG_MSCHUNKS */
 extern long lmb_reserve(unsigned long, unsigned long);
 extern unsigned long lmb_alloc(unsigned long, unsigned long);
 extern unsigned long lmb_phys_mem_size(void);
diff -urN linux-2.5.8-pre2/include/asm-ppc64/machdep.h linux-2.5.8-pre3/include/asm-ppc64/machdep.h
--- linux-2.5.8-pre2/include/asm-ppc64/machdep.h	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/machdep.h	Tue Apr  9 18:35:26 2002
@@ -24,26 +24,33 @@
 	/* High use functions in the first cachelines, low use functions
 	 * follow.  DRENG collect profile data.
 	 */
-	void            (*hpte_invalidate)(unsigned long slot);
-
-	void            (*hpte_updatepp)(long slot, 
+	void            (*hpte_invalidate)(unsigned long slot,
+					   unsigned long va,
+					   int large,
+					   int local);
+	long		(*hpte_updatepp)(unsigned long slot, 
 					 unsigned long newpp, 
-					 unsigned long va);
+					 unsigned long va,
+					 int large);
 	void            (*hpte_updateboltedpp)(unsigned long newpp, 
 					       unsigned long ea);
-	unsigned long	(*hpte_getword0)(unsigned long slot);
-
-	long		(*hpte_find)( unsigned long vpn );
-
-	long		(*hpte_selectslot)(unsigned long vpn); 
+	long		(*insert_hpte)(unsigned long hpte_group,
+				       unsigned long vpn,
+				       unsigned long prpn,
+				       int secondary, 
+				       unsigned long hpteflags, 
+				       int bolted,
+				       int large);
+	long		(*remove_hpte)(unsigned long hpte_group);
+	void		(*flush_hash_range)(unsigned long context,
+					    unsigned long number,
+					    int local);
+	void		(*make_pte)(void *htab, unsigned long va,
+				    unsigned long pa,
+				    int mode,
+				    unsigned long hash_mask,
+				    int large);
 
-	void		(*hpte_create_valid)(unsigned long slot,
-					     unsigned long vpn,
-					     unsigned long prpn,
-					     unsigned hash, 
-					     void * ptep,
-					     unsigned hpteflags, 
-					     unsigned bolted);
 	void		(*tce_build)(struct TceTable * tbl,
 				     long tcenum,
 				     unsigned long uaddr,
@@ -148,17 +155,5 @@
 
 extern void setup_pci_ptrs(void);
 
-/*
- * Power macintoshes have either a CUDA or a PMU controlling
- * system reset, power, NVRAM, RTC.
- */
-typedef enum sys_ctrler_kind {
-	SYS_CTRLER_UNKNOWN = 0,
-	SYS_CTRLER_CUDA = 1,
-	SYS_CTRLER_PMU = 2,
-} sys_ctrler_t;
-
-extern sys_ctrler_t sys_ctrler;
-
 #endif /* _PPC_MACHDEP_H */
 #endif /* __KERNEL__ */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/mman.h linux-2.5.8-pre3/include/asm-ppc64/mman.h
--- linux-2.5.8-pre2/include/asm-ppc64/mman.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/mman.h	Tue Apr  9 18:35:26 2002
@@ -11,6 +11,7 @@
 #define PROT_READ	0x1		/* page can be read */
 #define PROT_WRITE	0x2		/* page can be written */
 #define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_SEM	0x8		/* page may be used for atomic ops */
 #define PROT_NONE	0x0		/* page can not be accessed */
 
 #define MAP_SHARED	0x01		/* Share changes */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/mmu.h linux-2.5.8-pre3/include/asm-ppc64/mmu.h
--- linux-2.5.8-pre2/include/asm-ppc64/mmu.h	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/mmu.h	Tue Apr  9 18:35:26 2002
@@ -77,7 +77,7 @@
 	unsigned long resv0: 7; /* Padding to a 64b boundary */
 } slb_dword1;
 
-typedef struct _SLBE {
+typedef struct {
 	union {
 		unsigned long dword0;
 		slb_dword0    dw0;
@@ -107,26 +107,13 @@
 	unsigned long avpn:57; /* vsid | api == avpn  */
 	unsigned long :     2; /* Software use */
 	unsigned long bolted: 1; /* HPTE is "bolted" */
-	unsigned long :     1; /* Software use */
-	unsigned long :     1; /* Reserved */
+	unsigned long lock: 1; /* lock on pSeries SMP */
+	unsigned long l:    1; /* Virtual page is large (L=1) or 4 KB (L=0) */
 	unsigned long h:    1; /* Hash function identifier */
 	unsigned long v:    1; /* Valid (v=1) or invalid (v=0) */
 } Hpte_dword0;
 
 typedef struct {
-	unsigned long :     6; /* unused - padding */
-	unsigned long ac:   1; /* Address compare */
-	unsigned long r:    1; /* Referenced */
-	unsigned long c:    1; /* Changed */
-	unsigned long w:	1; /* Write-thru cache mode */
-	unsigned long i:	1; /* Cache inhibited */
-	unsigned long m:	1; /* Memory coherence required */
-	unsigned long g:	1; /* Guarded */
-	unsigned long n:	1; /* No-execute */
-	unsigned long pp:   2; /* Page protection bits 1:2 */
-} Hpte_flags;
-
-typedef struct {
 	unsigned long pp0:  1; /* Page protection bit 0 */
 	unsigned long :     1; /* Reserved */
 	unsigned long rpn: 50; /* Real page number */
@@ -134,12 +121,12 @@
 	unsigned long ac:   1; /* Address compare */ 
 	unsigned long r:    1; /* Referenced */
 	unsigned long c:    1; /* Changed */
-	unsigned long w:	1; /* Write-thru cache mode */
-	unsigned long i:	1; /* Cache inhibited */
-	unsigned long m:	1; /* Memory coherence required */
-	unsigned long g:	1; /* Guarded */
-	unsigned long n:	1; /* No-execute */
-	unsigned long pp:	2; /* Page protection bits 1:2 */
+	unsigned long w:    1; /* Write-thru cache mode */
+	unsigned long i:    1; /* Cache inhibited */
+	unsigned long m:    1; /* Memory coherence required */
+	unsigned long g:    1; /* Guarded */
+	unsigned long n:    1; /* No-execute */
+	unsigned long pp:   2; /* Page protection bits 1:2 */
 } Hpte_dword1;
 
 typedef struct {
@@ -148,7 +135,7 @@
 	unsigned long flags: 10;	/* HPTE flags */
 } Hpte_dword1_flags;
 
-typedef struct _HPTE {
+typedef struct {
 	union {
 		unsigned long dword0;
 		Hpte_dword0   dw0;
@@ -156,21 +143,8 @@
 
 	union {
 		unsigned long dword1;
-		struct {
-			unsigned long pp0:  1; /* Page protection bit 0 */
-			unsigned long ts:   1; /* Tag set bit */ 
-			unsigned long rpn: 50; /* Real page number */
-			unsigned long :     2; /* Unused */
-			unsigned long ac:   1; /* Address compare bit */
-			unsigned long r:    1; /* Referenced */
-			unsigned long c:    1; /* Changed */
-			unsigned long w:    1; /* Write-thru cache mode */
-			unsigned long i:    1; /* Cache inhibited */
-			unsigned long m:    1; /* Memory coherence */
-			unsigned long g:    1; /* Guarded */
-			unsigned long n:    1; /* No-execute page if N=1 */
-			unsigned long pp:   2; /* Page protection bit 1:2 */
-		} dw1;
+		Hpte_dword1 dw1;
+		Hpte_dword1_flags flags;
 	} dw1;
 } HPTE; 
 
@@ -204,6 +178,8 @@
 #define PT_SHIFT (12)			/* Page Table */
 #define PT_MASK  0x02FF
 
+#define LARGE_PAGE_SHIFT 24
+
 static inline unsigned long hpt_hash(unsigned long vpn, int large)
 {
 	unsigned long vsid;
@@ -220,20 +196,36 @@
 	return (vsid & 0x7fffffffff) ^ page;
 }
 
-#define PG_SHIFT (12)			/* Page Entry */
+static inline void _tlbie(unsigned long va, int large)
+{
+	asm volatile("ptesync": : :"memory");
 
-extern __inline__ void _tlbie( unsigned long va )
+	if (large) {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbie	%0,1" : : "r"(va) : "memory");
+	} else {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbie	%0,0" : : "r"(va) : "memory");
+	}
+
+	asm volatile("eieio; tlbsync; ptesync": : :"memory");
+}
+
+static inline void _tlbiel(unsigned long va, int large)
 {
-	__asm__ __volatile__ ( " \n\
-		clrldi	%0,%0,16 \n\
-		ptesync		 \n\
-		tlbie	%0	 \n\
-		eieio		 \n\
-		tlbsync		 \n\
-		ptesync"
-		: : "r" (va) : "memory" );
+	asm volatile("ptesync": : :"memory");
+
+	if (large) {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbiel	%0,1" : : "r"(va) : "memory");
+	} else {
+		asm volatile("clrldi	%0,%0,16\n\
+			      tlbiel	%0,0" : : "r"(va) : "memory");
+	}
+
+	asm volatile("ptesync": : :"memory");
 }
- 
+
 #endif /* __ASSEMBLY__ */
 
 /* Block size masks */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/mmu_context.h linux-2.5.8-pre3/include/asm-ppc64/mmu_context.h
--- linux-2.5.8-pre2/include/asm-ppc64/mmu_context.h	Mon Mar 18 12:37:12 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/mmu_context.h	Tue Apr  9 18:35:26 2002
@@ -60,8 +60,6 @@
 {
 }
 
-extern void flush_stab(void);
-
 /*
  * The context number queue has underflowed.
  * Meaning: we tried to push a context number that was freed
@@ -133,6 +131,7 @@
 	spin_unlock( &mmu_context_queue.lock );
 }
 
+extern void flush_stab(struct task_struct *tsk, struct mm_struct *mm);
 
 /*
  * switch_mm is the entry point called from the architecture independent
@@ -142,22 +141,16 @@
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	  struct task_struct *tsk, int cpu)
 {
-	tsk->thread.pgdir = next->pgd;	/* cache the pgdir in the thread 
-					   maybe not needed any more */
-	flush_stab();
+	flush_stab(tsk, next);
+	set_bit(cpu, &next->cpu_vm_mask);
 }
 
 /*
  * After we have set current->mm to a new value, this activates
  * the context for the new mm so we see the new mappings.
  */
-static inline void
-activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
-{
-	current->thread.pgdir = mm->pgd;
-	flush_stab();
-}
-
+#define activate_mm(active_mm, mm) \
+	switch_mm(active_mm, mm, current, smp_processor_id());
 
 #define VSID_RANDOMIZER 42470972311
 #define VSID_MASK	0xfffffffff
diff -urN linux-2.5.8-pre2/include/asm-ppc64/nvram.h linux-2.5.8-pre3/include/asm-ppc64/nvram.h
--- linux-2.5.8-pre2/include/asm-ppc64/nvram.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/nvram.h	Tue Apr  9 18:35:26 2002
@@ -36,33 +36,4 @@
 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
 #endif
 
-/* PowerMac specific nvram stuffs */
-
-enum {
-	pmac_nvram_OF,		/* Open Firmware partition */
-	pmac_nvram_XPRAM,	/* MacOS XPRAM partition */
-	pmac_nvram_NR		/* MacOS Name Registry partition */
-};
-
-/* Return partition offset in nvram */
-extern int	pmac_get_partition(int partition);
-
-/* Direct access to XPRAM */
-extern u8	pmac_xpram_read(int xpaddr);
-extern void	pmac_xpram_write(int xpaddr, u8 data);
-
-/* Some offsets in XPRAM */
-#define PMAC_XPRAM_MACHINE_LOC	0xe4
-#define PMAC_XPRAM_SOUND_VOLUME	0x08
-
-/* Machine location structure in XPRAM */
-struct pmac_machine_location {
-	u32	latitude;	/* 2+30 bit Fractional number */
-	u32	longitude;	/* 2+30 bit Fractional number */
-	u32	delta;		/* mix of GMT delta and DLS */
-};
-
-/* /dev/nvram ioctls */
-#define PMAC_NVRAM_GET_OFFSET   _IOWR('p', 0x40, int) /* Get NVRAM partition offset */
-
 #endif /* _PPC64_NVRAM_H */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/page.h linux-2.5.8-pre3/include/asm-ppc64/page.h
--- linux-2.5.8-pre2/include/asm-ppc64/page.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/page.h	Tue Apr  9 18:35:26 2002
@@ -130,6 +130,13 @@
 
 #define PAGE_BUG(page) do { BUG(); } while (0)
 
+/*
+ * XXX A bug in the current ppc64 compiler prevents an optimisation
+ * where a divide is replaced by a multiply by shifted inverse. For
+ * the moment use page->virtaul
+ */
+#define WANT_PAGE_VIRTUAL 1
+
 /* Pure 2^n version of get_order */
 extern __inline__ int get_order(unsigned long size)
 {
diff -urN linux-2.5.8-pre2/include/asm-ppc64/pgalloc.h linux-2.5.8-pre3/include/asm-ppc64/pgalloc.h
--- linux-2.5.8-pre2/include/asm-ppc64/pgalloc.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/pgalloc.h	Tue Apr  9 18:35:26 2002
@@ -12,116 +12,83 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#define quicklists      get_paca()
 
-#define pgd_quicklist 		(quicklists->pgd_cache)
-#define pmd_quicklist 		(quicklists->pmd_cache)
-#define pte_quicklist 		(quicklists->pte_cache)
-#define pgtable_cache_size 	(quicklists->pgtable_cache_sz)
-
-static inline pgd_t*
-pgd_alloc_one_fast (struct mm_struct *mm)
-{
-	unsigned long *ret = pgd_quicklist;
-
-	if (ret != NULL) {
-		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		--pgtable_cache_size;
-	} else
-		ret = NULL;
-	return (pgd_t *) ret;
-}
-
-static inline pgd_t*
-pgd_alloc (struct mm_struct *mm)
-{
-	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
-	pgd_t *pgd = pgd_alloc_one_fast(mm);
-
-	if (pgd == NULL) {
-		pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
-		if (pgd != NULL)
-			clear_page(pgd);
-	}
+static inline pgd_t *
+pgd_alloc(struct mm_struct *mm)
+{
+	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+	if (pgd != NULL)
+		clear_page(pgd);
 	return pgd;
 }
 
 static inline void
-pgd_free (pgd_t *pgd)
+pgd_free(pgd_t *pgd)
 {
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	++pgtable_cache_size;
+	free_page((unsigned long)pgd);
 }
 
 #define pgd_populate(MM, PGD, PMD)	pgd_set(PGD, PMD)
 
-static inline pmd_t*
-pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
+static inline pmd_t *
+pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	unsigned long *ret = (unsigned long *)pmd_quicklist;
-
-	if (ret != NULL) {
-		pmd_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		--pgtable_cache_size;
-	}
-	return (pmd_t *)ret;
-}
+	int count = 0;
+	pmd_t *pmd;
 
-static inline pmd_t*
-pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
-{
-	pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+	do {
+		pmd = (pmd_t *)__get_free_page(GFP_KERNEL);
+		if (pmd)
+			clear_page(pmd);
+		else {
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+	} while (!pmd && (count++ < 10));
 
-	if (pmd != NULL)
-		clear_page(pmd);
 	return pmd;
 }
 
 static inline void
-pmd_free (pmd_t *pmd)
+pmd_free(pmd_t *pmd)
 {
-	*(unsigned long *)pmd = (unsigned long) pmd_quicklist;
-	pmd_quicklist = (unsigned long *) pmd;
-	++pgtable_cache_size;
+	free_page((unsigned long)pmd);
 }
 
-#define pmd_populate(MM, PMD, PTE)	pmd_set(PMD, PTE)
+#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte)
+#define pmd_populate(mm, pmd, pte_page) \
+	pmd_populate_kernel(mm, pmd, page_address(pte_page))
+
+static inline pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
+{
+	int count = 0;
+	pte_t *pte;
+
+	do {
+		pte = (pte_t *)__get_free_page(GFP_KERNEL);
+		if (pte)
+			clear_page(pte);
+		else {
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+	} while (!pte && (count++ < 10));
 
-static inline pte_t*
-pte_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
-{
-	unsigned long *ret = (unsigned long *)pte_quicklist;
-
-	if (ret != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		--pgtable_cache_size;
-	}
-	return (pte_t *)ret;
-}
-
-
-static inline pte_t*
-pte_alloc_one (struct mm_struct *mm, unsigned long addr)
-{
-	pte_t *pte = (pte_t *) __get_free_page(GFP_KERNEL);
-
-	if (pte != NULL)
-		clear_page(pte);
 	return pte;
 }
 
+#define pte_alloc_one(mm, address) \
+	virt_to_page(pte_alloc_one_kernel((mm), (address)))
+
 static inline void
-pte_free (pte_t *pte)
+pte_free_kernel(pte_t *pte)
 {
-	*(unsigned long *)pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	++pgtable_cache_size;
+	free_page((unsigned long)pte);
 }
 
-extern int do_check_pgt_cache(int, int);
+#define pte_free(pte_page)	pte_free_kernel(page_address(pte_page))
+
+#define check_pgt_cache()	do { } while (0)
 
 #endif /* _PPC64_PGALLOC_H */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/pgtable.h linux-2.5.8-pre3/include/asm-ppc64/pgtable.h
--- linux-2.5.8-pre2/include/asm-ppc64/pgtable.h	Mon Mar 18 12:37:13 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/pgtable.h	Tue Apr  9 18:35:26 2002
@@ -7,6 +7,7 @@
  */
 
 #ifndef __ASSEMBLY__
+#include <linux/threads.h>
 #include <asm/processor.h>		/* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
@@ -93,13 +94,15 @@
 #define _PAGE_WRITETHRU	0x040UL	/* W: cache write-through */
 #define _PAGE_DIRTY	0x080UL	/* C: page changed */
 #define _PAGE_ACCESSED	0x100UL	/* R: page referenced */
+#if 0
 #define _PAGE_HPTENOIX	0x200UL /* software: pte HPTE slot unknown */
+#endif
 #define _PAGE_HASHPTE	0x400UL	/* software: pte has an associated HPTE */
 #define _PAGE_EXEC	0x800UL	/* software: i-cache coherence required */
 #define _PAGE_SECONDARY 0x8000UL /* software: HPTE is in secondary group */
 #define _PAGE_GROUP_IX  0x7000UL /* software: HPTE index within group */
 /* Bits 0x7000 identify the index within an HPT Group */
-#define _PAGE_HPTEFLAGS (_PAGE_HASHPTE | _PAGE_HPTENOIX | _PAGE_SECONDARY | _PAGE_GROUP_IX)
+#define _PAGE_HPTEFLAGS (_PAGE_HASHPTE | _PAGE_SECONDARY | _PAGE_GROUP_IX)
 /* PAGE_MASK gives the right answer below, but only by accident */
 /* It should be preserving the high 48 bits and then specifically */
 /* preserving _PAGE_SECONDARY | _PAGE_GROUP_IX */
@@ -201,7 +204,8 @@
 #define	pmd_bad(pmd)		((pmd_val(pmd)) == 0)
 #define	pmd_present(pmd)	((pmd_val(pmd)) != 0)
 #define	pmd_clear(pmdp)		(pmd_val(*(pmdp)) = 0)
-#define pmd_page(pmd)		(__bpn_to_ba(pmd_val(pmd)))
+#define pmd_page_kernel(pmd)	(__bpn_to_ba(pmd_val(pmd)))
+#define pmd_page(pmd)		virt_to_page(pmd_page_kernel(pmd))
 #define pgd_set(pgdp, pmdp)	(pgd_val(*(pgdp)) = (__ba_to_bpn(pmdp)))
 #define pgd_none(pgd)		(!pgd_val(pgd))
 #define pgd_bad(pgd)		((pgd_val(pgd)) == 0)
@@ -222,8 +226,13 @@
   ((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
 
 /* Find an entry in the third-level page table.. */
-#define pte_offset(dir,addr) \
-  ((pte_t *) pmd_page(*(dir)) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+#define pte_offset_kernel(dir,addr) \
+  ((pte_t *) pmd_page_kernel(*(dir)) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+
+#define pte_offset_map(dir,addr)	pte_offset_kernel((dir), (addr))
+#define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir), (addr))
+#define pte_unmap(pte)			do { } while(0)
+#define pte_unmap_nested(pte)		do { } while(0)
 
 /* to find an entry in a kernel page-table-directory */
 /* This now only contains the vmalloc pages */
@@ -232,12 +241,6 @@
 /* to find an entry in the ioremap page-table-directory */
 #define pgd_offset_i(address) (ioremap_pgd + pgd_index(address))
 
-/*
- * Given a pointer to an mem_map[] entry, return the kernel virtual
- * address corresponding to that page.
- */
-#define page_address(page) ((page)->virtual)
-
 #define pages_to_mb(x)		((x) >> (20-PAGE_SHIFT))
 
 /*
@@ -336,43 +339,6 @@
 	pte_update(ptep, ~_PAGE_HPTEFLAGS, 0);
 }
 
-struct mm_struct;
-struct vm_area_struct;
-extern void local_flush_tlb_all(void);
-extern void local_flush_tlb_mm(struct mm_struct *mm);
-extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void local_flush_tlb_range(struct mm_struct *mm,
-			    unsigned long start, unsigned long end);
-
-#define flush_tlb_all local_flush_tlb_all
-#define flush_tlb_mm local_flush_tlb_mm
-#define flush_tlb_page local_flush_tlb_page
-#define flush_tlb_range(vma, start, end) local_flush_tlb_range(vma->vm_mm, start, end)
-
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-				unsigned long start, unsigned long end)
-{
-	/* PPC has hw page tables. */
-}
-
-/*
- * No cache flushing is required when address mappings are
- * changed, because the caches on PowerPCs are physically
- * addressed.
- */
-#define flush_cache_all()		do { } while (0)
-#define flush_cache_mm(mm)		do { } while (0)
-#define flush_cache_range(vma, a, b)	do { } while (0)
-#define flush_cache_page(vma, p)	do { } while (0)
-#define flush_page_to_ram(page)		do { } while (0)
-
-extern void flush_icache_user_range(struct vm_area_struct *vma,
-			struct page *page, unsigned long addr, int len);
-extern void flush_icache_range(unsigned long, unsigned long);
-extern void __flush_dcache_icache(void *page_va);
-extern void flush_dcache_page(struct page *page);
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
-
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(unsigned long address);
 extern unsigned long ioremap_bot, ioremap_base;
@@ -397,6 +363,7 @@
  * as entries are faulted into the hash table by the low-level
  * data/instruction access exception handlers.
  */
+#if 0
 /*
  * We won't be able to use update_mmu_cache to update the 
  * hardware page table because we need to update the pte
@@ -404,9 +371,16 @@
  * its value.
  */
 #define update_mmu_cache(vma, addr, pte)	do { } while (0)
-
-extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid);
-extern void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte);
+#else
+/*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to put a corresponding HPTE into the hash table
+ * ahead of time, instead of waiting for the inevitable extra
+ * hash-table miss exception.
+ */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+#endif
 
 /* Encode and de-code a swap entry */
 #define SWP_TYPE(entry)			(((entry).val >> 1) & 0x3f)
diff -urN linux-2.5.8-pre2/include/asm-ppc64/ppcdebug.h linux-2.5.8-pre3/include/asm-ppc64/ppcdebug.h
--- linux-2.5.8-pre2/include/asm-ppc64/ppcdebug.h	Mon Mar 18 12:37:16 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/ppcdebug.h	Tue Apr  9 18:35:26 2002
@@ -108,4 +108,8 @@
 #define PPCDBG_ENTER_DEBUGGER() do {;} while(0)
 #endif
 
+#ifndef PPCDBG_ENTER_DEBUGGER_REGS
+#define PPCDBG_ENTER_DEBUGGER_REGS(A) do {;} while(0)
+#endif
+
 #endif /*__PPCDEBUG_H */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/processor.h linux-2.5.8-pre3/include/asm-ppc64/processor.h
--- linux-2.5.8-pre2/include/asm-ppc64/processor.h	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/processor.h	Tue Apr  9 18:35:26 2002
@@ -53,36 +53,36 @@
 #define MSR_LE_LG	0 		/* Little Endian */
 
 #ifdef __ASSEMBLY__
-#define MASK(X)		(1<<(X))
+#define __MASK(X)	(1<<(X))
 #else
-#define MASK(X)		(1UL<<(X))
+#define __MASK(X)	(1UL<<(X))
 #endif
 
-#define MSR_SF		MASK(MSR_SF_LG)  /* Enable 64 bit mode */
-#define MSR_ISF		MASK(MSR_ISF_LG) /* Interrupt 64b mode valid on 630 */
-#define MSR_HV 		MASK(MSR_HV_LG)	 /* Hypervisor state */
-#define MSR_VEC		MASK(MSR_VEC_LG) /* Enable AltiVec */
-#define MSR_POW		MASK(MSR_POW_LG) /* Enable Power Management */
-#define MSR_WE		MASK(MSR_WE_LG)	 /* Wait State Enable */
-#define MSR_TGPR	MASK(MSR_TGPR_LG)/* TLB Update registers in use */
-#define MSR_CE		MASK(MSR_CE_LG)	 /* Critical Interrupt Enable */
-#define MSR_ILE		MASK(MSR_ILE_LG) /* Interrupt Little Endian */
-#define MSR_EE		MASK(MSR_EE_LG)	 /* External Interrupt Enable */
-#define MSR_PR		MASK(MSR_PR_LG)	 /* Problem State / Privilege Level */
-#define MSR_FP		MASK(MSR_FP_LG)	 /* Floating Point enable */
-#define MSR_ME		MASK(MSR_ME_LG)	 /* Machine Check Enable */
-#define MSR_FE0		MASK(MSR_FE0_LG) /* Floating Exception mode 0 */
-#define MSR_SE		MASK(MSR_SE_LG)	 /* Single Step */
-#define MSR_BE		MASK(MSR_BE_LG)	 /* Branch Trace */
-#define MSR_DE		MASK(MSR_DE_LG)	 /* Debug Exception Enable */
-#define MSR_FE1		MASK(MSR_FE1_LG) /* Floating Exception mode 1 */
-#define MSR_IP		MASK(MSR_IP_LG)	 /* Exception prefix 0x000/0xFFF */
-#define MSR_IR		MASK(MSR_IR_LG)	 /* Instruction Relocate */
-#define MSR_DR		MASK(MSR_DR_LG)	 /* Data Relocate */
-#define MSR_PE		MASK(MSR_PE_LG)	 /* Protection Enable */
-#define MSR_PX		MASK(MSR_PX_LG)	 /* Protection Exclusive Mode */
-#define MSR_RI		MASK(MSR_RI_LG)	 /* Recoverable Exception */
-#define MSR_LE		MASK(MSR_LE_LG)	 /* Little Endian */
+#define MSR_SF		__MASK(MSR_SF_LG)	/* Enable 64 bit mode */
+#define MSR_ISF		__MASK(MSR_ISF_LG)	/* Interrupt 64b mode valid on 630 */
+#define MSR_HV 		__MASK(MSR_HV_LG)	/* Hypervisor state */
+#define MSR_VEC		__MASK(MSR_VEC_LG)	/* Enable AltiVec */
+#define MSR_POW		__MASK(MSR_POW_LG)	/* Enable Power Management */
+#define MSR_WE		__MASK(MSR_WE_LG)	/* Wait State Enable */
+#define MSR_TGPR	__MASK(MSR_TGPR_LG)	/* TLB Update registers in use */
+#define MSR_CE		__MASK(MSR_CE_LG)	/* Critical Interrupt Enable */
+#define MSR_ILE		__MASK(MSR_ILE_LG)	/* Interrupt Little Endian */
+#define MSR_EE		__MASK(MSR_EE_LG)	/* External Interrupt Enable */
+#define MSR_PR		__MASK(MSR_PR_LG)	/* Problem State / Privilege Level */
+#define MSR_FP		__MASK(MSR_FP_LG)	/* Floating Point enable */
+#define MSR_ME		__MASK(MSR_ME_LG)	/* Machine Check Enable */
+#define MSR_FE0		__MASK(MSR_FE0_LG)	/* Floating Exception mode 0 */
+#define MSR_SE		__MASK(MSR_SE_LG)	/* Single Step */
+#define MSR_BE		__MASK(MSR_BE_LG)	/* Branch Trace */
+#define MSR_DE		__MASK(MSR_DE_LG)	/* Debug Exception Enable */
+#define MSR_FE1		__MASK(MSR_FE1_LG)	/* Floating Exception mode 1 */
+#define MSR_IP		__MASK(MSR_IP_LG)	/* Exception prefix 0x000/0xFFF */
+#define MSR_IR		__MASK(MSR_IR_LG)	/* Instruction Relocate */
+#define MSR_DR		__MASK(MSR_DR_LG)	/* Data Relocate */
+#define MSR_PE		__MASK(MSR_PE_LG)	/* Protection Enable */
+#define MSR_PX		__MASK(MSR_PX_LG)	/* Protection Exclusive Mode */
+#define MSR_RI		__MASK(MSR_RI_LG)	/* Recoverable Exception */
+#define MSR_LE		__MASK(MSR_LE_LG)	/* Little Endian */
 
 #define MSR_		MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF
 #define MSR_KERNEL      MSR_ | MSR_SF | MSR_HV
@@ -579,7 +579,9 @@
 #define mfmsr()		({unsigned long rval; \
 			asm volatile("mfmsr %0" : "=r" (rval)); rval;})
 
-#define mtmsrd(v)	asm volatile("mtmsrd %0" : : "r" (v))
+#define __mtmsrd(v, l)	asm volatile("mtmsrd %0," __stringify(l) \
+				     : : "r" (v))
+#define mtmsrd(v)	__mtmsrd((v), 0)
 
 #define mfspr(rn)	({unsigned long rval; \
 			asm volatile("mfspr %0," __stringify(rn) \
@@ -663,7 +665,6 @@
 	unsigned long	ksp;		/* Kernel stack pointer */
 	struct pt_regs	*regs;		/* Pointer to saved register state */
 	mm_segment_t	fs;		/* for get_fs() validation */
-	void		*pgdir;		/* root of page-table tree */
 	signed long     last_syscall;
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
@@ -676,7 +677,6 @@
 	INIT_SP, /* ksp */ \
 	(struct pt_regs *)INIT_SP - 1, /* regs */ \
 	KERNEL_DS, /*fs*/ \
-	swapper_pg_dir, /* pgdir */ \
 	0, /* last_syscall */ \
 	{0}, 0, 0 \
 }
@@ -694,10 +694,8 @@
 /*
  * Return saved PC of a blocked thread. For now, this is the "user" PC
  */
-static inline unsigned long thread_saved_pc(struct thread_struct *t)
-{
-	return (t->regs) ? t->regs->nip : 0;
-}
+#define thread_saved_pc(tsk)    \
+        ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
 
 #define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
diff -urN linux-2.5.8-pre2/include/asm-ppc64/rtas.h linux-2.5.8-pre3/include/asm-ppc64/rtas.h
--- linux-2.5.8-pre2/include/asm-ppc64/rtas.h	Mon Mar 18 12:37:19 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/rtas.h	Tue Apr  9 18:35:26 2002
@@ -38,7 +38,9 @@
 	u32 nargs;
 	u32 nret; 
 	rtas_arg_t args[16];
+#if 0
 	spinlock_t lock;
+#endif
 	rtas_arg_t *rets;     /* Pointer to return values in args[]. */
 };  
 
diff -urN linux-2.5.8-pre2/include/asm-ppc64/siginfo.h linux-2.5.8-pre3/include/asm-ppc64/siginfo.h
--- linux-2.5.8-pre2/include/asm-ppc64/siginfo.h	Mon Mar 18 12:37:18 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/siginfo.h	Tue Apr  9 18:35:26 2002
@@ -113,6 +113,7 @@
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
 #define SI_TKILL	-6		/* sent by tkill system call */
+#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.5.8-pre2/include/asm-ppc64/spinlock.h linux-2.5.8-pre3/include/asm-ppc64/spinlock.h
--- linux-2.5.8-pre2/include/asm-ppc64/spinlock.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/spinlock.h	Tue Apr  9 18:35:26 2002
@@ -67,7 +67,7 @@
 
 static __inline__ void _raw_spin_unlock(spinlock_t *lock)
 {
-	__asm__ __volatile__("eieio	# spin_unlock": : :"memory");
+	__asm__ __volatile__("lwsync	# spin_unlock": : :"memory");
 	lock->lock = 0;
 }
 
@@ -137,7 +137,7 @@
 	unsigned int tmp;
 
 	__asm__ __volatile__(
-	"eieio				# read_unlock\n\
+	"lwsync				# read_unlock\n\
 1:	lwarx		%0,0,%1\n\
 	addic		%0,%0,-1\n\
 	stwcx.		%0,0,%1\n\
@@ -192,7 +192,7 @@
 
 static __inline__ void _raw_write_unlock(rwlock_t *rw)
 {
-	__asm__ __volatile__("eieio		# write_unlock": : :"memory");
+	__asm__ __volatile__("lwsync		# write_unlock": : :"memory");
 	rw->lock = 0;
 }
 
diff -urN linux-2.5.8-pre2/include/asm-ppc64/system.h linux-2.5.8-pre3/include/asm-ppc64/system.h
--- linux-2.5.8-pre2/include/asm-ppc64/system.h	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/system.h	Tue Apr  9 18:35:26 2002
@@ -78,7 +78,6 @@
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 extern int abs(int);
-extern void cacheable_memzero(void *p, unsigned int nb);
 
 struct device_node;
 
diff -urN linux-2.5.8-pre2/include/asm-ppc64/thread_info.h linux-2.5.8-pre3/include/asm-ppc64/thread_info.h
--- linux-2.5.8-pre2/include/asm-ppc64/thread_info.h	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/thread_info.h	Tue Apr  9 18:35:26 2002
@@ -22,6 +22,7 @@
 	struct exec_domain *exec_domain;	/* execution domain */
 	unsigned long	flags;			/* low level flags */
 	int		cpu;			/* cpu we're on */
+	int		preempt_count;		/* not used at present */
 };
 
 /*
diff -urN linux-2.5.8-pre2/include/asm-ppc64/time.h linux-2.5.8-pre3/include/asm-ppc64/time.h
--- linux-2.5.8-pre2/include/asm-ppc64/time.h	Mon Mar 18 12:37:14 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/time.h	Tue Apr  9 18:35:26 2002
@@ -50,6 +50,7 @@
 	unsigned long tb_ticks_per_sec;
 	struct gettimeofday_vars vars[2];
 	struct gettimeofday_vars * volatile varp;
+	unsigned      var_idx;
 	unsigned      tb_to_us;
 };
 
diff -urN linux-2.5.8-pre2/include/asm-ppc64/tlbflush.h linux-2.5.8-pre3/include/asm-ppc64/tlbflush.h
--- linux-2.5.8-pre2/include/asm-ppc64/tlbflush.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/asm-ppc64/tlbflush.h	Tue Apr  9 18:35:26 2002
@@ -0,0 +1,46 @@
+#ifndef _PPC64_TLBFLUSH_H
+#define _PPC64_TLBFLUSH_H
+
+#include <linux/threads.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ */
+
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void __flush_tlb_range(struct mm_struct *mm,
+			    unsigned long start, unsigned long end);
+#define flush_tlb_range(vma, start, end) \
+	__flush_tlb_range(vma->vm_mm, start, end)
+
+#define flush_tlb_kernel_range(start, end) \
+	__flush_tlb_range(&init_mm, (start), (end))
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+	/* PPC has hw page tables. */
+}
+
+extern void flush_hash_page(unsigned long context, unsigned long ea, pte_t pte,
+			    int local);
+void flush_hash_range(unsigned long context, unsigned long number, int local);
+
+/* TLB flush batching */
+#define MAX_BATCH_FLUSH 128
+struct tlb_batch_data {
+	pte_t pte;
+	unsigned long addr;
+};
+extern struct tlb_batch_data tlb_batch_array[NR_CPUS][MAX_BATCH_FLUSH];
+
+#endif /* _PPC64_TLBFLUSH_H */
diff -urN linux-2.5.8-pre2/include/asm-ppc64/unistd.h linux-2.5.8-pre3/include/asm-ppc64/unistd.h
--- linux-2.5.8-pre2/include/asm-ppc64/unistd.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/include/asm-ppc64/unistd.h	Tue Apr  9 18:35:26 2002
@@ -217,22 +217,24 @@
 #define __NR_mincore		206
 #define __NR_gettid		207
 #define __NR_tkill		208
+#define __NR_setxattr		209
+#define __NR_lsetxattr		210
+#define __NR_fsetxattr		211
+#define __NR_getxattr		212
+#define __NR_lgetxattr		213
+#define __NR_fgetxattr		214
+#define __NR_listxattr		215
+#define __NR_llistxattr		216
+#define __NR_flistxattr		217
+#define __NR_removexattr	218
+#define __NR_lremovexattr	219
+#define __NR_fremovexattr	220
+#define __NR_futex		221
 
-#if 0 /* Remind paulus to add these into ppc32 */
+#if 0
+/* Remind paulus to add these into ppc32 */
 __NR_security
 __NR_readahead
-__NR_setxattr
-__NR_lsetxattr
-__NR_fsetxattr
-__NR_getxattr
-__NR_lgetxattr
-__NR_fgetxattr
-__NR_listxattr
-__NR_llistxattr
-__NR_flistxattr
-__NR_removexattr
-__NR_lremovexattr
-__NR_fremovexattr
 #endif
 
 #define __NR(n)	#n
@@ -442,4 +444,12 @@
 
 #endif /* __KERNEL_SYSCALLS__ */
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",sys_ni_syscall");
+
 #endif /* _ASM_PPC_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-s390/unistd.h linux-2.5.8-pre3/include/asm-s390/unistd.h
--- linux-2.5.8-pre2/include/asm-s390/unistd.h	Mon Mar 18 12:37:15 2002
+++ linux-2.5.8-pre3/include/asm-s390/unistd.h	Tue Apr  9 18:35:26 2002
@@ -375,4 +375,12 @@
 
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_S390_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-s390x/unistd.h linux-2.5.8-pre3/include/asm-s390x/unistd.h
--- linux-2.5.8-pre2/include/asm-s390x/unistd.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/include/asm-s390x/unistd.h	Tue Apr  9 18:35:26 2002
@@ -345,4 +345,12 @@
 
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _ASM_S390_UNISTD_H_ */
diff -urN linux-2.5.8-pre2/include/asm-sh/unistd.h linux-2.5.8-pre3/include/asm-sh/unistd.h
--- linux-2.5.8-pre2/include/asm-sh/unistd.h	Mon Mar 18 12:37:10 2002
+++ linux-2.5.8-pre3/include/asm-sh/unistd.h	Tue Apr  9 18:35:26 2002
@@ -367,4 +367,12 @@
 }
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* __ASM_SH_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-sparc/unistd.h linux-2.5.8-pre3/include/asm-sparc/unistd.h
--- linux-2.5.8-pre2/include/asm-sparc/unistd.h	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/include/asm-sparc/unistd.h	Tue Apr  9 18:35:27 2002
@@ -437,4 +437,12 @@
 
 #endif /* __KERNEL_SYSCALLS__ */
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _SPARC_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-sparc64/unistd.h linux-2.5.8-pre3/include/asm-sparc64/unistd.h
--- linux-2.5.8-pre2/include/asm-sparc64/unistd.h	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/include/asm-sparc64/unistd.h	Tue Apr  9 18:35:27 2002
@@ -439,4 +439,12 @@
 #define   _SC_VERSION             8
 #endif
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif /* _SPARC64_UNISTD_H */
diff -urN linux-2.5.8-pre2/include/asm-x86_64/unistd.h linux-2.5.8-pre3/include/asm-x86_64/unistd.h
--- linux-2.5.8-pre2/include/asm-x86_64/unistd.h	Mon Mar 18 12:37:06 2002
+++ linux-2.5.8-pre3/include/asm-x86_64/unistd.h	Tue Apr  9 18:35:27 2002
@@ -650,4 +650,12 @@
 
 #endif /* __NO_STUBS */
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
 #endif
diff -urN linux-2.5.8-pre2/include/linux/acpi.h linux-2.5.8-pre3/include/linux/acpi.h
--- linux-2.5.8-pre2/include/linux/acpi.h	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/include/linux/acpi.h	Tue Apr  9 18:35:27 2002
@@ -29,6 +29,12 @@
 #define _LINUX
 #endif
 
+/*
+ * YES this is ugly.
+ * But, moving all of ACPI's private headers to include/acpi isn't the right
+ * answer either.
+ * Please just ignore it for now.
+ */
 #include "../../drivers/acpi/include/acpi.h"
 #include <asm/acpi.h>
 
@@ -270,7 +276,7 @@
 	struct acpi_table_header header;
 	u64			localities;
 	u8			entry[1];	/* real size = localities^2 */
-};
+} __attribute__ ((packed));
 
 /* Smart Battery Description Table (SBST) */
 
@@ -283,7 +289,6 @@
 
 /* Embedded Controller Boot Resources Table (ECDT) */
 
-/* TBD: acpi_generic_address
 struct acpi_table_ecdt {
 	struct acpi_table_header header;
 	acpi_generic_address	ec_control;
@@ -292,7 +297,6 @@
 	u8			gpe_bit;
 	char			*ec_id;
 } __attribute__ ((packed));
-*/
 
 /* Table Handlers */
 
@@ -343,9 +347,9 @@
 
 #ifdef CONFIG_ACPI_PCI
 
-#define ACPI_PCI_ROUTING_PIC	0
-#define ACPI_PCI_ROUTING_IOAPIC 1
-#define ACPI_PCI_ROUTING_IOSAPIC 2
+#define ACPI_INT_MODEL_PIC	0
+#define ACPI_INT_MODEL_IOAPIC	1
+#define ACPI_INT_MODEL_IOSAPIC	2
 
 struct acpi_prt_entry {
 	struct list_head	node;
diff -urN linux-2.5.8-pre2/include/linux/blkdev.h linux-2.5.8-pre3/include/linux/blkdev.h
--- linux-2.5.8-pre2/include/linux/blkdev.h	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/include/linux/blkdev.h	Tue Apr  9 18:35:27 2002
@@ -313,7 +313,7 @@
 extern void blk_dump_rq_flags(struct request *, char *);
 extern void generic_unplug_device(void *);
 
-extern int * blk_size[MAX_BLKDEV];
+extern int * blk_size[MAX_BLKDEV];	/* in units of 1024 bytes */
 extern int * blksize_size[MAX_BLKDEV];
 
 #define MAX_PHYS_SEGMENTS 128
@@ -353,6 +353,7 @@
 #define blk_finished_io(nsects)	do { } while (0)
 #define blk_started_io(nsects)	do { } while (0)
 
+/* assumes size > 256 */
 extern inline unsigned int blksize_bits(unsigned int size)
 {
 	unsigned int bits = 8;
@@ -376,6 +377,20 @@
 	return retval;
 }
 
+static inline loff_t blkdev_size_in_bytes(kdev_t dev)
+{
+#if 0
+	if (blk_size_in_bytes[major(dev)])
+		return blk_size_in_bytes[major(dev)][minor(dev)];
+	else
+#endif
+	if (blk_size[major(dev)])
+		return (loff_t) blk_size[major(dev)][minor(dev)]
+			<< BLOCK_SIZE_BITS;
+	else
+		return 0;
+}
+
 typedef struct {struct page *v;} Sector;
 
 unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *);
diff -urN linux-2.5.8-pre2/include/linux/compiler.h linux-2.5.8-pre3/include/linux/compiler.h
--- linux-2.5.8-pre2/include/linux/compiler.h	Mon Mar 18 12:37:05 2002
+++ linux-2.5.8-pre3/include/linux/compiler.h	Tue Apr  9 18:35:27 2002
@@ -15,8 +15,8 @@
 
 /* This macro obfuscates arithmetic on a variable address so that gcc
    shouldn't recognize the original var, and make assumptions about it */
-#define RELOC_HIDE(var, off)					\
-  ({ __typeof__(&(var)) __ptr;					\
-    __asm__ ("" : "=g"(__ptr) : "0"((void *)&(var) + (off)));	\
-    *__ptr; })
+#define RELOC_HIDE(ptr, off)					\
+  ({ __typeof__(ptr) __ptr;					\
+    __asm__ ("" : "=g"(__ptr) : "0"((void *)(ptr) + (off)));	\
+    __ptr; })
 #endif /* __LINUX_COMPILER_H */
diff -urN linux-2.5.8-pre2/include/linux/devfs_fs_kernel.h linux-2.5.8-pre3/include/linux/devfs_fs_kernel.h
--- linux-2.5.8-pre2/include/linux/devfs_fs_kernel.h	Mon Mar 18 12:37:17 2002
+++ linux-2.5.8-pre3/include/linux/devfs_fs_kernel.h	Tue Apr  9 18:35:27 2002
@@ -54,7 +54,7 @@
     unsigned char sem_initialised;
     unsigned int num_free;          /*  Num free in bits       */
     unsigned int length;            /*  Array length in bytes  */
-    __u32 *bits;
+    unsigned long *bits;
     struct semaphore semaphore;
 };
 
diff -urN linux-2.5.8-pre2/include/linux/fs.h linux-2.5.8-pre3/include/linux/fs.h
--- linux-2.5.8-pre2/include/linux/fs.h	Tue Apr  9 18:35:12 2002
+++ linux-2.5.8-pre3/include/linux/fs.h	Tue Apr  9 18:35:27 2002
@@ -305,6 +305,8 @@
 #define ATTR_MTIME_SET	256
 #define ATTR_FORCE	512	/* Not a change, but a change it */
 #define ATTR_ATTR_FLAG	1024
+#define ATTR_KILL_SUID	2048
+#define ATTR_KILL_SGID	4096
 
 /*
  * This is the Inode Attributes structure, used for notify_change().  It
@@ -1231,6 +1233,7 @@
 extern int do_pipe(int *);
 
 extern int open_namei(const char *, int, int, struct nameidata *);
+extern int may_open(struct nameidata *, int, int);
 
 extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
 extern struct file * open_exec(const char *);
@@ -1313,7 +1316,7 @@
 
 extern void clear_inode(struct inode *);
 extern struct inode *new_inode(struct super_block *);
-extern void remove_suid(struct inode *inode);
+extern void remove_suid(struct dentry *);
 extern void insert_inode_hash(struct inode *);
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
diff -urN linux-2.5.8-pre2/include/linux/ide.h linux-2.5.8-pre3/include/linux/ide.h
--- linux-2.5.8-pre2/include/linux/ide.h	Tue Apr  9 18:35:12 2002
+++ linux-2.5.8-pre3/include/linux/ide.h	Tue Apr  9 18:35:28 2002
@@ -433,10 +433,10 @@
 typedef void (ide_maskproc_t) (ide_drive_t *, int);
 typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
 
-/*
- * ide soft-power support
- */
-typedef int (ide_busproc_t) (ide_drive_t *, int);
+enum {
+	ATA_PRIMARY	= 0,
+	ATA_SECONDARY	= 1
+};
 
 struct ata_channel {
 	struct device	dev;		/* device handle */
@@ -467,7 +467,6 @@
 	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
 	int sg_nents;			/* Current number of entries in it */
 	int sg_dma_direction;		/* dma transfer direction */
-	struct ata_channel *mate;	/* other hwif from same PCI chip */
 	unsigned long	dma_base;	/* base addr for dma ports */
 	unsigned	dma_extra;	/* extra addr for dma ports */
 	unsigned long	config_data;	/* for use by chipset-specific code */
@@ -480,7 +479,7 @@
 	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
 	unsigned	present    : 1;	/* there is a device on this interface */
-	unsigned	serialized : 1;	/* serialized operation with mate hwif */
+	unsigned	serialized : 1;	/* serialized operation between channels */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 	unsigned	reset      : 1;	/* reset after probe */
 	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
@@ -490,7 +489,7 @@
 	unsigned long	last_time;	/* time when previous rq was done */
 #endif
 	byte		straight8;	/* Alan's straight 8 check */
-	ide_busproc_t	*busproc;	/* driver soft-power interface */
+	int (*busproc)(ide_drive_t *, int);	/* driver soft-power interface */
 	byte		bus_state;	/* power state of the IDE bus */
 };
 
@@ -513,7 +512,6 @@
  */
 typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
-typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
 
 /*
  * when ide_timer_expiry fires, invoke a handler of this type
diff -urN linux-2.5.8-pre2/include/linux/percpu.h linux-2.5.8-pre3/include/linux/percpu.h
--- linux-2.5.8-pre2/include/linux/percpu.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.8-pre3/include/linux/percpu.h	Tue Apr  9 18:35:28 2002
@@ -0,0 +1,14 @@
+#ifndef __LINUX_PERCPU_H
+#define __LINUX_PERCPU_H
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
+#define __per_cpu_data	__attribute__((section(".data.percpu")))
+#include <asm/percpu.h>
+#else
+#define __per_cpu_data
+#define per_cpu(var, cpu)			var
+#define this_cpu(var)				var
+#endif
+
+#endif /* __LINUX_PERCPU_H */
diff -urN linux-2.5.8-pre2/include/linux/proc_fs.h linux-2.5.8-pre3/include/linux/proc_fs.h
--- linux-2.5.8-pre2/include/linux/proc_fs.h	Mon Mar 18 12:37:02 2002
+++ linux-2.5.8-pre3/include/linux/proc_fs.h	Tue Apr  9 18:35:28 2002
@@ -27,7 +27,7 @@
 /* Finally, the dynamically allocatable proc entries are reserved: */
 
 #define PROC_DYNAMIC_FIRST 4096
-#define PROC_NDYNAMIC      4096
+#define PROC_NDYNAMIC      16384
 
 #define PROC_SUPER_MAGIC 0x9fa0
 
diff -urN linux-2.5.8-pre2/include/linux/seq_file.h linux-2.5.8-pre3/include/linux/seq_file.h
--- linux-2.5.8-pre2/include/linux/seq_file.h	Mon Mar 18 12:37:15 2002
+++ linux-2.5.8-pre3/include/linux/seq_file.h	Tue Apr  9 18:35:29 2002
@@ -3,6 +3,8 @@
 #ifdef __KERNEL__
 
 #include <linux/types.h>
+#include <linux/string.h>
+#include <asm/semaphore.h>
 
 struct seq_operations;
 struct file;
diff -urN linux-2.5.8-pre2/include/linux/smp.h linux-2.5.8-pre3/include/linux/smp.h
--- linux-2.5.8-pre2/include/linux/smp.h	Mon Mar 18 12:37:03 2002
+++ linux-2.5.8-pre3/include/linux/smp.h	Tue Apr  9 18:35:29 2002
@@ -72,16 +72,6 @@
 #define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
 #define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
 
-#define __per_cpu_data	__attribute__((section(".data.percpu")))
-
-#ifndef __HAVE_ARCH_PER_CPU
-extern unsigned long __per_cpu_offset[NR_CPUS];
-
-/* var is in discarded region: offset to particular copy we want */
-#define per_cpu(var, cpu) RELOC_HIDE(var, per_cpu_offset(cpu))
-
-#define this_cpu(var) per_cpu(var, smp_processor_id())
-#endif /* !__HAVE_ARCH_PER_CPU */
 #else /* !SMP */
 
 /*
diff -urN linux-2.5.8-pre2/include/linux/usb.h linux-2.5.8-pre3/include/linux/usb.h
--- linux-2.5.8-pre2/include/linux/usb.h	Tue Apr  9 18:35:13 2002
+++ linux-2.5.8-pre3/include/linux/usb.h	Tue Apr  9 18:35:29 2002
@@ -305,6 +305,7 @@
 } __attribute__ ((packed));
 
 /* helpers for driver access to descriptors */
+extern int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum);
 extern struct usb_interface *
 	usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
 extern struct usb_endpoint_descriptor *
@@ -470,8 +471,10 @@
 
 /**
  * struct usb_driver - identifies USB driver to usbcore
- * @owner: pointer to the module owner of this driver
- * @name: The driver name should be unique among USB drivers
+ * @owner: Pointer to the module owner of this driver; initialize
+ *	it using THIS_MODULE.
+ * @name: The driver name should be unique among USB drivers,
+ *	and should normally be the same as the module name.
  * @probe: Called to see if the driver is willing to manage a particular
  *	interface on a device.  The probe routine returns a handle that 
  *	will later be provided to disconnect(), or a null pointer to
@@ -506,7 +509,7 @@
  * is used by both user and kernel mode hotplugging support.
  *
  * The probe() and disconnect() methods are called in a context where
- * they can sleep, but they should avoid abusing the privilage.  Most
+ * they can sleep, but they should avoid abusing the privilege.  Most
  * work to connect to a device should be done when the device is opened,
  * and undone at the last close.  The disconnect code needs to address
  * concurrency issues with respect to open() and close() methods, as
@@ -961,24 +964,6 @@
 
 /* -------------------------------------------------------------------------- */
 
-/* Enumeration is only for the hub driver, or HCD virtual root hubs */
-extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
-	struct usb_bus *);
-extern void usb_free_dev(struct usb_device *);
-extern int usb_new_device(struct usb_device *dev);
-extern void usb_connect(struct usb_device *dev);
-extern void usb_disconnect(struct usb_device **);
-
-#ifndef _LINUX_HUB_H
-/* exported to hub driver ONLY to support usb_reset_device () */
-extern int usb_get_configuration(struct usb_device *dev);
-extern void usb_set_maxpacket(struct usb_device *dev);
-extern void usb_destroy_configuration(struct usb_device *dev);
-extern int usb_set_address(struct usb_device *dev);
-#endif /* _LINUX_HUB_H */
-
-/* -------------------------------------------------------------------------- */
-
 /* This is arbitrary.
  * From USB 2.0 spec Table 11-13, offset 7, a hub can
  * have up to 255 ports. The most yet reported is 10.
@@ -1047,11 +1032,52 @@
 /* for drivers using iso endpoints */
 extern int usb_get_current_frame_number (struct usb_device *usb_dev);
 
-/* drivers must track when they bind to a device's interfaces */
-extern void usb_inc_dev_use(struct usb_device *);
-#define usb_dec_dev_use usb_free_dev
+/**
+ * usb_inc_dev_use - record another reference to a device
+ * @dev: the device being referenced
+ *
+ * Each live reference to a device should be refcounted.
+ *
+ * Drivers for USB interfaces should normally record such references in
+ * their probe() methods, when they bind to an interface, and release
+ * them usb_dec_dev_use(), in their disconnect() methods.
+ */
+static inline void usb_inc_dev_use (struct usb_device *dev)
+{
+	atomic_inc (&dev->refcnt);
+}
+
+/**
+ * usb_dec_dev_use - drop a reference to a device
+ * @dev: the device no longer being referenced
+ *
+ * Each live reference to a device should be refcounted.
+ *
+ * Drivers for USB interfaces should normally release such references in
+ * their disconnect() methods, and record them in probe().
+ *
+ * Note that driver disconnect() methods must guarantee that when they
+ * return, all of their outstanding references to the device (and its
+ * interfaces) are cleaned up.  That means that all pending URBs from
+ * this driver must have completed, and that no more copies of the device
+ * handle are saved in driver records (including other kernel threads).
+ */
+static inline void usb_dec_dev_use (struct usb_device *dev)
+{
+	if (atomic_dec_and_test (&dev->refcnt)) {
+		/* May only go to zero when usbcore finishes
+		 * usb_disconnect() processing:  khubd or HCDs.
+		 *
+		 * If you hit this BUG() it's likely a problem
+		 * with some driver's disconnect() routine.
+		 */
+		BUG ();
+	}
+}
+
 
 /* used these for multi-interface device registration */
+extern int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned int ifnum);
 extern void usb_driver_claim_interface(struct usb_driver *driver,
 			struct usb_interface *iface, void* priv);
 extern int usb_interface_claimed(struct usb_interface *iface);
diff -urN linux-2.5.8-pre2/include/linux/usbdevice_fs.h linux-2.5.8-pre3/include/linux/usbdevice_fs.h
--- linux-2.5.8-pre2/include/linux/usbdevice_fs.h	Mon Mar 18 12:37:08 2002
+++ linux-2.5.8-pre3/include/linux/usbdevice_fs.h	Tue Apr  9 18:35:29 2002
@@ -142,6 +142,8 @@
 #define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
 #define USBDEVFS_RESET             _IO('U', 20)
 #define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
+#define USBDEVFS_DISCONNECT        _IO('U', 22)
+#define USBDEVFS_CONNECT           _IO('U', 23)
 
 /* --------------------------------------------------------------------- */
 
diff -urN linux-2.5.8-pre2/init/main.c linux-2.5.8-pre3/init/main.c
--- linux-2.5.8-pre2/init/main.c	Mon Mar 18 12:37:07 2002
+++ linux-2.5.8-pre3/init/main.c	Tue Apr  9 18:35:29 2002
@@ -27,6 +27,7 @@
 #include <linux/iobuf.h>
 #include <linux/bootmem.h>
 #include <linux/tty.h>
+#include <linux/percpu.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -270,12 +271,9 @@
 #define smp_init()	do { } while (0)
 #endif
 
-static inline void setup_per_cpu_areas(void)
-{
-}
 #else
 
-#ifndef __HAVE_ARCH_PER_CPU
+#ifdef __GENERIC_PER_CPU
 unsigned long __per_cpu_offset[NR_CPUS];
 
 static void __init setup_per_cpu_areas(void)
@@ -297,7 +295,11 @@
 		memcpy(ptr, __per_cpu_start, size);
 	}
 }
-#endif /* !__HAVE_ARCH_PER_CPU */
+#else
+static inline void setup_per_cpu_areas(void)
+{
+}
+#endif /* !__GENERIC_PER_CPU */
 
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
diff -urN linux-2.5.8-pre2/kernel/sched.c linux-2.5.8-pre3/kernel/sched.c
--- linux-2.5.8-pre2/kernel/sched.c	Tue Apr  9 18:35:13 2002
+++ linux-2.5.8-pre3/kernel/sched.c	Tue Apr  9 18:35:29 2002
@@ -1234,6 +1234,96 @@
 	return retval;
 }
 
+/**
+ * sys_sched_setaffinity - set the cpu affinity of a process
+ * @pid: pid of the process
+ * @len: length of new_mask
+ * @new_mask: user-space pointer to the new cpu mask
+ */
+asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len,
+				      unsigned long *new_mask_ptr)
+{
+	unsigned long new_mask;
+	task_t *p;
+	int retval;
+
+	if (len < sizeof(new_mask))
+		return -EINVAL;
+
+	if (copy_from_user(&new_mask, new_mask_ptr, sizeof(new_mask)))
+		return -EFAULT;
+
+	new_mask &= cpu_online_map;
+	if (!new_mask)
+		return -EINVAL;
+
+	read_lock(&tasklist_lock);
+
+	p = find_process_by_pid(pid);
+	if (!p) {
+		read_unlock(&tasklist_lock);
+		return -ESRCH;
+	}
+
+	/*
+	 * It is not safe to call set_cpus_allowed with the
+	 * tasklist_lock held.  We will bump the task_struct's
+	 * usage count and then drop tasklist_lock.
+	 */
+	get_task_struct(p);
+	read_unlock(&tasklist_lock);
+
+	retval = -EPERM;
+	if ((current->euid != p->euid) && (current->euid != p->uid) &&
+			!capable(CAP_SYS_NICE))
+		goto out_unlock;
+
+	retval = 0;
+	set_cpus_allowed(p, new_mask);
+
+out_unlock:
+	put_task_struct(p);
+	return retval;
+}
+
+/**
+ * sys_sched_getaffinity - get the cpu affinity of a process
+ * @pid: pid of the process
+ * @len: length of the new mask
+ * @user_mask_ptr: userspace pointer to the mask
+ */
+asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len,
+				      unsigned long *user_mask_ptr)
+{
+	unsigned long mask;
+	unsigned int real_len;
+	task_t *p;
+	int retval;
+
+	real_len = sizeof(mask);
+
+	if (len < real_len)
+		return -EINVAL;
+
+	read_lock(&tasklist_lock);
+
+	retval = -ESRCH;
+	p = find_process_by_pid(pid);
+	if (!p)
+		goto out_unlock;
+
+	retval = 0;
+	mask = p->cpus_allowed & cpu_online_map;
+
+out_unlock:
+	read_unlock(&tasklist_lock);
+	if (retval)
+		return retval;
+	if (copy_to_user(user_mask_ptr, &mask, real_len))
+		return -EFAULT;
+	return real_len;
+}
+
 asmlinkage long sys_sched_yield(void)
 {
 	runqueue_t *rq;
@@ -1689,8 +1779,10 @@
 	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
 		int logical = cpu_logical_map(cpu);
 
-		while (!cpu_rq(logical)->migration_thread)
+		while (!cpu_rq(logical)->migration_thread) {
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(2);
+		}
 	}
 	if (migration_mask)
 		BUG();
diff -urN linux-2.5.8-pre2/kernel/sys.c linux-2.5.8-pre3/kernel/sys.c
--- linux-2.5.8-pre2/kernel/sys.c	Tue Apr  9 18:35:13 2002
+++ linux-2.5.8-pre3/kernel/sys.c	Tue Apr  9 18:35:29 2002
@@ -19,6 +19,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/unistd.h>
 
 /*
  * this is where the system-wide overflow UID and GID are defined, for
@@ -174,14 +175,6 @@
 	return -ENOSYS;
 }
 
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on sparc64, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
-
 cond_syscall(sys_nfsservctl)
 cond_syscall(sys_quotactl)
 cond_syscall(sys_acct)
diff -urN linux-2.5.8-pre2/mm/filemap.c linux-2.5.8-pre3/mm/filemap.c
--- linux-2.5.8-pre2/mm/filemap.c	Tue Apr  9 18:35:13 2002
+++ linux-2.5.8-pre3/mm/filemap.c	Tue Apr  9 18:35:29 2002
@@ -2503,18 +2503,19 @@
 	return page;
 }
 
-inline void remove_suid(struct inode *inode)
+inline void remove_suid(struct dentry *dentry)
 {
-	unsigned int mode;
+	struct iattr newattrs;
+	struct inode *inode = dentry->d_inode;
+	unsigned int mode = inode->i_mode & (S_ISUID|S_ISGID|S_IXGRP);
 
-	/* set S_IGID if S_IXGRP is set, and always set S_ISUID */
-	mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
+	if (!(mode & S_IXGRP))
+		mode &= S_ISUID;
 
 	/* was any of the uid bits set? */
-	mode &= inode->i_mode;
 	if (mode && !capable(CAP_FSETID)) {
-		inode->i_mode &= ~mode;
-		mark_inode_dirty(inode);
+		newattrs.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID;
+		notify_change(dentry, &newattrs);
 	}
 }
 
@@ -2646,7 +2647,7 @@
 	if (count == 0)
 		goto out;
 
-	remove_suid(inode);
+	remove_suid(file->f_dentry);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	mark_inode_dirty_sync(inode);
 
diff -urN linux-2.5.8-pre2/mm/highmem.c linux-2.5.8-pre3/mm/highmem.c
--- linux-2.5.8-pre2/mm/highmem.c	Mon Mar 18 12:37:04 2002
+++ linux-2.5.8-pre3/mm/highmem.c	Tue Apr  9 18:35:29 2002
@@ -88,7 +88,7 @@
 
 		page->virtual = NULL;
 	}
-	flush_tlb_all();
+	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
 static inline unsigned long map_new_virtual(struct page *page)
diff -urN linux-2.5.8-pre2/mm/shmem.c linux-2.5.8-pre3/mm/shmem.c
--- linux-2.5.8-pre2/mm/shmem.c	Tue Apr  9 18:35:13 2002
+++ linux-2.5.8-pre3/mm/shmem.c	Tue Apr  9 18:35:29 2002
@@ -802,7 +802,7 @@
 
 	status	= 0;
 	if (count) {
-		remove_suid(inode);
+		remove_suid(file->f_dentry);
 		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	}
 
diff -urN linux-2.5.8-pre2/mm/vmalloc.c linux-2.5.8-pre3/mm/vmalloc.c
--- linux-2.5.8-pre2/mm/vmalloc.c	Tue Apr  9 18:35:13 2002
+++ linux-2.5.8-pre3/mm/vmalloc.c	Tue Apr  9 18:35:29 2002
@@ -81,6 +81,7 @@
 void vmfree_area_pages(unsigned long address, unsigned long size)
 {
 	pgd_t * dir;
+	unsigned long start = address;
 	unsigned long end = address + size;
 
 	dir = pgd_offset_k(address);
@@ -90,7 +91,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
-	flush_tlb_all();
+	flush_tlb_kernel_range(start, end);
 }
 
 static inline int alloc_area_pte (pte_t * pte, unsigned long address,
