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

diff -urN linux-2.4.21-pre7/Documentation/Configure.help linux-2.4.21-rc1/Documentation/Configure.help
--- linux-2.4.21-pre7/Documentation/Configure.help	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/Documentation/Configure.help	2003-04-21 11:48:39.000000000 -0700
@@ -2523,6 +2523,19 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+Amanda protocol support
+CONFIG_IP_NF_AMANDA
+  If you are running the Amanda backup package (http://www.amanda.org/)
+  on this machine or machines that will be MASQUERADED through this
+  machine, then you may want to enable this feature.  This allows the
+  connection tracking and natting code to allow the sub-channels that
+  Amanda requires for communication of the backup data, messages and
+  index.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+
 IRC Send/Chat protocol support
 CONFIG_IP_NF_IRC
   There is a commonly-used extension to IRC called
@@ -2537,6 +2550,16 @@
   If you want to compile it as a module, say 'M' here and read
   Documentation/modules.txt.  If unsure, say 'N'.
 
+TFTP protocol support
+CONFIG_IP_NF_TFTP
+  TFTP connection tracking helper, this is required depending
+  on how restrictive your ruleset is.
+  If you are using a tftp client behind -j SNAT or -j MASQUERADING
+  you will need this.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `Y'.
+
 FTP protocol support
 CONFIG_IP_NF_FTP
   Tracking FTP connections is problematic: special helpers are
@@ -19126,6 +19149,34 @@
   The module is called rtc.o. If you want to compile it as a module,
   say M here and read <file:Documentation/modules.txt>.
 
+Generic Real Time Clock Support
+CONFIG_GEN_RTC
+  If you say Y here and create a character special file /dev/rtc with
+  major number 10 and minor number 135 using mknod ("man mknod"), you
+  will get access to the real time clock (or hardware clock) built
+  into your computer.
+
+  In 2.4 and later kernels this is the only way to set and get rtc
+  time on m68k systems so it is highly recommended.
+
+  It reports status information via the file /proc/driver/rtc and its 
+  behaviour is set by various ioctls on /dev/rtc. If you enable the
+  "extended RTC operation" below it will also provide an emulation
+  for RTC_UIE which is required by some programs and may improve
+  precision in some cases.
+
+  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 is called genrtc.o. If you want to compile it as a module,
+  say M here and read <file:Documentation/modules.txt>. To load the
+  module automatically add 'alias char-major-10-135 genrtc' to your
+  /etc/modules.conf
+
+Extended RTC operation
+CONFIG_GEN_RTC_X
+  Provides an emulation for RTC_UIE which is required by some programs 
+  and may improve precision of the generic RTC support in some cases.
+
 Tadpole ANA H8 Support
 CONFIG_H8
   The Hitachi H8/337 is a microcontroller used to deal with the power
diff -urN linux-2.4.21-pre7/Makefile linux-2.4.21-rc1/Makefile
--- linux-2.4.21-pre7/Makefile	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/Makefile	2003-04-21 11:48:39.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 21
-EXTRAVERSION = -pre7
+EXTRAVERSION = -rc1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.21-pre7/arch/i386/kernel/apic.c linux-2.4.21-rc1/arch/i386/kernel/apic.c
--- linux-2.4.21-pre7/arch/i386/kernel/apic.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/i386/kernel/apic.c	2003-04-21 11:48:39.000000000 -0700
@@ -649,7 +649,6 @@
 	}
 	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)
 		nmi_watchdog = NMI_LOCAL_APIC;
 
@@ -1169,8 +1168,7 @@
 
 	connect_bsp_APIC();
 
-	phys_cpu_present_map = 1;
-	apic_write_around(APIC_ID, boot_cpu_physical_apicid);
+	phys_cpu_present_map = 1 << boot_cpu_physical_apicid;
 
 	apic_pm_init2();
 
diff -urN linux-2.4.21-pre7/arch/i386/kernel/dmi_scan.c linux-2.4.21-rc1/arch/i386/kernel/dmi_scan.c
--- linux-2.4.21-pre7/arch/i386/kernel/dmi_scan.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/i386/kernel/dmi_scan.c	2003-04-21 11:48:39.000000000 -0700
@@ -427,8 +427,10 @@
 #ifdef CONFIG_X86_IO_APIC
 	skip_ioapic_setup = 0;
 #endif
+#ifdef CONFIG_PCI
 	broken_440gx_bios = 1;
 	pci_probe |= PCI_BIOS_IRQ_SCAN;
+#endif
 	
 	return 0;
 }
diff -urN linux-2.4.21-pre7/arch/i386/kernel/io_apic.c linux-2.4.21-rc1/arch/i386/kernel/io_apic.c
--- linux-2.4.21-pre7/arch/i386/kernel/io_apic.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/i386/kernel/io_apic.c	2003-04-21 11:48:39.000000000 -0700
@@ -776,7 +776,9 @@
 	printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
 	printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)&reg_00);
 	printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.ID);
-	if (reg_00.__reserved_1 || reg_00.__reserved_2)
+	printk(KERN_DEBUG ".......    : Delivery Type: %X\n", reg_00.delivery_type);
+	printk(KERN_DEBUG ".......    : LTS          : %X\n", reg_00.LTS);
+	if (reg_00.__reserved_0 || reg_00.__reserved_1 || reg_00.__reserved_2)
 		UNEXPECTED_IO_APIC();
 
 	printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
diff -urN linux-2.4.21-pre7/arch/ia64/config.in linux-2.4.21-rc1/arch/ia64/config.in
--- linux-2.4.21-pre7/arch/ia64/config.in	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ia64/config.in	2003-04-21 11:48:39.000000000 -0700
@@ -179,6 +179,9 @@
     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
diff -urN linux-2.4.21-pre7/arch/m68k/config.in linux-2.4.21-rc1/arch/m68k/config.in
--- linux-2.4.21-pre7/arch/m68k/config.in	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/m68k/config.in	2003-04-21 11:48:40.000000000 -0700
@@ -519,9 +519,12 @@
    if [ "$CONFIG_SUN3" = "y" ]; then
       define_bool CONFIG_GEN_RTC y
    else
-      bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+      tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC      
    fi
 fi
+if [ "$CONFIG_GEN_RTC" != "n" ]; then
+   bool '   Extended RTC operation' CONFIG_GEN_RTC_X
+fi
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
    int '  Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
diff -urN linux-2.4.21-pre7/arch/m68k/kernel/m68k_ksyms.c linux-2.4.21-rc1/arch/m68k/kernel/m68k_ksyms.c
--- linux-2.4.21-pre7/arch/m68k/kernel/m68k_ksyms.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/m68k/kernel/m68k_ksyms.c	2003-04-21 11:48:40.000000000 -0700
@@ -18,6 +18,7 @@
 #include <asm/checksum.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
+#include <asm/rtc.h>
 
 asmlinkage long long __ashldi3 (long long, int);
 asmlinkage long long __ashrdi3 (long long, int);
@@ -49,6 +50,10 @@
 EXPORT_SYMBOL(kernel_set_cachemode);
 #endif /* !CONFIG_SUN3 */
 EXPORT_SYMBOL(m68k_debug_device);
+EXPORT_SYMBOL(mach_hwclk);
+EXPORT_SYMBOL(mach_get_ss);
+EXPORT_SYMBOL(mach_get_rtc_pll);
+EXPORT_SYMBOL(mach_set_rtc_pll);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(strnlen);
diff -urN linux-2.4.21-pre7/arch/m68k/kernel/setup.c linux-2.4.21-rc1/arch/m68k/kernel/setup.c
--- linux-2.4.21-pre7/arch/m68k/kernel/setup.c	2002-11-28 15:53:09.000000000 -0800
+++ linux-2.4.21-rc1/arch/m68k/kernel/setup.c	2003-04-21 11:48:40.000000000 -0700
@@ -90,6 +90,9 @@
 void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
 int (*mach_hwclk) (int, struct rtc_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
+unsigned int (*mach_get_ss)(void) = NULL;
+int (*mach_get_rtc_pll)(struct rtc_pll_info *) = NULL;
+int (*mach_set_rtc_pll)(struct rtc_pll_info *) = NULL;
 void (*mach_reset)( void );
 void (*mach_halt)( void ) = NULL;
 void (*mach_power_off)( void ) = NULL;
diff -urN linux-2.4.21-pre7/arch/m68k/q40/config.c linux-2.4.21-rc1/arch/m68k/q40/config.c
--- linux-2.4.21-pre7/arch/m68k/q40/config.c	2002-11-28 15:53:09.000000000 -0800
+++ linux-2.4.21-rc1/arch/m68k/q40/config.c	2003-04-21 11:48:40.000000000 -0700
@@ -58,7 +58,10 @@
 extern void q40_gettod (int *year, int *mon, int *day, int *hour,
                            int *min, int *sec);
 extern int q40_hwclk (int, struct rtc_time *);
+extern unsigned int q40_get_ss (void);
 extern int q40_set_clock_mmss (unsigned long);
+static int q40_get_rtc_pll(struct rtc_pll_info *pll);
+static int q40_set_rtc_pll(struct rtc_pll_info *pll);
 extern void q40_reset (void);
 void q40_halt(void);
 extern void q40_waitbut(void);
@@ -196,6 +199,9 @@
     mach_gettimeoffset   = q40_gettimeoffset; 
     mach_gettod  	 = q40_gettod;
     mach_hwclk           = q40_hwclk; 
+    mach_get_ss          = q40_get_ss; 
+    mach_get_rtc_pll     = q40_get_rtc_pll; 
+    mach_set_rtc_pll     = q40_set_rtc_pll; 
     mach_set_clock_mmss	 = q40_set_clock_mmss;
 
     mach_reset		 = q40_reset;
@@ -331,6 +337,11 @@
 	return 0;
 }
 
+unsigned int q40_get_ss()
+{
+	return bcd2bin(Q40_RTC_SECS);
+}
+
 /*
  * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
  * clock is out by > 30 minutes.  Logic lifted from atari code.
@@ -362,3 +373,33 @@
 	return retval;
 }
 
+
+/* get and set PLL calibration of RTC clock */
+#define Q40_RTC_PLL_MASK ((1<<5)-1)
+#define Q40_RTC_PLL_SIGN (1<<5)
+
+static int q40_get_rtc_pll(struct rtc_pll_info *pll)
+{
+      int tmp=Q40_RTC_CTRL;
+      pll->pll_value = tmp & Q40_RTC_PLL_MASK;
+      if (tmp & Q40_RTC_PLL_SIGN) 
+	  pll->pll_value = -pll->pll_value;
+      pll->pll_max=31;
+      pll->pll_min=-31;
+      pll->pll_posmult=512;
+      pll->pll_negmult=256;
+      pll->pll_clock=125829120;
+      return 0;
+  }
+
+static int q40_set_rtc_pll(struct rtc_pll_info *pll)
+{
+  if (!pll->pll_ctrl){
+      /* the docs are a bit unclear so I am doublesetting RTC_WRITE here ... */
+      int tmp=(pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) | Q40_RTC_WRITE;
+      Q40_RTC_CTRL |= Q40_RTC_WRITE;
+      Q40_RTC_CTRL = tmp;
+      Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
+      return 0;
+  } else return -EINVAL;
+}
diff -urN linux-2.4.21-pre7/arch/ppc/8260_io/Config.in linux-2.4.21-rc1/arch/ppc/8260_io/Config.in
--- linux-2.4.21-pre7/arch/ppc/8260_io/Config.in	2002-11-28 15:53:10.000000000 -0800
+++ linux-2.4.21-rc1/arch/ppc/8260_io/Config.in	2003-04-21 11:48:40.000000000 -0700
@@ -23,7 +23,4 @@
     bool 'Ethernet on FCC3' CONFIG_FCC3_ENET
   fi
 fi
-
-comment 'Generic MPC8260 Options'
-bool 'Disable data cache' CONFIG_DCACHE_DISABLE
 endmenu
diff -urN linux-2.4.21-pre7/arch/ppc/boot/ld.script linux-2.4.21-rc1/arch/ppc/boot/ld.script
--- linux-2.4.21-pre7/arch/ppc/boot/ld.script	2002-11-28 15:53:11.000000000 -0800
+++ linux-2.4.21-rc1/arch/ppc/boot/ld.script	2003-04-21 11:48:40.000000000 -0700
@@ -39,7 +39,7 @@
   PROVIDE (etext = .);
 
   /* Read-write section, merged into data segment: */
-  . = ALIGN(8);
+  . = ALIGN(4096);
   .data    :
   {
     *(.data)
diff -urN linux-2.4.21-pre7/arch/ppc/config.in linux-2.4.21-rc1/arch/ppc/config.in
--- linux-2.4.21-pre7/arch/ppc/config.in	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/config.in	2003-04-21 11:48:40.000000000 -0700
@@ -196,12 +196,9 @@
 
 source drivers/parport/Config.in
 
-if [ "$CONFIG_4xx" != "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
+tristate 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
+if [ "$CONFIG_GEN_RTC" = "n" -a "$CONFIG_APUS" != "y" ]; then
+  tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
 fi
 
 if [ "$CONFIG_ALL_PPC" = "y" -a "$CONFIG_POWER3" = "n" ] ; then
diff -urN linux-2.4.21-pre7/arch/ppc/configs/est8260_defconfig linux-2.4.21-rc1/arch/ppc/configs/est8260_defconfig
--- linux-2.4.21-pre7/arch/ppc/configs/est8260_defconfig	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/configs/est8260_defconfig	2003-04-21 11:48:40.000000000 -0700
@@ -456,11 +456,6 @@
 # CONFIG_FEC_ENET is not set
 
 #
-# Generic MPC8260 Options
-#
-# CONFIG_DCACHE_DISABLE is not set
-
-#
 # USB support
 #
 # CONFIG_USB is not set
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/Makefile linux-2.4.21-rc1/arch/ppc/kernel/Makefile
--- linux-2.4.21-pre7/arch/ppc/kernel/Makefile	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/kernel/Makefile	2003-04-21 11:48:40.000000000 -0700
@@ -36,7 +36,7 @@
 					process.o signal.o ptrace.o align.o \
 					semaphore.o syscalls.o setup.o \
 					cputable.o ppc_htab.o
-obj-$(CONFIG_6xx)		+= l2cr.o
+obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_PCI)		+= pci.o 
 obj-$(CONFIG_PCI)		+= pci-dma.o
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/cpu_setup_6xx.S linux-2.4.21-rc1/arch/ppc/kernel/cpu_setup_6xx.S
--- linux-2.4.21-pre7/arch/ppc/kernel/cpu_setup_6xx.S	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/arch/ppc/kernel/cpu_setup_6xx.S	2003-04-21 11:48:40.000000000 -0700
@@ -0,0 +1,415 @@
+/*
+ * This file contains low level CPU setup functions.
+ *    Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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 <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/cache.h>
+#include "ppc_defs.h"
+
+_GLOBAL(__setup_cpu_601)
+	blr
+_GLOBAL(__setup_cpu_603)
+	b	setup_common_caches
+_GLOBAL(__setup_cpu_604)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_604_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750cx)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	bl	setup_750cx
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750fx)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	bl	setup_750fx
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_7400)
+	mflr	r4
+	bl	setup_7400_workarounds
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_7410)
+	mflr	r4
+	bl	setup_7410_workarounds
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	li	r3,0
+	mtspr	SPRN_L2CR2,r3
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_745x)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_745x_specifics
+	mtlr	r4
+	blr
+
+/* Enable caches for 603's, 604, 750 & 7400 */
+setup_common_caches:
+	mfspr	r11,HID0
+	andi.	r0,r11,HID0_DCE
+	ori	r11,r11,HID0_ICE|HID0_DCE
+	ori	r8,r11,HID0_ICFI
+	bne	1f			/* don't invalidate the D-cache */
+	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
+1:	sync
+	mtspr	HID0,r8			/* enable and invalidate caches */
+	sync
+	mtspr	HID0,r11		/* enable caches */
+	sync
+	isync
+	blr
+
+/* 604, 604e, 604ev, ...
+ * Enable superscalar execution & branch history table
+ */
+setup_604_hid0:
+	mfspr	r11,HID0
+	ori	r11,r11,HID0_SIED|HID0_BHTE
+	ori	r8,r11,HID0_BTCD
+	sync
+	mtspr	HID0,r8		/* flush branch target address cache */
+	sync			/* on 604e/604r */
+	mtspr	HID0,r11
+	sync
+	isync
+	blr
+
+/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some
+ * erratas we work around here.
+ * Moto MPC710CE.pdf describes them, those are errata
+ * #3, #4 and #5
+ * Note that we assume the firmware didn't choose to
+ * apply other workarounds (there are other ones documented
+ * in the .pdf). It appear that Apple firmware only works
+ * around #3 and with the same fix we use. We may want to
+ * check if the CPU is using 60x bus mode in which case
+ * the workaround for errata #4 is useless. Also, we may
+ * want to explicitely clear HID0_NOPDST as this is not
+ * needed once we have applied workaround #5 (though it's
+ * not set by Apple's firmware at least).
+ */
+setup_7400_workarounds:
+	mfpvr	r3
+	rlwinm	r3,r3,0,20,31
+	cmpwi	0,r3,0x0207
+	ble	1f
+	blr
+setup_7410_workarounds:
+	mfpvr	r3
+	rlwinm	r3,r3,0,20,31
+	cmpwi	0,r3,0x0100
+	bnelr
+1:
+	mfspr	r11,SPRN_MSSSR0
+	/* Errata #3: Set L1OPQ_SIZE to 0x10 */
+	rlwinm	r11,r11,0,9,6
+	oris	r11,r11,0x0100
+	/* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */
+	oris	r11,r11,0x0002
+	/* Errata #5: Set DRLT_SIZE to 0x01 */
+	rlwinm	r11,r11,0,5,2
+	oris	r11,r11,0x0800
+	sync
+	mtspr	SPRN_MSSSR0,r11
+	sync
+	isync
+	blr
+	
+/* 740/750/7400/7410
+ * Enable Store Gathering (SGE), Address Brodcast (ABE),
+ * Branch History Table (BHTE), Branch Target ICache (BTIC)
+ * Dynamic Power Management (DPM), Speculative (SPD)
+ * Clear Instruction cache throttling (ICTC)
+ */
+setup_750_7400_hid0:
+	mfspr	r11,HID0
+	ori	r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
+BEGIN_FTR_SECTION
+	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
+	li	r3,HID0_SPD
+	andc	r11,r11,r3		/* clear SPD: enable speculative */
+ 	li	r3,0
+ 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
+	isync
+	mtspr	HID0,r11
+	sync
+	isync
+	blr
+
+/* 750cx specific
+ * Looks like we have to disable NAP feature for some PLL settings...
+ * (waiting for confirmation)
+ */
+setup_750cx:
+	mfspr	r10, SPRN_HID1
+	rlwinm	r10,r10,4,28,31
+	cmpi	cr0,r10,7
+	cmpi	cr1,r10,9
+	cmpi	cr2,r10,11
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
+	bnelr
+	lwz	r6,CPU_SPEC_FEATURES(r5)
+	li	r7,CPU_FTR_CAN_NAP
+	andc	r6,r6,r7
+	stw	r6,CPU_SPEC_FEATURES(r5)
+	blr
+
+/* 750fx specific
+ */
+setup_750fx:
+	blr
+
+/* MPC 745x
+ * Enable Store Gathering (SGE), Branch Folding (FOLD)
+ * Branch History Table (BHTE), Branch Target ICache (BTIC)
+ * Dynamic Power Management (DPM), Speculative (SPD)
+ * Ensure our data cache instructions really operate.
+ * Timebase has to be running or we wouldn't have made it here,
+ * just ensure we don't disable it.
+ * Clear Instruction cache throttling (ICTC)
+ * Enable L2 HW prefetch
+ */
+setup_745x_specifics:
+	/* We check for the presence of an L3 cache setup by
+	 * the firmware. If any, we disable NAP capability as
+	 * it's known to be bogus on rev 2.1 and earlier
+	 */
+	mfspr	r11,SPRN_L3CR
+	andis.	r11,r11,L3CR_L3E@h
+	beq	1f
+	lwz	r6,CPU_SPEC_FEATURES(r5)
+	andi.	r0,r6,CPU_FTR_L3_DISABLE_NAP
+	beq	1f
+	li	r7,CPU_FTR_CAN_NAP
+	andc	r6,r6,r7
+	stw	r6,CPU_SPEC_FEATURES(r5)
+1:	
+	mfspr	r11,HID0
+
+	/* All of the bits we have to set.....
+	 */
+	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
+BEGIN_FTR_SECTION
+	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
+
+	/* All of the bits we have to clear....
+	 */
+	li	r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
+	andc	r11,r11,r3		/* clear SPD: enable speculative */
+ 	li	r3,0
+
+ 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
+	isync
+	mtspr	HID0,r11
+	sync
+	isync
+
+	/* Enable L2 HW prefetch
+	 */
+	mfspr	r3,SPRN_MSSCR0
+	ori	r3,r3,3
+	sync
+	mtspr	SPRN_MSSCR0,r3
+	sync
+	isync
+	blr
+
+/* Definitions for the table use to save CPU states */
+#define CS_HID0		0
+#define CS_HID1		4
+#define	CS_MSSCR0	8
+#define CS_MSSSR0	12
+#define CS_ICTRL	16
+#define CS_LDSTCR	20
+#define CS_LDSTDB	24
+#define CS_SIZE		28
+
+	.data
+	.balign	L1_CACHE_LINE_SIZE
+cpu_state_storage:	
+	.space	CS_SIZE
+	.balign	L1_CACHE_LINE_SIZE,0
+	.text
+	
+/* Called in normal context to backup CPU 0 state. This
+ * does not include cache settings. This function is also
+ * called for machine sleep. This does not include the MMU
+ * setup, BATs, etc... but rather the "special" registers
+ * like HID0, HID1, MSSCR0, etc...
+ */
+_GLOBAL(__save_cpu_setup)
+	/* Some CR fields are volatile, we back it up all */
+	mfcr	r7
+
+	/* Get storage ptr */
+	lis	r5,cpu_state_storage@h
+	ori	r5,r5,cpu_state_storage@l
+
+	/* Save HID0 (common to all CONFIG_6xx cpus) */
+	mfspr	r3,SPRN_HID0
+	stw	r3,CS_HID0(r5)
+
+	/* Now deal with CPU type dependent registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000	/* 7450 */
+	cmpli	cr1,r3,0x000c	/* 7400 */
+	cmpli	cr2,r3,0x800c	/* 7410 */
+	cmpli	cr3,r3,0x8001	/* 7455 */
+	cmpli	cr4,r3,0x8002	/* 7457 */
+	cmpli	cr5,r3,0x7000	/* 750FX */
+	/* cr1 is 7400 || 7410 */
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	/* cr0 is 74xx */
+	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr4+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	1f
+	/* Backup 74xx specific regs */
+	mfspr	r4,SPRN_MSSCR0
+	stw	r4,CS_MSSCR0(r5)
+	mfspr	r4,SPRN_MSSSR0
+	stw	r4,CS_MSSSR0(r5)
+	beq	cr1,1f
+	/* Backup 745x specific registers */
+	mfspr	r4,SPRN_HID1
+	stw	r4,CS_HID1(r5)
+	mfspr	r4,SPRN_ICTRL
+	stw	r4,CS_ICTRL(r5)
+	mfspr	r4,SPRN_LDSTCR
+	stw	r4,CS_LDSTCR(r5)
+	mfspr	r4,SPRN_LDSTDB
+	stw	r4,CS_LDSTDB(r5)
+1:	
+	bne	cr5,1f
+	/* Backup 750FX specific registers */
+	mfspr	r4,SPRN_HID1
+	stw	r4,CS_HID1(r5)
+1:
+	mtcr	r7
+	blr
+
+/* Called with no MMU context (typically MSR:IR/DR off) to
+ * restore CPU state as backed up by the previous
+ * function. This does not include cache setting
+ */
+_GLOBAL(__restore_cpu_setup)
+	/* Some CR fields are volatile, we back it up all */
+	mfcr	r7
+
+	/* Get storage ptr */
+	lis	r5,(cpu_state_storage-KERNELBASE)@h
+	ori	r5,r5,cpu_state_storage@l
+
+	/* Restore HID0 */
+	lwz	r3,CS_HID0(r5)
+	sync
+	isync
+	mtspr	SPRN_HID0,r3
+	sync
+	isync
+
+	/* Now deal with CPU type dependent registers */
+	mfspr	r3,PVR
+	srwi	r3,r3,16
+	cmpli	cr0,r3,0x8000	/* 7450 */
+	cmpli	cr1,r3,0x000c	/* 7400 */
+	cmpli	cr2,r3,0x800c	/* 7410 */
+	cmpli	cr3,r3,0x8001	/* 7455 */
+	cmpli	cr4,r3,0x8002	/* 7457 */
+	cmpli	cr5,r3,0x7000	/* 750FX */
+	/* cr1 is 7400 || 7410 */
+	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
+	/* cr0 is 74xx */
+	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr4+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	bne	2f
+	/* Restore 74xx specific regs */
+	lwz	r4,CS_MSSCR0(r5)
+	sync
+	mtspr	SPRN_MSSCR0,r4
+	sync
+	isync
+	lwz	r4,CS_MSSSR0(r5)
+	sync
+	mtspr	SPRN_MSSSR0,r4
+	sync
+	isync
+	bne	cr2,1f
+	/* Clear 7410 L2CR2 */
+	li	r4,0
+	mtspr	SPRN_L2CR2,r4
+1:	beq	cr1,2f
+	/* Restore 745x specific registers */
+	lwz	r4,CS_HID1(r5)
+	sync
+	mtspr	SPRN_HID1,r4
+	isync
+	sync
+	lwz	r4,CS_ICTRL(r5)
+	sync
+	mtspr	SPRN_ICTRL,r4
+	isync
+	sync
+	lwz	r4,CS_LDSTCR(r5)
+	sync
+	mtspr	SPRN_LDSTCR,r4
+	isync
+	sync
+	lwz	r4,CS_LDSTDB(r5)
+	sync
+	mtspr	SPRN_LDSTDB,r4
+	isync
+	sync
+2:	bne	cr5,1f
+	/* Restore 750FX specific registers
+	 * that is restore PLL config & switch
+	 * to PLL 0
+	 */
+	lwz	r4,CS_HID1(r5)
+	rlwinm  r5,r4,0,16,14
+	mtspr	SPRN_HID1,r5
+		/* Wait for PLL to stabilize */
+	mftbl	r5
+3:	mftbl	r6
+	sub	r6,r6,r5
+	cmpli	cr0,r6,10000
+	ble	3b
+	/* Setup final PLL */
+	mtspr	SPRN_HID1,r4
+1:
+	mtcr	r7
+	blr
+
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/gen550_dbg.c linux-2.4.21-rc1/arch/ppc/kernel/gen550_dbg.c
--- linux-2.4.21-pre7/arch/ppc/kernel/gen550_dbg.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/kernel/gen550_dbg.c	2003-04-21 11:48:40.000000000 -0700
@@ -129,6 +129,7 @@
 gen550_init(int i, struct serial_struct *serial_req)
 {
 	rs_table[i].io_type = serial_req->io_type;
+	rs_table[i].port = serial_req->port;
 	rs_table[i].iomem_base = serial_req->iomem_base;
 	rs_table[i].iomem_reg_shift = serial_req->iomem_reg_shift;
 }
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/head.S linux-2.4.21-rc1/arch/ppc/kernel/head.S
--- linux-2.4.21-pre7/arch/ppc/kernel/head.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/kernel/head.S	2003-04-21 11:48:40.000000000 -0700
@@ -141,7 +141,7 @@
  * early_init() does the early machine identification and does
  * the necessary low-level setup and clears the BSS
  *  -- Cort <cort@fsmlabs.com>
- */ 
+ */
 	bl	early_init
 
 #ifdef CONFIG_APUS
@@ -152,7 +152,6 @@
 	bl	fix_mem_constants
 #endif /* CONFIG_APUS */
 
-#ifndef CONFIG_GEMINI
 /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
  * the physical address we are running at, returned by early_init()
  */
@@ -160,7 +159,6 @@
 __after_mmu_off:
 	bl	clear_bats
 	bl	flush_tlbs
-#endif
 
 #ifndef CONFIG_POWER4
 	/* POWER4 doesn't have BATs */
@@ -200,8 +198,7 @@
  * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
  * the exception vectors at 0 (and therefore this copy
  * overwrites OF's exception vectors with our own).
- * If the MMU is already turned on, we copy stuff to KERNELBASE,
- * otherwise we copy it to 0.
+ * The MMU is off at this point.
  */
 	bl	reloc_offset
 	mr	r26,r3
@@ -791,6 +788,9 @@
 	stw	r22,THREAD_VRSAVE(r23)
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
+#ifndef CONFIG_6xx
+2:
+#endif
 	.globl transfer_to_handler_cont
 transfer_to_handler_cont:
 	tovirt(r2,r2)
@@ -813,12 +813,12 @@
 	mtlr	r23
 	SYNC
 	RFI				/* jump to handler, enable MMU */
+
+#ifdef CONFIG_6xx
 2:
 	/* Out of line case when returning to kernel,
 	 * check return from power_save_6xx
 	 */
-#ifdef CONFIG_6xx
-	
 	mfspr	r24,SPRN_HID0
 	mtcr	r24
 BEGIN_FTR_SECTION
@@ -828,7 +828,6 @@
 	bt-	9,power_save_6xx_restore	/* Check NAP */
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
 	b	transfer_to_handler_cont
-
 #endif /* CONFIG_6xx */
 
 /*
@@ -1073,7 +1072,8 @@
 giveup_fpu:
 	mfmsr	r5
 	ori	r5,r5,MSR_FP
-	SYNC
+	SYNC_601
+	ISYNC_601
 	mtmsr	r5			/* enable use of fpu now */
 	SYNC_601
 	isync
@@ -1266,6 +1266,8 @@
 	MTMSRD(r0)
 	isync
 #endif
+	/* Copy some CPU settings from CPU 0 */
+	bl	__restore_cpu_setup
 
 	lis	r3,-KERNELBASE@h
 	mr	r4,r24
@@ -1312,250 +1314,20 @@
 #endif /* CONFIG_SMP */
 
 /*
- * Enable caches and 604-specific features if necessary.
+ * Those generic dummy functions are kept for CPUs not
+ * included in CONFIG_6xx
  */
-_GLOBAL(__setup_cpu_601)
-	blr
-_GLOBAL(__setup_cpu_603)
-	b	setup_common_caches
-_GLOBAL(__setup_cpu_604)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_604_hid0
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_750)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_750cx)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	bl	setup_750cx
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_750fx)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	bl	setup_750fx
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7400)
-	mflr	r4
-	bl	setup_7400_workarounds
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7410)
-	mflr	r4
-	bl	setup_7410_workarounds
-	bl	setup_common_caches
-	bl	setup_750_7400_hid0
-	li	r3,0
-	mtspr	SPRN_L2CR2,r3
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7450)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_745x_specifics
-	mtlr	r4
-	blr
-_GLOBAL(__setup_cpu_7455)
-	mflr	r4
-	bl	setup_common_caches
-	bl	setup_745x_specifics
-	mtlr	r4
-	blr
 _GLOBAL(__setup_cpu_power3)
 	blr
-_GLOBAL(__setup_cpu_power4)
-	blr
 _GLOBAL(__setup_cpu_generic)
 	blr
 
-/* Enable caches for 603's, 604, 750 & 7400 */
-setup_common_caches:
-	mfspr	r11,HID0
-	andi.	r0,r11,HID0_DCE
-#ifdef CONFIG_DCACHE_DISABLE
-	ori	r11,r11,HID0_ICE
-#else
-	ori	r11,r11,HID0_ICE|HID0_DCE
-#endif
-	ori	r8,r11,HID0_ICFI
-	bne	1f			/* don't invalidate the D-cache */
-	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
-1:	sync
-	mtspr	HID0,r8			/* enable and invalidate caches */
-	sync
-	mtspr	HID0,r11		/* enable caches */
-	sync
-	isync
+#ifndef CONFIG_6xx
+_GLOBAL(__save_cpu_setup)
 	blr
-
-/* 604, 604e, 604ev, ...
- * Enable superscalar execution & branch history table
- */
-setup_604_hid0:
-	mfspr	r11,HID0
-	ori	r11,r11,HID0_SIED|HID0_BHTE
-	ori	r8,r11,HID0_BTCD
-	sync
-	mtspr	HID0,r8		/* flush branch target address cache */
-	sync			/* on 604e/604r */
-	mtspr	HID0,r11
-	sync
-	isync
-	blr
-
-/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some
- * erratas we work around here.
- * Moto MPC710CE.pdf describes them, those are errata
- * #3, #4 and #5
- * Note that we assume the firmware didn't choose to
- * apply other workarounds (there are other ones documented
- * in the .pdf). It appear that Apple firmware only works
- * around #3 and with the same fix we use. We may want to
- * check if the CPU is using 60x bus mode in which case
- * the workaround for errata #4 is useless. Also, we may
- * want to explicitely clear HID0_NOPDST as this is not
- * needed once we have applied workaround #5 (though it's
- * not set by Apple's firmware at least).
- */
-setup_7400_workarounds:
-	mfpvr	r3
-	rlwinm	r3,r3,0,20,31
-	cmpwi	0,r3,0x0207
-	ble	1f
-	blr
-setup_7410_workarounds:
-	mfpvr	r3
-	rlwinm	r3,r3,0,20,31
-	cmpwi	0,r3,0x0100
-	bnelr
-1:
-	mfspr	r11,SPRN_MSSSR0
-	/* Errata #3: Set L1OPQ_SIZE to 0x10 */
-	rlwinm	r11,r11,0,9,6
-	oris	r11,r11,0x0100
-	/* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */
-	oris	r11,r11,0x0002
-	/* Errata #5: Set DRLT_SIZE to 0x01 */
-	rlwinm	r11,r11,0,5,2
-	oris	r11,r11,0x0800
-	sync
-	mtspr	SPRN_MSSSR0,r11
-	sync
-	isync
-	blr
-	
-/* 740/750/7400/7410
- * Enable Store Gathering (SGE), Address Brodcast (ABE),
- * Branch History Table (BHTE), Branch Target ICache (BTIC)
- * Dynamic Power Management (DPM), Speculative (SPD)
- * Clear Instruction cache throttling (ICTC)
- */
-setup_750_7400_hid0:
-	mfspr	r11,HID0
-	ori	r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
-BEGIN_FTR_SECTION
-	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
-END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
-	li	r3,HID0_SPD
-	andc	r11,r11,r3		/* clear SPD: enable speculative */
- 	li	r3,0
- 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
-	isync
-	mtspr	HID0,r11
-	sync
-	isync
-	blr
-
-/* 750cx specific
- * Looks like we have to disable NAP feature for some PLL settings...
- * (waiting for confirmation)
- */
-setup_750cx:
-	mfspr	r10, SPRN_HID1
-	rlwinm	r10,r10,4,28,31
-	cmpi	cr0,r10,7
-	cmpi	cr1,r10,9
-	cmpi	cr2,r10,11
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
-	bnelr
-	lwz	r6,CPU_SPEC_FEATURES(r5)
-	li	r7,CPU_FTR_CAN_NAP
-	andc	r6,r6,r7
-	stw	r6,CPU_SPEC_FEATURES(r5)
-	blr
-
-/* 750fx specific
- */
-setup_750fx:
-	blr
-
-/* MPC 745x
- * Enable Store Gathering (SGE), Branch Folding (FOLD)
- * Branch History Table (BHTE), Branch Target ICache (BTIC)
- * Dynamic Power Management (DPM), Speculative (SPD)
- * Ensure our data cache instructions really operate.
- * Timebase has to be running or we wouldn't have made it here,
- * just ensure we don't disable it.
- * Clear Instruction cache throttling (ICTC)
- * Enable L2 HW prefetch
- */
-setup_745x_specifics:
-	/* We check for the presence of an L3 cache setup by
-	 * the firmware. If any, we disable NAP capability as
-	 * it's known to be bogus on rev 2.1 and earlier
-	 */
-	mfspr	r11,SPRN_L3CR
-	andis.	r11,r11,L3CR_L3E@h
-	beq	1f
-	lwz	r6,CPU_SPEC_FEATURES(r5)
-	andi.	r0,r6,CPU_FTR_L3_DISABLE_NAP
-	beq	1f
-	li	r7,CPU_FTR_CAN_NAP
-	andc	r6,r6,r7
-	stw	r6,CPU_SPEC_FEATURES(r5)
-1:	
-	mfspr	r11,HID0
-
-	/* All of the bits we have to set.....
-	 */
-	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
-BEGIN_FTR_SECTION
-	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
-END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
-
-	/* All of the bits we have to clear....
-	 */
-	li	r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
-	andc	r11,r11,r3		/* clear SPD: enable speculative */
- 	li	r3,0
-
- 	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
-	isync
-	mtspr	HID0,r11
-	sync
-	isync
-
-	/* Enable L2 HW prefetch
-	 */
-	mfspr	r3,SPRN_MSSCR0
-	ori	r3,r3,3
-	sync
-	mtspr	SPRN_MSSCR0,r3
-	sync
-	isync
+_GLOBAL(__restore_cpu_setup)
 	blr
+#endif /* CONFIG_6xx */
 
 /*
  * Load stuff into the MMU.  Intended to be called with
@@ -1567,7 +1339,7 @@
 	tophys(r6,r6)
 	lwz	r6,_SDR1@l(r6)
 	mtspr	SDR1,r6
-#ifdef CONFIG_PPC64BRIDGE	
+#ifdef CONFIG_PPC64BRIDGE
 	/* clear the ASR so we only use the pseudo-segment registers. */
 	li	r6,0
 	mtasr	r6
@@ -1735,7 +1507,6 @@
  *  -- Cort 
  */
 clear_bats:
-#if !defined(CONFIG_GEMINI)
 	li	r20,0
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
@@ -1759,10 +1530,32 @@
 	mtspr	IBAT2L,r20
 	mtspr	IBAT3U,r20
 	mtspr	IBAT3L,r20
-#endif /* !defined(CONFIG_GEMINI) */
+BEGIN_FTR_SECTION
+	/* Here's a tweak: at this point, CPU setup have
+	 * not been called yet, so HIGH_BAT_EN may not be
+	 * set in HID0 for the 745x processors. However, it
+	 * seems that doesn't affect our ability to actually
+	 * write to these SPRs.
+	 */
+	mtspr	SPRN_DBAT4U,r20
+	mtspr	SPRN_DBAT4L,r20
+	mtspr	SPRN_DBAT5U,r20
+	mtspr	SPRN_DBAT5L,r20
+	mtspr	SPRN_DBAT6U,r20
+	mtspr	SPRN_DBAT6L,r20
+	mtspr	SPRN_DBAT7U,r20
+	mtspr	SPRN_DBAT7L,r20
+	mtspr	SPRN_IBAT4U,r20
+	mtspr	SPRN_IBAT4L,r20
+	mtspr	SPRN_IBAT5U,r20
+	mtspr	SPRN_IBAT5L,r20
+	mtspr	SPRN_IBAT6U,r20
+	mtspr	SPRN_IBAT6L,r20
+	mtspr	SPRN_IBAT7U,r20
+	mtspr	SPRN_IBAT7L,r20
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
 	blr
 
-#ifndef CONFIG_GEMINI
 flush_tlbs:
 	lis	r20, 0x40
 1:	addic.	r20, r20, -0x1000
@@ -1781,7 +1574,6 @@
 	mtspr	SRR1,r3
 	sync
 	RFI
-#endif
 
 #ifndef CONFIG_POWER4	
 /*
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/irq.c linux-2.4.21-rc1/arch/ppc/kernel/irq.c
--- linux-2.4.21-pre7/arch/ppc/kernel/irq.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/kernel/irq.c	2003-04-21 11:48:40.000000000 -0700
@@ -516,27 +516,21 @@
 	int irq, first = 1;
         hardirq_enter( cpu );
 
-	for (;;) {
-		/*
-		 * Every arch is required to implement ppc_md.get_irq.
-		 * This function will either return an irq number or -1 to
-		 * indicate there are no more pending.  But the first time
-		 * through the loop this means there wasn't and IRQ pending.
-		 * The value -2 is for buggy hardware and means that this IRQ
-		 * has already been handled. -- Tom
-		 */
-		irq = ppc_md.get_irq( regs );
-
-		if (irq >= 0)
-			ppc_irq_dispatch_handler( regs, irq );
-		else {
-			if (irq != -2 && first)
-				/* That's not SMP safe ... but who cares ? */
-				ppc_spurious_interrupts++;
-			break;
-		}
+	/*
+	 * Every platform is required to implement ppc_md.get_irq.
+	 * This function will either return an irq number or -1 to
+	 * indicate there are no more pending.  But the first time
+	 * through the loop this means there wasn't an IRQ pending.
+	 * The value -2 is for buggy hardware and means that this IRQ
+	 * has already been handled. -- Tom
+	 */
+	while ((irq = ppc_md.get_irq(regs)) >= 0) {
+		ppc_irq_dispatch_handler(regs, irq);
 		first = 0;
 	}
+	if (irq != -2 && first)
+		/* That's not SMP safe ... but who cares ? */
+		ppc_spurious_interrupts++;
         hardirq_exit( cpu );
 
 	if (softirq_pending(cpu))
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/l2cr.S linux-2.4.21-rc1/arch/ppc/kernel/l2cr.S
--- linux-2.4.21-pre7/arch/ppc/kernel/l2cr.S	2002-11-28 15:53:11.000000000 -0800
+++ linux-2.4.21-rc1/arch/ppc/kernel/l2cr.S	2003-04-21 11:48:40.000000000 -0700
@@ -40,9 +40,11 @@
 	Author:	Terry Greeniaus (tgree@phys.ualberta.ca)
 	Please e-mail updates to this file to me, thanks!
 */
+#include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
+#include <asm/cache.h>
 
 /* Usage:
 	
@@ -101,6 +103,8 @@
 	blr
 END_FTR_SECTION_IFCLR(CPU_FTR_L2CR)
 
+	mflr	r9
+	
 	/* Stop DST streams */
 BEGIN_FTR_SECTION
 	DSSALL
@@ -115,6 +119,22 @@
 	mtmsr	r4
 	isync
 
+	/* Before we perform the global invalidation, we must disable dynamic
+	 * power management via HID0[DPM] to work around a processor bug where
+	 * DPM can possibly interfere with the state machine in the processor
+	 * that invalidates the L2 cache tags.
+	 */
+	mfspr	r8,HID0			/* Save HID0 in r8 */
+	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
+	sync
+	mtspr	HID0,r4			/* Disable DPM */
+	sync
+
+	/* Flush & disable L1 */
+	mr	r5,r3
+	bl	__flush_disable_L1
+	mr	r3,r5
+	
 	/* Get the current enable bit of the L2CR into r4 */
 	mfspr	r4,L2CR
 	
@@ -142,21 +162,22 @@
 
 	/* TODO: use HW flush assist when available */
 
-	lis	r4,0x0004
+	lis	r4,0x0002
 	mtctr	r4
 	li	r4,0
 1:
 	lwzx	r0,r0,r4
 	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
+	isync
 	
 	/* Now, flush the first 4MB of memory */
-	lis	r4,0x0004
+	lis	r4,0x0002
 	mtctr	r4
 	li	r4,0
 	sync
 1:
-	dcbf	r0,r4
+	dcbf	0,r4
 	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
 
@@ -166,25 +187,19 @@
 	 * L1 icache
 	 */
 	b	20f
-21:
+	.balign	L1_CACHE_LINE_SIZE
+22:
 	sync
 	mtspr	L2CR,r3
 	sync
-	b	22f
+	b	23f
 20:
-	b	21b
-22:
-	/* Before we perform the global invalidation, we must disable dynamic
-	 * power management via HID0[DPM] to work around a processor bug where
-	 * DPM can possibly interfere with the state machine in the processor
-	 * that invalidates the L2 cache tags.
-	 */
-	mfspr	r8,HID0			/* Save HID0 in r8 */
-	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
-	sync
-	mtspr	HID0,r4			/* Disable DPM */
-	sync
-
+	b	21f
+21:	sync
+	isync
+	b	22b
+		
+23:
 	/* Perform a global invalidation */
 	oris	r3,r3,0x0020
 	sync
@@ -211,11 +226,6 @@
 	mtspr	L2CR,r3
 	sync
 	
-	/* Restore HID0[DPM] to whatever it was before */
-	sync
-	mtspr	1008,r8
-	sync
-
 	/* See if we need to enable the cache */
 	cmplwi	r5,0
 	beq	4f
@@ -225,10 +235,20 @@
 	mtspr	L2CR,r3
 	sync
 
+4:
+	bl	__inval_enable_L1
+
+	/* Restore HID0[DPM] to whatever it was before */
+	sync
+	mtspr	1008,r8
+	sync
+
 	/* Restore MSR (restores EE and DR bits to original state) */
-4:	SYNC
+	SYNC
 	mtmsr	r7
 	isync
+
+	mtlr	r9
 	blr
 
 _GLOBAL(_get_L2CR)
@@ -286,7 +306,7 @@
 	li	r4,0
 1:
 	lwzx	r0,r0,r4
-	dcbf	r0,r4
+	dcbf	0,r4
 	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
 	
@@ -360,3 +380,73 @@
 
 /* --- End of PowerLogix code ---
  */
+
+
+/* flush_disable_L1()	- Flush and disable L1 cache
+ *
+ * clobbers r0, r3, ctr, cr0
+ *
+ */
+ 	.globl	__flush_disable_L1
+ __flush_disable_L1:
+ 
+	/* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+	DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ 	sync
+ 	
+	/* Load counter to 0x1000 cache lines (128k) and
+	 * load cache with datas
+	 */
+	lis	r3,0x0002
+//	li	r3,0x1000	/* 128kB / 32B */
+	mtctr	r3
+	li	r3, 0
+1:
+	lwz	r0,0(r3)
+	addi	r3,r3,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	isync
+	sync
+
+	/* Now flush those cache lines */
+	lis	r3,0x0002
+//	li	r3,0x1000	/* 128kB / 32B */
+	mtctr	r3
+	li	r3, 0
+1:
+	dcbf	0,r3
+	addi	r3,r3,0x0020	/* Go to start of next cache line */
+	bdnz	1b
+	sync
+
+	/* We can now disable the L1 cache (HID0:DCE, HID0:ICE) */
+	mfspr	r3,SPRN_HID0
+	rlwinm	r3,r3,0,18,15
+	mtspr	SPRN_HID0,r3
+	sync
+	isync	
+ 	blr
+
+/* inval_enable_L1	- Invalidate and enable L1 cache
+ *
+ * Assumes L1 is already disabled and MSR:EE is off
+ *
+ * clobbers r3
+ */
+ 	.globl	__inval_enable_L1
+ __inval_enable_L1:
+	/* Enable and then Flash inval the instruction & data cache */
+	mfspr	r3,SPRN_HID0
+	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
+	sync
+	isync
+	mtspr	SPRN_HID0,r3
+	xori	r3,r3, HID0_ICFI|HID0_DCI
+	mtspr	SPRN_HID0,r3
+	sync
+
+ 	blr
+
+ 
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/open_pic.c linux-2.4.21-rc1/arch/ppc/kernel/open_pic.c
--- linux-2.4.21-pre7/arch/ppc/kernel/open_pic.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/kernel/open_pic.c	2003-04-21 11:48:40.000000000 -0700
@@ -146,7 +146,8 @@
  */
 extern unsigned long* _get_SP(void);
 #define check_arg_irq(irq) \
-    if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
+    if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
+	|| ISR[irq - open_pic_irq_offset] == 0) { \
       printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
       print_backtrace(_get_SP()); }
 #define check_arg_cpu(cpu) \
@@ -565,14 +566,19 @@
 	if (OpenPIC == NULL)
 		return;
 
+	/* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
-		    openpic_ipi_action, 0, "IPI0 (call function)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI0 (call function)", 0);
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
-		    openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI1 (reschedule)", 0);
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
-		    openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI2 (invalidate tlb)", 0);
 	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
-		    openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
+		    openpic_ipi_action, SA_INTERRUPT,
+		    "IPI3 (xmon break)", 0);
 
 	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
 		openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
@@ -650,7 +656,6 @@
 				9 << OPENPIC_PRIORITY_SHIFT);
 }
 
-
 /*
  *
  * All functions below take an offset'ed irq argument
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/ppc-stub.c linux-2.4.21-rc1/arch/ppc/kernel/ppc-stub.c
--- linux-2.4.21-pre7/arch/ppc/kernel/ppc-stub.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/kernel/ppc-stub.c	2003-04-21 11:48:40.000000000 -0700
@@ -509,12 +509,12 @@
 	*ptr++ = hexchars[PC_REGNUM >> 4];
 	*ptr++ = hexchars[PC_REGNUM & 0xf];
 	*ptr++ = ':';
-	ptr = mem2hex((char *)regs->nip, ptr, 4);
+	ptr = mem2hex((char *)&regs->nip, ptr, 4);
 	*ptr++ = ';';
 	*ptr++ = hexchars[SP_REGNUM >> 4];
 	*ptr++ = hexchars[SP_REGNUM & 0xf];
 	*ptr++ = ':';
-	ptr = mem2hex(((char *)&regs) + SP_REGNUM*4, ptr, 4);
+	ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4);
 	*ptr++ = ';';
 #endif
 
diff -urN linux-2.4.21-pre7/arch/ppc/kernel/smp.c linux-2.4.21-rc1/arch/ppc/kernel/smp.c
--- linux-2.4.21-pre7/arch/ppc/kernel/smp.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/kernel/smp.c	2003-04-21 11:48:40.000000000 -0700
@@ -63,6 +63,9 @@
 extern int cpu_idle(void *unused);
 void smp_call_function_interrupt(void);
 
+/* Low level assembly function used to backup CPU 0 state */
+extern void __save_cpu_setup(void);
+
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  * 
  * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
@@ -327,6 +330,9 @@
 	/* Probe arch for CPUs */
 	cpu_nr = smp_ops->probe();
 
+	/* Backup CPU 0 state */
+	__save_cpu_setup();
+	
 	/*
 	 * only check for cpus we know exist.  We keep the callin map
 	 * with cpus at the bottom -- Cort
@@ -368,7 +374,7 @@
 		 * use this value that I found through experimentation.
 		 * -- Cort
 		 */
-		for ( c = 1000; c && !cpu_callin_map[i] ; c-- )
+		for ( c = 10000; c && !cpu_callin_map[i] ; c-- )
 			udelay(100);
 		
 		if ( cpu_callin_map[i] )
@@ -502,19 +508,11 @@
 	int cpu = current->processor;
 	
         smp_store_cpu_info(cpu);
+	smp_ops->setup_cpu(cpu);
 	set_dec(tb_ticks_per_jiffy);
+	cpu_online_map |= 1UL << cpu;
+	mb();
 	cpu_callin_map[cpu] = 1;
-
-	smp_ops->setup_cpu(cpu);
-
-	/*
-	 * This cpu is now "online".  Only set them online
-	 * before they enter the loop below since write access
-	 * to the below variable is _not_ guaranteed to be
-	 * atomic.
-	 *   -- Cort <cort@fsmlabs.com>
-	 */
-	cpu_online_map |= 1UL << smp_processor_id();
 	
 	while(!smp_commenced)
 		barrier();
diff -urN linux-2.4.21-pre7/arch/ppc/mm/Makefile linux-2.4.21-rc1/arch/ppc/mm/Makefile
--- linux-2.4.21-pre7/arch/ppc/mm/Makefile	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/mm/Makefile	2003-04-21 11:48:40.000000000 -0700
@@ -18,7 +18,6 @@
 					mmu_context.o pgtable.o
 
 obj-$(CONFIG_PPC_STD_MMU)	+= hashtable.o ppc_mmu.o tlb.o
-obj-$(CONFIG_PPC_ISERIES)	+= iSeries_hashtable.o iSeries_mmu.o tlb.o
 obj-$(CONFIG_4xx)		+= cachemap.o 4xx_mmu.o
 obj-$(CONFIG_8xx)		+= cachemap.o
 
diff -urN linux-2.4.21-pre7/arch/ppc/platforms/pmac_sleep.S linux-2.4.21-rc1/arch/ppc/platforms/pmac_sleep.S
--- linux-2.4.21-pre7/arch/ppc/platforms/pmac_sleep.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/platforms/pmac_sleep.S	2003-04-21 11:48:40.000000000 -0700
@@ -15,8 +15,7 @@
 #include <asm/page.h>
 #include <asm/ppc_asm.h>
 #include <asm/cputable.h>
-#include <asm/ppc_asm.h>
-#include "../kernel/ppc_defs.h" // DAMMIT !
+#include <asm/cache.h>
 
 #define MAGIC	0x4c617273	/* 'Lars' */
 
@@ -37,16 +36,9 @@
 #define SL_DBAT3	0x50
 #define SL_IBAT3	0x58
 #define SL_TB		0x60
-#define SL_HID0		0x68
-#define SL_HID1		0x6c
-#define SL_MSSCR0	0x70
-#define SL_MSSSR0	0x74
-#define SL_ICTRL	0x78
-#define SL_LDSTCR	0x7c
-#define SL_LDSTDB	0x80
-#define SL_R2		0x84
-#define SL_CR		0x88
-#define SL_R12		0x8c	/* r12 to r31 */
+#define SL_R2		0x68
+#define SL_CR		0x6c
+#define SL_R12		0x70	/* r12 to r31 */
 #define SL_SIZE		(SL_R12 + 80)
 
 	.text
@@ -127,43 +119,9 @@
 	mfibatl	r4,3
 	stw	r4,SL_IBAT3+4(r1)
 
-	/* Save HID0 */
-	mfspr	r4,HID0
-	stw	r4,SL_HID0(r1)
-
-	/* Save 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000	/* 7450 */
-	cmpli	cr1,r3,0x000c	/* 7400 */
-	cmpli	cr2,r3,0x800c	/* 7410 */
-	cmpli	cr3,r3,0x8001	/* 7455 */
-	cmpli	cr4,r3,0x7000	/* 750FX */
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	mfspr	r4,SPRN_MSSCR0
-	stw	r4,SL_MSSCR0(r1)
-	mfspr	r4,SPRN_MSSSR0
-	stw	r4,SL_MSSSR0(r1)
-	/* Save 7450/7455 specific registers */
-	beq	cr1,1f
-	mfspr	r4,HID1
-	stw	r4,SL_HID1(r1)
-	mfspr	r4,SPRN_ICTRL
-	stw	r4,SL_ICTRL(r1)
-	mfspr	r4,SPRN_LDSTCR
-	stw	r4,SL_LDSTCR(r1)
-	mfspr	r4,SPRN_LDSTDB
-	stw	r4,SL_LDSTDB(r1)
-1:	
-	/* Save 750FX specific registers */
-	bne	cr4,1f
-	mfspr	r4,HID1
-	stw	r4,SL_HID1(r1)
-	
-1:
+	/* Backup various CPU config stuffs */
+	bl	__save_cpu_setup
+
 	/* The ROM can wake us up via 2 different vectors:
 	 *  - On wallstreet & lombard, we must write a magic
 	 *    value 'Lars' at address 4 and a pointer to a
@@ -198,33 +156,22 @@
 	addi r3,r3,sleep_storage@l
 	stw r5,0(r3)
 
-BEGIN_FTR_SECTION
-	DSSALL
+	/* Disable DPM during cache flush */
+	mfspr	r3, SPRN_HID0
+	rlwinm	r3,r3,0,12,10
 	sync
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-
-/*
- * Flush the L1 data cache by reading the first 128kB of RAM
- * and then flushing the same area with the dcbf instruction.
- * The L2 cache has already been disabled.
- */
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	lwz	r0,0(r4)
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
+	mtspr	SPRN_HID0,r3
 	sync
 	
-	li	r4,0x1000	/* 128kB / 32B */
-	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:
-	dcbf	r0,r4
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	1b
+	/* Turn off data relocation. */
+	mfmsr	r3		/* Save MSR in r7 */
+	rlwinm	r3,r3,0,28,26	/* Turn off DR bit */
 	sync
+	mtmsr	r3
+	isync
+
+	/* Flush & disable L1 cache */
+	bl	__flush_disable_L1
 
 /*
  * Set the HID0 and MSR for sleep.
@@ -233,6 +180,7 @@
 	rlwinm	r2,r2,0,10,7	/* clear doze, nap */
 	oris	r2,r2,HID0_SLEEP@h
 	sync
+	isync
 	mtspr	HID0,r2
 	sync
 
@@ -293,16 +241,11 @@
  */
 	
 grackle_wake_up:
-	/* Enable and then Flash inval the instruction & data cache */
-	mfspr	r3,HID0
-	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
-	sync
-	isync
-	mtspr	HID0,r3
-	xori	r3,r3, HID0_ICFI|HID0_DCI
-	mtspr	HID0,r3
-	sync
-	
+	/* Invalidate & enable L1 cache, we don't care about
+	 * whatever the ROM may have tried to write to memory
+	 */
+	bl	__inval_enable_L1
+
 	/* Restore the kernel's segment registers before
 	 * we do any r1 memory access as we are not sure they
 	 * are in a sane state above the first 256Mb region
@@ -315,79 +258,14 @@
 	addi	r3,r3,0x111	/* increment VSID */
 	addis	r4,r4,0x1000	/* address of next segment */
 	bdnz	3b
-	
-	/* Restore the remaining bits of the HID0 register. */
-	subi	r1,r1,SL_PC
-	lwz	r3,SL_HID0(r1)
-	sync
-	isync
-	mtspr	HID0,r3
 	sync
 	isync
+	
+	subi	r1,r1,SL_PC
+
+	/* Restore various CPU config stuffs */
+	bl	__restore_cpu_setup
 
-	/* Restore 7400/7410/7450 specific registers */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpli	cr0,r3,0x8000	/* 7450 */
-	cmpli	cr1,r3,0x000c	/* 7400 */
-	cmpli	cr2,r3,0x800c	/* 7410 */
-	cmpli	cr3,r3,0x8001	/* 7455 */
-	cmpli	cr4,r3,0x7000	/* 750FX */
-	cror	4*cr1+eq,4*cr1+eq,4*cr2+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr3+eq
-	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
-	bne	1f
-	lwz	r4,SL_MSSCR0(r1)
-	sync
-	mtspr	SPRN_MSSCR0,r4
-	sync
-	isync
-	lwz	r4,SL_MSSSR0(r1)
-	sync
-	mtspr	SPRN_MSSSR0,r4
-	sync
-	isync
-	bne	cr2,1f
-	li	r4,0
-	mtspr	SPRN_L2CR2,r4
-	/* Restore 7450/7455 specific registers */
-	beq	cr1,1f
-	lwz	r4,SL_HID1(r1)
-	sync
-	mtspr	HID1,r4
-	isync
-	sync
-	lwz	r4,SPRN_ICTRL(r1)
-	sync
-	mtspr	SPRN_ICTRL,r4
-	isync
-	sync
-	lwz	r4,SPRN_LDSTCR(r1)
-	sync
-	mtspr	SPRN_LDSTCR,r4
-	isync
-	sync
-	lwz	r4,SL_LDSTDB(r1)
-	sync
-	mtspr	SPRN_LDSTDB,r4
-	isync
-	sync
-1:	
-	/* Restore 750FX specific registers */
-	bne	cr4,1f
-		/* Read PLL config & switch to PLL 0 */
-	lwz	r4,SL_HID1(r1)
-	rlwinm  r5,r4,0,16,14
-	mtspr	SPRN_HID1,r5
-		/* Wait for PLL to stabilize */
-	mftbl	r5
-2:	mftbl	r6
-	sub	r6,r6,r5
-	cmpli	cr0,r6,10000
-	ble	2b
-		/* Setup final PLL */
-	mtspr	SPRN_HID1,r4
-1:
 	/* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
 	lwz	r4,SL_SDR1(r1)
 	mtsdr1	r4
@@ -433,6 +311,26 @@
 	lwz	r4,SL_IBAT3+4(r1)
 	mtibatl	3,r4
 
+BEGIN_FTR_SECTION
+	li	r4,0
+	mtspr	SPRN_DBAT4U,r4
+	mtspr	SPRN_DBAT4L,r4
+	mtspr	SPRN_DBAT5U,r4
+	mtspr	SPRN_DBAT5L,r4
+	mtspr	SPRN_DBAT6U,r4
+	mtspr	SPRN_DBAT6L,r4
+	mtspr	SPRN_DBAT7U,r4
+	mtspr	SPRN_DBAT7L,r4
+	mtspr	SPRN_IBAT4U,r4
+	mtspr	SPRN_IBAT4L,r4
+	mtspr	SPRN_IBAT5U,r4
+	mtspr	SPRN_IBAT5L,r4
+	mtspr	SPRN_IBAT6U,r4
+	mtspr	SPRN_IBAT6L,r4
+	mtspr	SPRN_IBAT7U,r4
+	mtspr	SPRN_IBAT7L,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+
 	/* Flush all TLBs */
 	lis	r4,0x1000
 1:	addic.	r4,r4,-0x1000
@@ -477,6 +375,8 @@
 #endif /* defined(CONFIG_PMAC_PBOOK) */
 
 	.data
-	.globl sleep_storage
+	.balign	L1_CACHE_LINE_SIZE
 sleep_storage:
 	.long 0
+	.balign	L1_CACHE_LINE_SIZE, 0
+	.text
diff -urN linux-2.4.21-pre7/arch/ppc/platforms/pmac_smp.c linux-2.4.21-rc1/arch/ppc/platforms/pmac_smp.c
--- linux-2.4.21-pre7/arch/ppc/platforms/pmac_smp.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/platforms/pmac_smp.c	2003-04-21 11:48:40.000000000 -0700
@@ -3,6 +3,12 @@
  *
  * We support both the old "powersurge" SMP architecture
  * and the current Core99 (G4 PowerMac) machines.
+ * 
+ * Note that we don't support the very first rev. of
+ * Apple/DayStar 2 CPUs board, the one with the funky
+ * watchdog. Hopefully, none of these should be there except
+ * maybe internally to Apple. I should probably still add some
+ * code to detect this card though and disable SMP. --BenH.
  *
  * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
  * and Ben Herrenschmidt <benh@kernel.crashing.org>.
@@ -93,15 +99,16 @@
 static volatile u8 *psurge_sec_intr;
 static volatile u32 *psurge_start;
 
-/* what sort of powersurge board we have */
-static int psurge_type;
-
 /* values for psurge_type */
+#define PSURGE_NONE		-1
 #define PSURGE_DUAL		0
 #define PSURGE_QUAD_OKEE	1
 #define PSURGE_QUAD_COTTON	2
 #define PSURGE_QUAD_ICEGRASS	3
 
+/* what sort of powersurge board we have */
+static int psurge_type = PSURGE_NONE;
+
 volatile static long int core99_l2_cache;
 volatile static long int core99_l3_cache;
 
@@ -137,113 +144,13 @@
 	}
 }
 
-/* Some CPU registers have to be saved from the first CPU and
- * applied to others. Note that we override what is setup by
- * the cputable intentionally.
- */
-
-#define	reg_hid0	0
-#define	reg_hid1	1
-#define	reg_msscr0	2
-#define	reg_msssr0	3
-#define	reg_ictrl	4
-#define	reg_ldstcr	5
-#define	reg_ldstdb	6
-#define	reg_count	7
-
-#define stringify __stringify
-
-static unsigned long cpu_regs[reg_count];
-
-static void __pmac
-cpu_setup_grab(void)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Read cache setting of CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		cpu_regs[reg_hid0] = mfspr(SPRN_HID0);
-		cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0);
-		cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0);
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		cpu_regs[reg_hid1] = mfspr(SPRN_HID1);
-		cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL);
-		cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR);
-		cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB);
-	}
-	flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]);
-}
-
-static void __pmac
-cpu_setup_apply(int cpu_nr)
-{
-	unsigned int pvers = mfspr(SPRN_PVR)>>16;
-
-	/* Apply cache setting from CPU 0 */
-	core99_init_caches();
-
-	/* 7400/7410/7450 */
-	if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0,4*"stringify(reg_hid0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID0)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_msscr0)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_MSSCR0)", %0\n"
-			"isync;sync\n"
-//			"lwz	%0, "stringify(reg_msssr0)"(%1)\n"
-//			"sync\n"
-//			"mtspr	"stringify(SPRN_MSSSR0)", %0\n"
-//			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));			
-	}
-	/* 7410 only */
-	if (pvers == 0x800c) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"li	%0, 0\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_L2CR2)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp));		
-	}
-	/* 7450 only */
-	if (pvers == 0x8000) {
-		unsigned long tmp;
-		__asm__ __volatile__ (
-			"lwz	%0, 4*"stringify(reg_hid1)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_HID1)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ictrl)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_ICTRL)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstcr)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTCR)", %0\n"
-			"isync;sync\n"
-			"lwz	%0, 4*"stringify(reg_ldstdb)"(%1)\n"
-			"sync\n"
-			"mtspr	"stringify(SPRN_LDSTDB)", %0\n"
-			"isync;sync\n"
-		: "=&r" (tmp) : "r" (cpu_regs));		
-	}
-}
-
 /*
  * Set and clear IPIs for powersurge.
  */
 static inline void psurge_set_ipi(int cpu)
 {
+	if (psurge_type == PSURGE_NONE)
+		return;
 	if (cpu == 0)
 		in_be32(psurge_pri_intr);
 	else if (psurge_type == PSURGE_DUAL)
@@ -255,10 +162,14 @@
 static inline void psurge_clr_ipi(int cpu)
 {
 	if (cpu > 0) {
-		if (psurge_type == PSURGE_DUAL)
+		switch(psurge_type) {
+		case PSURGE_DUAL:
 			out_8(psurge_sec_intr, ~0);
-		else
+		case PSURGE_NONE:
+			break;
+		default:
 			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
+		}
 	}
 }
 
@@ -410,6 +321,7 @@
 		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
 			/* not a dual-cpu card */
 			iounmap((void *) hhead_base);
+			psurge_type = PSURGE_NONE;
 			return 1;
 		}
 		ncpus = 2;
@@ -496,15 +408,19 @@
 {
 
 	if (cpu_nr == 0) {
+		/* If we failed to start the second CPU, we should still
+		 * send it an IPI to start the timebase & DEC or we might
+		 * have them stuck.
+		 */
 		if (smp_num_cpus < 2)
-			return;
+			goto sync_tb;
 		/* reset the entry point so if we get another intr we won't
 		 * try to startup again */
 		out_be32(psurge_start, 0x100);
-		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
+		if (request_irq(30, psurge_primary_intr, SA_INTERRUPT, "primary IPI", 0))
 			printk(KERN_ERR "Couldn't get primary IPI interrupt");
 	}
-
+sync_tb:
 	if (psurge_type == PSURGE_DUAL)
 		psurge_dual_sync_tb(cpu_nr);
 }
@@ -526,8 +442,11 @@
 		openpic_request_IPIs();
 		for (i = 1; i < ncpus; ++i)
 			smp_hw_index[i] = i;
+#ifdef CONFIG_6xx	/* XXX */
 		powersave_nap = 0;
-		cpu_setup_grab();
+#endif
+		/* Read cache setting of CPU 0 */
+		core99_init_caches();
 	}
 
 	return ncpus;
@@ -591,9 +510,12 @@
 static void __init
 smp_core99_setup_cpu(int cpu_nr)
 {
-	/* Setup some registers */
+
+	/* Setup some critical registers
+	 * and apply cache setting from CPU 0
+	 */
 	if (cpu_nr != 0)
-		cpu_setup_apply(cpu_nr);
+		core99_init_caches();
 	
 	/* Setup openpic */
 	do_openpic_setup_cpu();
@@ -605,16 +527,16 @@
 
 /* PowerSurge-style Macs */
 struct smp_ops_t psurge_smp_ops __pmacdata = {
-	smp_psurge_message_pass,
-	smp_psurge_probe,
-	smp_psurge_kick_cpu,
-	smp_psurge_setup_cpu,
+	.message_pass	= smp_psurge_message_pass,
+	.probe		= smp_psurge_probe,
+	.kick_cpu	= smp_psurge_kick_cpu,
+	.setup_cpu	= smp_psurge_setup_cpu,
 };
 
 /* Core99 Macs (dual G4s) */
 struct smp_ops_t core99_smp_ops __pmacdata = {
-	smp_openpic_message_pass,
-	smp_core99_probe,
-	smp_core99_kick_cpu,
-	smp_core99_setup_cpu,
+	.message_pass	= smp_openpic_message_pass,
+	.probe		= smp_core99_probe,
+	.kick_cpu	= smp_core99_kick_cpu,
+	.setup_cpu	= smp_core99_setup_cpu,
 };
diff -urN linux-2.4.21-pre7/arch/ppc/xmon/start.c linux-2.4.21-rc1/arch/ppc/xmon/start.c
--- linux-2.4.21-pre7/arch/ppc/xmon/start.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/xmon/start.c	2003-04-21 11:48:40.000000000 -0700
@@ -11,9 +11,11 @@
 #include <linux/cuda.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/sysrq.h>
 #include <asm/prom.h>
 #include <asm/bootx.h>
 #include <asm/machdep.h>
+#include <asm/errno.h>
 #include <asm/pmac_feature.h>
 #include <asm/processor.h>
 #include <asm/delay.h>
@@ -23,11 +25,10 @@
 #endif
 
 static volatile unsigned char *sccc, *sccd;
-unsigned long TXRDY, RXRDY;
+unsigned int TXRDY, RXRDY, DLAB;
 extern void xmon_printf(const char *fmt, ...);
 static int xmon_expect(const char *str, unsigned int timeout);
 
-static int console;
 static int use_screen;
 static int via_modem;
 static int xmon_use_sccb;
@@ -45,12 +46,65 @@
 
 void buf_access(void)
 {
-	if ( _machine == _MACH_chrp )
-		sccd[3] &= ~0x80;	/* reset DLAB */
+	if (DLAB)
+		sccd[3] &= ~DLAB;	/* reset DLAB */
 }
 
 extern int adb_init(void);
 
+#ifdef CONFIG_ALL_PPC
+/*
+ * This looks in the "ranges" property for the primary PCI host bridge
+ * to find the physical address of the start of PCI/ISA I/O space.
+ * It is basically a cut-down version of pci_process_bridge_OF_ranges.
+ */
+static unsigned long chrp_find_phys_io_base(void)
+{
+	struct device_node *node;
+	unsigned int *ranges;
+	unsigned long base = CHRP_ISA_IO_BASE;
+	int rlen = 0;
+	int np;
+
+	node = find_devices("isa");
+	if (node != NULL) {
+		node = node->parent;
+		if (node == NULL || node->type == NULL
+		    || strcmp(node->type, "pci") != 0)
+			node = NULL;
+	}
+	if (node == NULL)
+		node = find_devices("pci");
+	if (node == NULL)
+		return base;
+
+	ranges = (unsigned int *) get_property(node, "ranges", &rlen);
+	np = prom_n_addr_cells(node) + 5;
+	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
+		if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
+			/* I/O space starting at 0, grab the phys base */
+			base = ranges[np - 3];
+			break;
+		}
+		ranges += np;
+	}
+	return base;
+}
+#endif /* CONFIG_ALL_PPC */
+
+static void sysrq_handle_xmon(int key, struct pt_regs *regs,
+			      struct kbd_struct *kbd, struct tty_struct *tty)
+{
+	xmon(regs);
+}
+
+static struct sysrq_key_op sysrq_xmon_op = 
+{
+	handler:	sysrq_handle_xmon,
+	help_msg:	"Xmon",
+	action_msg:	"Entering xmon\n",
+};
+
 void
 xmon_map_scc(void)
 {
@@ -129,18 +183,22 @@
 		base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
 		sccc = base + (addr & ~PAGE_MASK);
 		sccd = sccc + 0x10;
-	}
-	else
-	{
-		/* should already be mapped by the kernel boot */
-		sccc = (volatile unsigned char *) (isa_io_base + 0x3fd);
-		sccd = (volatile unsigned char *) (isa_io_base + 0x3f8);
+
+	} else {
+		base = (volatile unsigned char *) isa_io_base;
+		if (_machine == _MACH_chrp)
+			base = (volatile unsigned char *)
+				ioremap(chrp_find_phys_io_base(), 0x1000);
+
+		sccc = base + 0x3fd;
+		sccd = base + 0x3f8;
 		if (xmon_use_sccb) {
 			sccc -= 0x100;
 			sccd -= 0x100;
 		}
 		TXRDY = 0x20;
 		RXRDY = 1;
+		DLAB = 0x80;
 	}
 #elif defined(CONFIG_GEMINI)
 	/* should already be mapped by the kernel boot */
@@ -148,8 +206,16 @@
 	sccd = (volatile unsigned char *) 0xffeffb08;
 	TXRDY = 0x20;
 	RXRDY = 1;
-	console = 1;
+	DLAB = 0x80;
+#elif defined(CONFIG_405GP) || defined(CONFIG_405LP) || defined(CONFIG_405EP)
+	sccc = (volatile unsigned char *)0xef600305;
+	sccd = (volatile unsigned char *)0xef600300;
+	TXRDY = 0x20;
+	RXRDY = 1;
+	DLAB = 0x80;
 #endif /* platform */
+
+	__sysrq_put_key_op('x', &sysrq_xmon_op);
 }
 
 static int scc_initialized = 0;
@@ -206,8 +272,6 @@
 			ct = 1;
 			--i;
 		} else {
-			if (console)
-				printk("%c", c);
 			ct = 0;
 		}
 		buf_access();
diff -urN linux-2.4.21-pre7/arch/ppc/xmon/xmon.c linux-2.4.21-rc1/arch/ppc/xmon/xmon.c
--- linux-2.4.21-pre7/arch/ppc/xmon/xmon.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/ppc/xmon/xmon.c	2003-04-21 11:48:40.000000000 -0700
@@ -11,6 +11,10 @@
 #include <asm/string.h>
 #include <asm/prom.h>
 #include <asm/bitops.h>
+#include <asm/bootx.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
 #include <asm/mmu.h>
 
 #include "nonstdio.h"
@@ -23,6 +27,7 @@
 static unsigned long cpus_in_xmon = 0;
 static unsigned long got_xmon = 0;
 static volatile int take_xmon = -1;
+static int xmon_owner = -1;
 #endif /* CONFIG_SMP */
 
 static unsigned adrs;
@@ -188,20 +193,31 @@
 	xmon_enter();
 	excprint(excp);
 #ifdef CONFIG_SMP
-	if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
-		for (;;)
-			;
-	while (test_and_set_bit(0, &got_xmon)) {
-		if (take_xmon == smp_processor_id()) {
-			take_xmon = -1;
-			break;
+	set_bit(smp_processor_id(), &cpus_in_xmon);
+	if (smp_processor_id() != xmon_owner) {
+		while (test_and_set_bit(0, &got_xmon)) {
+			if (take_xmon == smp_processor_id()) {
+				take_xmon = -1;
+				break;
+			}
 		}
+		xmon_owner = smp_processor_id();
 	}
 	/*
 	 * XXX: breakpoints are removed while any cpu is in xmon
 	 */
 #endif /* CONFIG_SMP */
 	remove_bpts();
+#ifdef CONFIG_PMAC_BACKLIGHT
+	if( setjmp(bus_error_jmp) == 0 ) {
+		debugger_fault_handler = handle_fault;
+		sync();
+		set_backlight_enable(1);
+		set_backlight_level(BACKLIGHT_MAX);
+		sync();
+	}
+	debugger_fault_handler = 0;
+#endif	/* CONFIG_PMAC_BACKLIGHT */
 	cmd = cmds(excp);
 	if (cmd == 's') {
 		xmon_trace[smp_processor_id()] = SSTEP;
@@ -217,6 +233,7 @@
 	xmon_regs[smp_processor_id()] = 0;
 #ifdef CONFIG_SMP
 	clear_bit(0, &got_xmon);
+	xmon_owner = -1;
 	clear_bit(smp_processor_id(), &cpus_in_xmon);
 #endif /* CONFIG_SMP */
 	set_msr(msr);		/* restore interrupt enable */
@@ -502,11 +519,13 @@
 	}
 	/* try to switch to cpu specified */
 	take_xmon = cpu;
+	xmon_owner = -1;
 	timeout = 10000000;
 	while (take_xmon >= 0) {
 		if (--timeout == 0) {
 			/* yes there's a race here */
 			take_xmon = -1;
+			xmon_owner = smp_processor_id();
 			printf("cpu %u didn't take control\n", cpu);
 			return;
 		}
@@ -515,6 +534,7 @@
 	while (test_and_set_bit(0, &got_xmon)) {
 		if (take_xmon == smp_processor_id()) {
 			take_xmon = -1;
+			xmon_owner = smp_processor_id();
 			break;
 		}
 	}
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/entry.S linux-2.4.21-rc1/arch/sparc64/kernel/entry.S
--- linux-2.4.21-pre7/arch/sparc64/kernel/entry.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/kernel/entry.S	2003-04-21 11:48:40.000000000 -0700
@@ -272,7 +272,7 @@
 	.align		32
 fp_other_bounce:
 	call		do_fpother
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -499,7 +499,7 @@
 	ba,pt		%xcc, etrap
 109:	 or		%g7, %lo(109b), %g7
 	call		catch_disabled_ivec
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -606,7 +606,7 @@
 	done
 utrap_ill:
         call		bad_trap
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -711,7 +711,7 @@
 	mov		11, %o0
 	mov		0, %o1
 	call		sparc_floppy_irq
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+	 add		%sp, PTREGS_OFF, %o2
 
 	b,pt		%xcc, rtrap
 	 clr		%l6
@@ -757,7 +757,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		data_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -778,7 +778,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		instruction_access_exception_tl1
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -797,7 +797,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		instruction_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -889,7 +889,7 @@
 
 	mov	%l5, %o1
 	call	cee_log
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o2
+	 add	%sp, PTREGS_OFF, %o2
 	ba,a,pt	%xcc, rtrap_clr_l6
 
 	/* Capture I/D/E-cache state into per-cpu error scoreboard.
@@ -1104,7 +1104,7 @@
 	 rd		%pc, %g7
 	mov		0x0, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1134,7 +1134,7 @@
 	 rd		%pc, %g7
 	mov		0x1, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1196,7 +1196,7 @@
 1:	or		%g7, %lo(1b), %g7
 	mov		0x2, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1234,7 +1234,7 @@
 1:	or		%g7, %lo(1b), %g7
 	mov		0x3, %o0
 	call		cheetah_plus_parity_error
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, PTREGS_OFF, %o1
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	
@@ -1290,7 +1290,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_fecc_handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	/* Our caller has disabled I-cache and performed membar Sync. */
@@ -1316,7 +1316,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_cee_handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	/* Our caller has disabled I-cache+D-cache and performed membar Sync. */
@@ -1342,7 +1342,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		cheetah_deferred_handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	.globl		__do_privact
@@ -1354,7 +1354,7 @@
 	ba,pt		%xcc, etrap
 109:	or		%g7, %lo(109b), %g7
 	call		do_privact
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1381,7 +1381,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		mem_address_unaligned
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1399,7 +1399,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		handle_lddfmna
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
@@ -1417,14 +1417,14 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		handle_stdfmna
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 
 	.globl	breakpoint_trap
 breakpoint_trap:
 	call		sparc_breakpoint
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 nop
 
@@ -1460,9 +1460,9 @@
 	call	sys_getppid
 	 nop
 	call	sys_getpid
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt	%xcc, ret_sys_call
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 
 	/* SunOS getuid() returns uid in %o0 and euid in %o1 */
 	.globl	sunos_getuid
@@ -1470,9 +1470,9 @@
 	call	sys32_geteuid16
 	 nop
 	call	sys32_getuid16
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt	%xcc, ret_sys_call
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 
 	/* SunOS getgid() returns gid in %o0 and egid in %o1 */
 	.globl	sunos_getgid
@@ -1480,9 +1480,9 @@
 	call	sys32_getegid16
 	 nop
 	call	sys32_getgid16
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt	%xcc, ret_sys_call
-	 stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx	%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 #endif
 
 	/* SunOS's execv() call only specifies the argv argument, the
@@ -1494,14 +1494,14 @@
 	ba,pt		%xcc, execve_merge
 	 or		%g1, %lo(sparc_execve), %g1
 sunos_execv:
-	stx		%g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
+	stx		%g0, [%sp + PTREGS_OFF + PT_V9_I2]
 sys32_execve:
 	sethi		%hi(sparc32_execve), %g1
 	or		%g1, %lo(sparc32_execve), %g1
 execve_merge:
 	flushw
 	jmpl		%g1, %g0
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 	.globl	sys_pipe, sys_sigpause, sys_nis_syscall
 	.globl	sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend
@@ -1512,12 +1512,12 @@
 	.globl	sys32_sigstack
 	.align	32
 sys_pipe:	ba,pt		%xcc, sparc_pipe
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		 add		%sp, PTREGS_OFF, %o0
 sys_nis_syscall:ba,pt		%xcc, c_sys_nis_syscall
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		 add		%sp, PTREGS_OFF, %o0
 sys_memory_ordering:
 		ba,pt		%xcc, sparc_memory_ordering
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+		 add		%sp, PTREGS_OFF, %o1
 sys_sigaltstack:ba,pt		%xcc, do_sigaltstack
 		 add		%i6, STACK_BIAS, %o2
 sys32_sigstack:	ba,pt		%xcc, do_sys32_sigstack
@@ -1527,41 +1527,41 @@
 		 mov		%i6, %o2
 
 		.align		32
-sys_sigsuspend:	add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+sys_sigsuspend:	add		%sp, PTREGS_OFF, %o0
 		call		do_sigsuspend
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+		add		%sp, PTREGS_OFF, %o2
 		call		do_rt_sigsuspend
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys32_rt_sigsuspend: /* NOTE: %o0,%o1 have a correct value already */
 		srl		%o0, 0, %o0
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+		add		%sp, PTREGS_OFF, %o2
 		call		do_rt_sigsuspend32
 		 add		%o7, 1f-.-4, %o7
 		/* NOTE: %o0 has a correct value already */
-sys_sigpause:	add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+sys_sigpause:	add		%sp, PTREGS_OFF, %o1
 		call		do_sigpause
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys32_sigreturn:
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		add		%sp, PTREGS_OFF, %o0
 		call		do_sigreturn32
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys_rt_sigreturn:
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		add		%sp, PTREGS_OFF, %o0
 		call		do_rt_sigreturn
 		 add		%o7, 1f-.-4, %o7
 		nop
 sys32_rt_sigreturn:
-		add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+		add		%sp, PTREGS_OFF, %o0
 		call		do_rt_sigreturn32
 		 add		%o7, 1f-.-4, %o7
 		nop
-sys_ptrace:	add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+sys_ptrace:	add		%sp, PTREGS_OFF, %o0
 		call		do_ptrace
 		 add		%o7, 1f-.-4, %o7
 		nop
@@ -1612,7 +1612,7 @@
 		movrz		%o1, %fp, %o1
 		mov		0, %o3
 		ba,pt		%xcc, do_fork
-		 add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+		 add		%sp, PTREGS_OFF, %o2
 ret_from_syscall:
 		/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in
 		 * %o7 for us.  Check performance counter stuff too.
@@ -1638,7 +1638,7 @@
 		rd		%pic, %g0
 
 1:		b,pt		%xcc, ret_sys_call
-		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+		 ldx		[%sp + PTREGS_OFF + PT_V9_I0], %o0
 sparc_exit:	wrpr		%g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate
 		rdpr		%otherwin, %g1
 		rdpr		%cansave, %g3
@@ -1686,7 +1686,7 @@
 	sll		%g1, 2, %l4				! IEU0	Group
 #ifdef SYSCALL_TRACING
 	call		syscall_trace_entry
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	srl		%i0, 0, %o0
 #endif
 	mov		%i4, %o4				! IEU1
@@ -1714,7 +1714,7 @@
 	sll		%g1, 2, %l4				! IEU0	Group
 #ifdef SYSCALL_TRACING
 	call		syscall_trace_entry
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	mov		%i0, %o0
 #endif
 	mov		%i1, %o1				! IEU1
@@ -1731,16 +1731,16 @@
 	 mov		%i5, %o5				! IEU0
 	nop
 
-3:	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+3:	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 ret_sys_call:
 #ifdef SYSCALL_TRACING
 	mov		%o0, %o1
 	call		syscall_trace_exit
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	mov		%o1, %o0
 #endif
-	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
-	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+	ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
+	ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
 	sra		%o0, 0, %o0
 	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
 	cmp		%o0, -ENOIOCTLCMD
@@ -1749,12 +1749,12 @@
 
 	 andcc		%l0, 0x02, %l6	
 	andn		%g3, %g2, %g3		/* System call success, clear Carry condition code. */
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]	
 	bne,pn		%icc, linux_syscall_trace2
 	 add		%l1, 0x4, %l2				         ! npc = npc+4
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	ba,pt		%xcc, rtrap_clr_l6
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 
 1:
 	/* System call failure, set Carry condition code.
@@ -1762,21 +1762,21 @@
 	 */
 	sub		%g0, %o0, %o0
 	or		%g3, %g2, %g3
-	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 	mov		1, %l6
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
 	bne,pn		%icc, linux_syscall_trace2
 	 add		%l1, 0x4, %l2				         !npc = npc+4
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 
 	b,pt		%xcc, rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 linux_syscall_trace2:
 	call		syscall_trace
 	 nop
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	ba,pt		%xcc, rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 
 	.align		32
 	.globl		__flushw_user
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/etrap.S linux-2.4.21-rc1/arch/sparc64/kernel/etrap.S
--- linux-2.4.21-pre7/arch/sparc64/kernel/etrap.S	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.21-rc1/arch/sparc64/kernel/etrap.S	2003-04-21 11:48:40.000000000 -0700
@@ -13,7 +13,7 @@
 #include <asm/head.h>
 #include <asm/processor.h>
 
-#define		TASK_REGOFF		(THREAD_SIZE-TRACEREG_SZ-REGWIN_SZ)
+#define		TASK_REGOFF		(THREAD_SIZE-TRACEREG_SZ-STACKFRAME_SZ)
 #define		ETRAP_PSTATE1		(PSTATE_RMO | PSTATE_PRIV)
 #define		ETRAP_PSTATE2		(PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE)
 
@@ -32,7 +32,7 @@
 		andcc	%g1, TSTATE_PRIV, %g0					! IEU1
 		or	%g1, %g3, %g1						! IEU0		Group
 		bne,pn	%xcc, 1f							! CTI
-		 sub	%sp, REGWIN_SZ+TRACEREG_SZ-STACK_BIAS, %g2		! IEU1
+		 sub	%sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2		! IEU1
 		wrpr	%g0, 7, %cleanwin					! Single	Group+4bubbles
 
 		sethi	%hi(TASK_REGOFF), %g2					! IEU0		Group		
@@ -44,12 +44,12 @@
 		wr	%g0, 0, %fprs						! Single	Group+4bubbles
 1:		rdpr	%tpc, %g3						! Single	Group
 
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE]		! Store		Group
 		rdpr	%tnpc, %g1						! Single	Group
-		stx	%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
+		stx	%g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]			! Store		Group
 		rd	%y, %g3							! Single	Group+4bubbles
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
-		st	%g3, [%g2 + REGWIN_SZ + PT_V9_Y]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]			! Store		Group
+		st	%g3, [%g2 + STACKFRAME_SZ + PT_V9_Y]			! Store		Group
 		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical	! Single	Group
 		mov	%g6, %l6						! IEU0		Group
 
@@ -73,25 +73,25 @@
 
 		mov	%g7, %l2						! IEU1
 		wrpr	%g0, ETRAP_PSTATE1, %pstate				! Single	Group+4bubbles
-		stx	%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
-		stx	%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
-		stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
-		stx	%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
-		stx	%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
-		stx	%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
-
-		stx	%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
-		stx	%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
-		stx	%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
-		stx	%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
-		stx	%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
-		stx	%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
+		stx	%g1, [%sp + PTREGS_OFF + PT_V9_G1]		! Store		Group
+		stx	%g2, [%sp + PTREGS_OFF + PT_V9_G2]		! Store		Group
+		stx	%g3, [%sp + PTREGS_OFF + PT_V9_G3]		! Store		Group
+		stx	%g4, [%sp + PTREGS_OFF + PT_V9_G4]		! Store		Group
+		stx	%g5, [%sp + PTREGS_OFF + PT_V9_G5]		! Store		Group
+		stx	%g6, [%sp + PTREGS_OFF + PT_V9_G6]		! Store		Group
+
+		stx	%g7, [%sp + PTREGS_OFF + PT_V9_G7]		! Store		Group
+		stx	%i0, [%sp + PTREGS_OFF + PT_V9_I0]		! Store		Group
+		stx	%i1, [%sp + PTREGS_OFF + PT_V9_I1]		! Store		Group
+		stx	%i2, [%sp + PTREGS_OFF + PT_V9_I2]		! Store		Group
+		stx	%i3, [%sp + PTREGS_OFF + PT_V9_I3]		! Store		Group
+		stx	%i4, [%sp + PTREGS_OFF + PT_V9_I4]		! Store		Group
 		sethi	%uhi(PAGE_OFFSET), %g4					! IEU0
-		stx	%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
+		stx	%i5, [%sp + PTREGS_OFF + PT_V9_I5]		! Store		Group
 
-		stx	%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
+		stx	%i6, [%sp + PTREGS_OFF + PT_V9_I6]		! Store		Group
 		sllx	%g4, 32, %g4						! IEU0
-		stx	%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
+		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]		! Store		Group
 		wrpr	%g0, ETRAP_PSTATE2, %pstate				! Single	Group+4bubbles
 		jmpl	%l2 + 0x4, %g0						! CTI		Group
 		 mov	%l6, %g6						! IEU0
@@ -165,7 +165,7 @@
 		stx	%g1, [%g2 + STACK_BIAS + 0x80]
 
 		rdpr	%tstate, %g1						! Single	Group+4bubbles
-		sub	%g2, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2		! IEU1
+		sub	%g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2	! IEU1
 		ba,pt	%xcc, 1b						! CTI		Group
 		 andcc	%g1, TSTATE_PRIV, %g0					! IEU0
 
@@ -177,7 +177,7 @@
 		andcc	%g1, TSTATE_PRIV, %g0					! IEU1
 		or	%g1, %g3, %g1						! IEU0		Group
 		bne,pn	%xcc, 1f						! CTI
-		 sub	%sp, (REGWIN_SZ+TRACEREG_SZ-STACK_BIAS), %g2		! IEU1
+		 sub	%sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2	! IEU1
 		wrpr	%g0, 7, %cleanwin					! Single	Group+4bubbles
 
 		sllx	%g1, 51, %g3						! IEU0		Group
@@ -187,11 +187,11 @@
 		 add	%g6, %g2, %g2						! IEU0		Group
 		wr	%g0, 0, %fprs						! Single	Group+4bubbles
 1:		rdpr	%tpc, %g3						! Single	Group
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE]		! Store		Group
 
 		rdpr	%tnpc, %g1						! Single	Group
-		stx	%g3, [%g2 + REGWIN_SZ + PT_V9_TPC]			! Store		Group
-		stx	%g1, [%g2 + REGWIN_SZ + PT_V9_TNPC]			! Store		Group
+		stx	%g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]			! Store		Group
+		stx	%g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]			! Store		Group
 		save	%g2, -STACK_BIAS, %sp	! Ordering here is critical	! Single	Group
 		mov	%g6, %l6						! IEU0		Group
 		bne,pn	%xcc, 2f						! CTI		
@@ -212,34 +212,34 @@
 		mov	%g5, %l5						! IEU0		Group
 		add	%g7, 0x4, %l2						! IEU1
 		wrpr	%g0, ETRAP_PSTATE1, %pstate				! Single	Group+4bubbles
-		stx	%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]		! Store		Group
-		stx	%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]		! Store		Group
+		stx	%g1, [%sp + PTREGS_OFF + PT_V9_G1]		! Store		Group
+		stx	%g2, [%sp + PTREGS_OFF + PT_V9_G2]		! Store		Group
 		sllx	%l7, 24, %l7						! IEU0
 
-		stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]		! Store		Group
+		stx	%g3, [%sp + PTREGS_OFF + PT_V9_G3]		! Store		Group
 		rdpr	%cwp, %l0						! Single	Group
-		stx	%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]		! Store		Group
-		stx	%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]		! Store		Group
-		stx	%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]		! Store		Group
-		stx	%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]		! Store		Group
+		stx	%g4, [%sp + PTREGS_OFF + PT_V9_G4]		! Store		Group
+		stx	%g5, [%sp + PTREGS_OFF + PT_V9_G5]		! Store		Group
+		stx	%g6, [%sp + PTREGS_OFF + PT_V9_G6]		! Store		Group
+		stx	%g7, [%sp + PTREGS_OFF + PT_V9_G7]		! Store		Group
 		or	%l7, %l0, %l7						! IEU0
 		sethi	%hi(TSTATE_RMO | TSTATE_PEF), %l0			! IEU1
 
 		or	%l7, %l0, %l7						! IEU0		Group
 		wrpr	%l2, %tnpc						! Single	Group+4bubbles
 		wrpr	%l7, (TSTATE_PRIV | TSTATE_IE), %tstate			! Single	Group+4bubbles
-		stx	%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]		! Store		Group
-		stx	%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]		! Store		Group
-		stx	%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]		! Store		Group
-		stx	%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]		! Store		Group
-		stx	%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]		! Store		Group
+		stx	%i0, [%sp + PTREGS_OFF + PT_V9_I0]		! Store		Group
+		stx	%i1, [%sp + PTREGS_OFF + PT_V9_I1]		! Store		Group
+		stx	%i2, [%sp + PTREGS_OFF + PT_V9_I2]		! Store		Group
+		stx	%i3, [%sp + PTREGS_OFF + PT_V9_I3]		! Store		Group
+		stx	%i4, [%sp + PTREGS_OFF + PT_V9_I4]		! Store		Group
 
 		sethi	%uhi(PAGE_OFFSET), %g4					! IEU0
-		stx	%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]		! Store		Group
-		stx	%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]		! Store		Group
+		stx	%i5, [%sp + PTREGS_OFF + PT_V9_I5]		! Store		Group
+		stx	%i6, [%sp + PTREGS_OFF + PT_V9_I6]		! Store		Group
 		sllx	%g4, 32, %g4						! IEU0
 		mov	%l6, %g6						! IEU1
-		stx	%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]		! Store		Group
+		stx	%i7, [%sp + PTREGS_OFF + PT_V9_I7]		! Store		Group
 		done
 		nop
 
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/head.S linux-2.4.21-rc1/arch/sparc64/kernel/head.S
--- linux-2.4.21-pre7/arch/sparc64/kernel/head.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/kernel/head.S	2003-04-21 11:48:40.000000000 -0700
@@ -551,7 +551,7 @@
 	wr	%g0, ASI_P, %asi
 	mov	1, %g5
 	sllx	%g5, THREAD_SHIFT, %g5
-	sub	%g5, (REGWIN_SZ + STACK_BIAS), %g5
+	sub	%g5, (STACKFRAME_SZ + STACK_BIAS), %g5
 	add	%g6, %g5, %sp
 	mov	0, %fp
 
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/itlb_base.S linux-2.4.21-rc1/arch/sparc64/kernel/itlb_base.S
--- linux-2.4.21-pre7/arch/sparc64/kernel/itlb_base.S	2001-08-28 07:09:44.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/kernel/itlb_base.S	2003-04-21 11:48:40.000000000 -0700
@@ -59,7 +59,7 @@
 
 /* ITLB ** ICACHE line 3: Finish faults + window fixups	*/
 	call		do_sparc64_fault		! Call fault handler
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
+	 add		%sp, PTREGS_OFF, %o0		! Compute pt_regs arg
 	ba,pt		%xcc, rtrap_clr_l6		! Restore cpu state
 	 nop
 winfix_trampoline:
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/process.c linux-2.4.21-rc1/arch/sparc64/kernel/process.c
--- linux-2.4.21-pre7/arch/sparc64/kernel/process.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/kernel/process.c	2003-04-21 11:48:40.000000000 -0700
@@ -39,6 +39,7 @@
 #include <asm/pstate.h>
 #include <asm/elf.h>
 #include <asm/fpumacro.h>
+#include <asm/head.h>
 
 /* #define VERBOSE_SHOWREGS */
 
@@ -362,8 +363,8 @@
 	    regs->u_regs[14] >= (long)current - PAGE_SIZE &&
 	    regs->u_regs[14] < (long)current + 6 * PAGE_SIZE) {
 		printk ("*********parent**********\n");
-		__show_regs((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ));
-		idump_from_user(((struct pt_regs *)(regs->u_regs[14] + STACK_BIAS + REGWIN_SZ))->tpc);
+		__show_regs((struct pt_regs *)(regs->u_regs[14] + PTREGS_OFF));
+		idump_from_user(((struct pt_regs *)(regs->u_regs[14] + PTREGS_OFF))->tpc);
 		printk ("*********endpar**********\n");
 	}
 #endif
@@ -538,11 +539,11 @@
 
 	flush_user_windows();
 	if ((window = t->w_saved) != 0) {
-		int winsize = REGWIN_SZ;
+		int winsize = sizeof(struct reg_window);
 		int bias = 0;
 
 		if (t->flags & SPARC_FLAG_32BIT)
-			winsize = REGWIN32_SZ;
+			winsize = sizeof(struct reg_window32);
 		else
 			bias = STACK_BIAS;
 
@@ -563,11 +564,11 @@
 {
 	struct thread_struct *t = &current->thread;
 	unsigned long window;
-	int winsize = REGWIN_SZ;
+	int winsize = sizeof(struct reg_window);
 	int bias = 0;
 
 	if (t->flags & SPARC_FLAG_32BIT)
-		winsize = REGWIN32_SZ;
+		winsize = sizeof(struct reg_window32);
 	else
 		bias = STACK_BIAS;
 
@@ -610,11 +611,11 @@
 #endif
 
 	/* Calculate offset to stack_frame & pt_regs */
-	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
-	memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
+	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ));
+	memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ));
 	t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
 	t->flags |= SPARC_FLAG_NEWCHILD;
-	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
+	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf));
 	t->cwp = (regs->tstate + 1) & TSTATE_CWP;
 	t->fpsaved[0] = 0;
 
@@ -634,7 +635,7 @@
 		flush_register_windows();
 		memcpy((void *)(t->ksp + STACK_BIAS),
 		       (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
-		       sizeof(struct reg_window));
+		       sizeof(struct sparc_stackf));
 		t->kregs->u_regs[UREG_G6] = (unsigned long) p;
 	} else {
 		if (t->flags & SPARC_FLAG_32BIT) {
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/rtrap.S linux-2.4.21-rc1/arch/sparc64/kernel/rtrap.S
--- linux-2.4.21-pre7/arch/sparc64/kernel/rtrap.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/kernel/rtrap.S	2003-04-21 11:48:40.000000000 -0700
@@ -55,7 +55,7 @@
 		mov			%l5, %o2
 		mov			%l6, %o3
 
-		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		add			%sp, PTREGS_OFF, %o1
 		call			do_signal
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
@@ -94,7 +94,7 @@
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
-		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		add			%sp, PTREGS_OFF, %o1
 
 		call			do_signal
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
@@ -122,7 +122,7 @@
 		clr			%o0
 		mov			%l5, %o2
 		mov			%l6, %o3
-		add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+		add			%sp, PTREGS_OFF, %o1
 		call			do_signal
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/signal32.c linux-2.4.21-rc1/arch/sparc64/kernel/signal32.c
--- linux-2.4.21-pre7/arch/sparc64/kernel/signal32.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/kernel/signal32.c	2003-04-21 11:48:40.000000000 -0700
@@ -828,7 +828,7 @@
 	save_and_clear_fpu();
 	
 	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
-	sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, REGWIN_SZ + SVR4_SF_ALIGNED);
+	sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, sizeof(struct reg_window32) + SVR4_SF_ALIGNED);
 
 	if (invalid_frame_pointer (sfp, sizeof (*sfp))){
 #ifdef DEBUG_SIGNALS
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/trampoline.S linux-2.4.21-rc1/arch/sparc64/kernel/trampoline.S
--- linux-2.4.21-pre7/arch/sparc64/kernel/trampoline.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/kernel/trampoline.S	2003-04-21 11:48:40.000000000 -0700
@@ -198,7 +198,7 @@
 
 	mov		1, %g5
 	sllx		%g5, THREAD_SHIFT, %g5
-	sub		%g5, (REGWIN_SZ + STACK_BIAS), %g5
+	sub		%g5, (STACKFRAME_SZ + STACK_BIAS), %g5
 	add		%g6, %g5, %sp
 	mov		0, %fp
 
diff -urN linux-2.4.21-pre7/arch/sparc64/kernel/winfixup.S linux-2.4.21-rc1/arch/sparc64/kernel/winfixup.S
--- linux-2.4.21-pre7/arch/sparc64/kernel/winfixup.S	2000-03-27 10:35:56.000000000 -0800
+++ linux-2.4.21-rc1/arch/sparc64/kernel/winfixup.S	2003-04-21 11:48:40.000000000 -0700
@@ -81,7 +81,7 @@
 	 * since we must preserve %l5 and %l6, see comment above.
 	 */
 	call		do_sparc64_fault
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 nop						! yes, nop is correct
 
@@ -159,7 +159,7 @@
 	ba,pt		%xcc, etrap
 	 rd		%pc, %g7
 	call		do_sparc64_fault
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
 	.globl		winfix_mna, fill_fixup_mna, spill_fixup_mna
@@ -199,7 +199,7 @@
 	mov		%o7, %g6			! Get current back.
 	sllx		%g4, 32, %g4			! Finish it.
 	call		mem_address_unaligned
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
@@ -260,7 +260,7 @@
 	mov		%l4, %o2
 	mov		%l5, %o1
 	call		mem_address_unaligned
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	
@@ -306,7 +306,7 @@
 	mov		%o7, %g6			! Get current back.
 	sllx		%g4, 32, %g4			! Finish it.
 	call		data_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
@@ -367,7 +367,7 @@
 	mov		%l4, %o1
 	mov		%l5, %o2
 	call		data_access_exception
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
 	
diff -urN linux-2.4.21-pre7/arch/sparc64/mm/ultra.S linux-2.4.21-rc1/arch/sparc64/mm/ultra.S
--- linux-2.4.21-pre7/arch/sparc64/mm/ultra.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/sparc64/mm/ultra.S	2003-04-21 11:48:40.000000000 -0700
@@ -561,7 +561,7 @@
 	b,pt		%xcc, etrap_irq
 109:	 or		%g7, %lo(109b), %g7
 	call		__show_regs
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	clr		%l6
 	/* Has to be a non-v9 branch due to the large distance. */
 	b		rtrap_xcall
diff -urN linux-2.4.21-pre7/arch/sparc64/solaris/entry64.S linux-2.4.21-rc1/arch/sparc64/solaris/entry64.S
--- linux-2.4.21-pre7/arch/sparc64/solaris/entry64.S	2000-01-13 12:03:00.000000000 -0800
+++ linux-2.4.21-rc1/arch/sparc64/solaris/entry64.S	2003-04-21 11:48:40.000000000 -0700
@@ -33,7 +33,7 @@
 	be,pt		%icc, 2f
 	 srl		%i2, 0, %o2
 	b,pt		%xcc, 2f
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 
 solaris_sucks:
 /* Solaris is a big system which needs to be able to do all the things
@@ -89,7 +89,7 @@
 	 sethi		%hi(sys_call_table32), %l6
 	andcc		%l3, 1, %g0
 	bne,a,pn	%icc, 10f
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 10:	srl		%i2, 0, %o2
 	mov		%i5, %o5
 	andn		%l3, 3, %l7
@@ -99,11 +99,11 @@
 2:	call		%l7
 	 srl		%i3, 0, %o3
 ret_from_solaris:
-	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 	ldx		[%g6 + AOFF_task_flags], %l6
 	sra		%o0, 0, %o0
 	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
-	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+	ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
 	cmp		%o0, -ENOIOCTLCMD
 	sllx		%g2, 32, %g2
 	bgeu,pn		%xcc, 1f
@@ -111,21 +111,21 @@
 
 	/* System call success, clear Carry condition code. */
 	andn		%g3, %g2, %g3
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]	
 	bne,pn		%icc, solaris_syscall_trace2
-	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1
 	andcc		%l1, 1, %g0
 	bne,pn		%icc, 2f
 	 clr		%l6
 	add		%l1, 0x4, %l2				         
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]	 ! pc = npc
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]	 ! pc = npc
 	call		rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc+4
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4
 
 	/* When tnpc & 1, this comes from setcontext and we don't want to advance pc */
 2:	andn		%l1, 3, %l1
 	call		rtrap
-	 stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc&~3
+	 stx		%l1, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc&~3
 
 1:
 	/* System call failure, set Carry condition code.
@@ -141,17 +141,17 @@
 	sll		%o0, 2, %o0
 	or		%l6, %lo(solaris_err_table), %l6
 	ldsw		[%l6 + %o0], %o0
-1:	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+1:	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 	mov		1, %l6
-	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+	stx		%g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
 	bne,pn		%icc, solaris_syscall_trace2
-	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TNPC], %l1
 	andcc		%l1, 1, %g0
 	bne,pn		%icc, 2b
 	 add		%l1, 0x4, %l2
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]  ! pc = npc
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]  ! pc = npc
 	call		rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] !npc = npc+4 
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4 
 
 solaris_syscall_trace2:
 	call		syscall_trace
@@ -159,9 +159,9 @@
 	andcc		%l1, 1, %g0
 	bne,pn		%icc, 2b
 	 nop
-	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	stx		%l1, [%sp + PTREGS_OFF + PT_V9_TPC]
 	call		rtrap
-	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	 stx		%l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 
 	/* This one is tricky, so that's why we do it in assembly */
 	.globl		solaris_sigsuspend
@@ -171,13 +171,13 @@
 	brlz,pn		%o0, ret_from_solaris
 	 nop
 	call		sys_sigsuspend
-	 stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	 stx		%o0, [%sp + PTREGS_OFF + PT_V9_I0]
 
 	.globl		solaris_getpid
 solaris_getpid:
 	call		sys_getppid	/* This is tricky, so don't do it in assembly */
 	 nop
-	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	stx		%o0, [%sp + PTREGS_OFF + PT_V9_I1]
 	b,pt		%xcc, ret_from_solaris
 	 lduw		[%g6 + AOFF_task_pid], %o0
 
@@ -186,19 +186,19 @@
 	lduw		[%g6 + AOFF_task_euid], %o1
 	lduw		[%g6 + AOFF_task_uid], %o0
 	b,pt		%xcc, ret_from_solaris
-	 stx		%o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx		%o1, [%sp + PTREGS_OFF + PT_V9_I1]
 
 	.globl	solaris_getgid
 solaris_getgid:
 	lduw		[%g6 + AOFF_task_egid], %o1
 	lduw		[%g6 + AOFF_task_gid], %o0
 	b,pt		%xcc, ret_from_solaris
-	 stx		%o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	 stx		%o1, [%sp + PTREGS_OFF + PT_V9_I1]
 
 	.globl		solaris_unimplemented
 solaris_unimplemented:
 	call		do_sol_unimplemented
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	 add		%sp, PTREGS_OFF, %o0
 	ba,pt		%xcc, ret_from_solaris
 	 nop
 
diff -urN linux-2.4.21-pre7/arch/x86_64/ia32/fpu32.c linux-2.4.21-rc1/arch/x86_64/ia32/fpu32.c
--- linux-2.4.21-pre7/arch/x86_64/ia32/fpu32.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/ia32/fpu32.c	2003-04-21 11:48:40.000000000 -0700
@@ -2,7 +2,7 @@
  * Copyright 2002 Andi Kleen, SuSE Labs.
  * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
  * This is used for ptrace, signals and coredumps in 32bit emulation.
- * $Id: fpu32.c,v 1.7 2003/03/14 16:06:35 ak Exp $
+ * $Id: fpu32.c,v 1.8 2003/03/24 09:29:51 ak Exp $
  */ 
 
 #include <linux/sched.h>
@@ -157,6 +157,7 @@
 			return -1;
 	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
 	}
+	tsk->used_math = 1;
 	return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
 }  
 
diff -urN linux-2.4.21-pre7/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.21-rc1/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.21-pre7/arch/x86_64/ia32/ia32_ioctl.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/ia32/ia32_ioctl.c	2003-04-21 11:48:40.000000000 -0700
@@ -1,4 +1,4 @@
-/* $Id: ia32_ioctl.c,v 1.30 2003/03/12 06:03:23 ak Exp $
+/* $Id: ia32_ioctl.c,v 1.31 2003/03/21 07:50:07 ak Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -2909,35 +2909,28 @@
 {
 	typedef struct serial_struct SS;
 	struct serial_struct32 *ss32 = ptr; 
-	int err = 0;
+	int err;
 	struct serial_struct ss; 
 	mm_segment_t oldseg = get_fs(); 
-	set_fs(KERNEL_DS);
 	if (cmd == TIOCSSERIAL) { 
-		err = -EFAULT;
 		if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32)))
-			goto out;
+			return -EFAULT;
 		memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, 
 			sizeof(SS)-offsetof(SS,iomem_reg_shift)); 
 		ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff);
 	}
-	if (!err)
+	set_fs(KERNEL_DS);
 		err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); 
+	set_fs(oldseg);
 	if (cmd == TIOCGSERIAL && err >= 0) { 
-		__u32 base;
 		if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) ||
-		    __copy_to_user(&ss32->iomem_reg_shift,
-				   &ss.iomem_reg_shift,
-				   sizeof(SS) - offsetof(SS, iomem_reg_shift)))
-			err = -EFAULT;
-		if (ss.iomem_base > (unsigned char *)0xffffffff)
-			base = -1; 
-		else
-			base = (unsigned long)ss.iomem_base;
-		err |= __put_user(base, &ss32->iomem_base); 		
+		    __put_user((unsigned long)ss.iomem_base  >> 32 ? 
+			       0xffffffff : (unsigned)(unsigned long)ss.iomem_base,
+			       &ss32->iomem_base) ||
+		    __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) || 
+		    __put_user(ss.port_high, &ss32->port_high))
+			return -EFAULT;
 	} 
- out:
-	set_fs(oldseg);
 	return err;	
 }
 
diff -urN linux-2.4.21-pre7/arch/x86_64/ia32/ia32entry.S linux-2.4.21-rc1/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.21-pre7/arch/x86_64/ia32/ia32entry.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/ia32/ia32entry.S	2003-04-21 11:48:40.000000000 -0700
@@ -3,7 +3,7 @@
  * 		
  * Copyright 2000,2001 Andi Kleen, SuSE Labs.
  * 
- * $Id: ia32entry.S,v 1.39 2003/01/14 14:29:59 ak Exp $ 		
+ * $Id: ia32entry.S,v 1.40 2003/04/03 09:46:54 ak Exp $ 		
  */		 
 
 #include <asm/calling.h>
@@ -368,7 +368,7 @@
 	.quad quiet_ni_syscall  
 	.quad quiet_ni_syscall  /* fremovexattr - 237 */
 	.quad sys_tkill
-	.quad quiet_ni_syscall  /* sendfile64 - 2.5 only */
+	.quad sys_sendfile64
 	.quad quiet_ni_syscall  /* futex */
 	.quad quiet_ni_syscall  /* sched_setaffinity */
 	.quad quiet_ni_syscall  /* sched_getaffinity */	
diff -urN linux-2.4.21-pre7/arch/x86_64/ia32/ipc32.c linux-2.4.21-rc1/arch/x86_64/ia32/ipc32.c
--- linux-2.4.21-pre7/arch/x86_64/ia32/ipc32.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/ia32/ipc32.c	2003-04-21 11:48:40.000000000 -0700
@@ -185,12 +185,58 @@
 	}
 }
 
+static int put_semid(void *user_semid, struct semid64_ds *s, int version)
+{
+	int err2;
+	switch (version) { 
+	case IPC_64: { 
+		struct semid64_ds32 *usp64 = (struct semid64_ds32 *) user_semid;
+		
+		if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
+			err2 = -EFAULT;
+			break;
+		} 
+		err2 = __put_user(s->sem_perm.key, &usp64->sem_perm.key);
+		err2 |= __put_user(s->sem_perm.uid, &usp64->sem_perm.uid);
+		err2 |= __put_user(s->sem_perm.gid, &usp64->sem_perm.gid);
+		err2 |= __put_user(s->sem_perm.cuid, &usp64->sem_perm.cuid);
+		err2 |= __put_user(s->sem_perm.cgid, &usp64->sem_perm.cgid);
+		err2 |= __put_user(s->sem_perm.mode, &usp64->sem_perm.mode);
+		err2 |= __put_user(s->sem_perm.seq, &usp64->sem_perm.seq);
+		err2 |= __put_user(s->sem_otime, &usp64->sem_otime);
+		err2 |= __put_user(s->sem_ctime, &usp64->sem_ctime);
+		err2 |= __put_user(s->sem_nsems, &usp64->sem_nsems);
+		break;
+	}
+	default: {
+		struct semid_ds32 *usp32 = (struct semid_ds32 *) user_semid;
+		
+		if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
+			err2 = -EFAULT;
+			break;
+		} 
+		err2 = __put_user(s->sem_perm.key, &usp32->sem_perm.key);
+		err2 |= __put_user(s->sem_perm.uid, &usp32->sem_perm.uid);
+		err2 |= __put_user(s->sem_perm.gid, &usp32->sem_perm.gid);
+		err2 |= __put_user(s->sem_perm.cuid, &usp32->sem_perm.cuid);
+		err2 |= __put_user(s->sem_perm.cgid, &usp32->sem_perm.cgid);
+		err2 |= __put_user(s->sem_perm.mode, &usp32->sem_perm.mode);
+		err2 |= __put_user(s->sem_perm.seq, &usp32->sem_perm.seq);
+		err2 |= __put_user(s->sem_otime, &usp32->sem_otime);
+		err2 |= __put_user(s->sem_ctime, &usp32->sem_ctime);
+		err2 |= __put_user(s->sem_nsems, &usp32->sem_nsems);
+		break;
+	}
+	}
+	return err2;
+}
+
 static int
 semctl32 (int first, int second, int third, void *uptr)
 {
 	union semun fourth;
 	u32 pad;
-	int err = 0, err2;
+	int err = 0;
 	struct semid64_ds s;
 	mm_segment_t old_fs;
 	int version = ipc_parse_version32(&third);
@@ -223,49 +269,12 @@
 		fourth.__pad = &s;
 		old_fs = get_fs();
 		set_fs(KERNEL_DS);
-		err = sys_semctl(first, second|IPC_64, third, fourth);
+		err = sys_semctl(first, second, third|IPC_64, fourth);
 		set_fs(old_fs);
 
-		if (version == IPC_64) {
-			/* This works, but the equivalent __put_user code 
-			   does not. Why? */
-			struct semid64_ds32 u64; 
-			memset(&u64, 0, sizeof(u64));
-#define C(x) u64.x = s.x
-			C(sem_perm.key);
-			C(sem_perm.uid);
-			C(sem_perm.gid);
-			C(sem_perm.cuid);
-			C(sem_perm.cgid);
-			C(sem_perm.mode);
-			C(sem_perm.seq);
-			C(sem_otime);
-			C(sem_ctime);
-			C(sem_nsems);
-#undef C
-			err2 = copy_to_user((void *)A(pad), &u64, sizeof(struct semid64_ds32));
-			if (err2) 
-				err2 = -EFAULT;
-		} else {
-			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
+		if (!err) 
+			err = put_semid((void *)A(pad), &s, version);
 
-			if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key);
-			err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid);
-			err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid);
-			err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid);
-			err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid);
-			err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode);
-			err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq);
-			err2 |= __put_user(s.sem_otime, &usp32->sem_otime);
-			err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime);
-			err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems);
-		}
-		if (err2)
-		    err = -EFAULT;
 		break;
 	default:
 		err = -EINVAL;
diff -urN linux-2.4.21-pre7/arch/x86_64/ia32/ptrace32.c linux-2.4.21-rc1/arch/x86_64/ia32/ptrace32.c
--- linux-2.4.21-pre7/arch/x86_64/ia32/ptrace32.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/ia32/ptrace32.c	2003-04-21 11:48:40.000000000 -0700
@@ -8,7 +8,7 @@
  * This allows to access 64bit processes too; but there is no way to see the extended 
  * register contents.
  *
- * $Id: ptrace32.c,v 1.16 2003/03/14 16:06:35 ak Exp $
+ * $Id: ptrace32.c,v 1.17 2003/03/24 09:25:15 ak Exp $
  */ 
 
 #include <linux/kernel.h>
@@ -173,18 +173,15 @@
 		get_task_struct(child);
 	read_unlock(&tasklist_lock);
 	if (child) { 
-		*err = -ESRCH;
-		if (!(child->ptrace & PT_PTRACED))
+		*err = -EPERM;
+		if (pid == 1) 
 			goto out;
-		if (child->state != TASK_STOPPED) {
-			if (request != PTRACE_KILL)
+		*err = ptrace_check_attach(child, request == PTRACE_KILL); 
+		if (*err < 0) 
 				goto out;
-		}
-		if (child->p_pptr != current)
-			goto out;
-
 		return child; 
 	} 
+
  out:
 	free_task_struct(child);
 	return NULL; 
diff -urN linux-2.4.21-pre7/arch/x86_64/ia32/sys_ia32.c linux-2.4.21-rc1/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.21-pre7/arch/x86_64/ia32/sys_ia32.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/ia32/sys_ia32.c	2003-04-21 11:48:40.000000000 -0700
@@ -16,7 +16,7 @@
  *
  * This file assumes that there is a hole at the end of user address space.
  *
- * $Id: sys_ia32.c,v 1.53 2003/03/12 09:45:06 ak Exp $
+ * $Id: sys_ia32.c,v 1.54 2003/03/24 09:28:26 ak Exp $
  */
 
 #include <linux/config.h>
@@ -961,7 +961,7 @@
 asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
 
 static struct iovec *
-get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type, int *errp)
+get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 *count, int type, int *errp)
 {
 	int i;
 	u32 buf, len;
@@ -971,17 +971,17 @@
 	/* Get the "struct iovec" from user memory */
 
 	*errp = 0; 
-	if (!count)
+	if (!*count)
 		return 0;
 	*errp = -EINVAL;
-	if (count > UIO_MAXIOV)
+	if (*count > UIO_MAXIOV)
 		return(struct iovec *)0;
 	*errp = -EFAULT;
-	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
+	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)**count))
 		return(struct iovec *)0;
-	if (count > UIO_FASTIOV) {
+	if (*count > UIO_FASTIOV) {
 		*errp = -ENOMEM; 
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+		iov = kmalloc(*count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
 			return((struct iovec *)0);
 	} else
@@ -989,14 +989,19 @@
 
 	ivp = iov;
 	totlen = 0;
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < *count; i++) {
 		*errp = __get_user(len, &iov32->iov_len) |
 		  	__get_user(buf, &iov32->iov_base);	
 		if (*errp)
 			goto error;
 		*errp = verify_area(type, (void *)A(buf), len);
-		if (*errp) 
+		if (*errp) { 
+			if (i > 0) { 
+				*count = i;
+				break;
+			}	
 			goto error;
+		}
 		/* SuS checks: */
 		*errp = -EINVAL; 
 		if ((int)len < 0)
@@ -1025,7 +1030,7 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE, &ret)) == NULL)
+	if ((iov = get_iovec32(vector, iovstack, &count, VERIFY_WRITE, &ret)) == NULL)
 		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_readv(fd, iov, count);
@@ -1043,7 +1048,7 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ, &ret)) == NULL)
+	if ((iov = get_iovec32(vector, iovstack, &count, VERIFY_READ, &ret)) == NULL)
 		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_writev(fd, iov, count);
@@ -2545,7 +2550,7 @@
 
 static int __init ia32_init (void)
 {
-	printk("IA32 emulation $Id: sys_ia32.c,v 1.53 2003/03/12 09:45:06 ak Exp $\n");  
+	printk("IA32 emulation $Id: sys_ia32.c,v 1.54 2003/03/24 09:28:26 ak Exp $\n");  
 	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
 	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
 	register_exec_domain(&ia32_exec_domain);
diff -urN linux-2.4.21-pre7/arch/x86_64/kernel/entry.S linux-2.4.21-rc1/arch/x86_64/kernel/entry.S
--- linux-2.4.21-pre7/arch/x86_64/kernel/entry.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/kernel/entry.S	2003-04-21 11:48:40.000000000 -0700
@@ -5,7 +5,7 @@
  *  Copyright (C) 2000, 2001, 2002  Andi Kleen SuSE Labs
  *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
  * 
- *  $Id: entry.S,v 1.93 2003/02/20 12:52:08 ak Exp $		
+ *  $Id: entry.S,v 1.95 2003/04/03 09:46:54 ak Exp $		
  */
 
 /*
@@ -311,7 +311,7 @@
 	je   1f
 	swapgs
 1:	cld
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_X86_REMOTE_DEBUG
 	SAVE_ALL
 	movq %rsp,%rdi
 #else			
@@ -542,12 +542,12 @@
  * Create a kernel thread.
  *
  * C extern interface:
- *	extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+ *	extern long arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
  *
  * asm input arguments:
  *	rdi: fn, rsi: arg, rdx: flags
  */
-ENTRY(kernel_thread)
+ENTRY(arch_kernel_thread)
 	FAKE_STACK_FRAME $child_rip
 	SAVE_ALL
 
diff -urN linux-2.4.21-pre7/arch/x86_64/kernel/head64.c linux-2.4.21-rc1/arch/x86_64/kernel/head64.c
--- linux-2.4.21-pre7/arch/x86_64/kernel/head64.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.21-rc1/arch/x86_64/kernel/head64.c	2003-04-21 11:48:40.000000000 -0700
@@ -3,9 +3,10 @@
  *
  *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
  *
- *  $Id: head64.c,v 1.25 2002/07/01 08:01:19 ak Exp $
+ *  $Id: head64.c,v 1.27 2003/03/31 15:12:07 ak Exp $
  */
 
+#include <asm/bootsetup.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
@@ -50,7 +51,7 @@
 		printk("old bootloader convention, maybe loadlin?\n");
 	}
 	command_line = (char *) ((u64)(new_data));
-	memcpy(saved_command_line, command_line, 2048);
+	memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
 	printk("Bootdata ok (command line is %s)\n", saved_command_line);	
 }
 
@@ -81,6 +82,12 @@
 	s = strstr(saved_command_line, "earlyprintk="); 
 	if (s != NULL)
 		setup_early_printk(s+12); 
+#ifdef CONFIG_DISCONTIGMEM
+	extern int numa_setup(char *);
+	s = strstr(saved_command_line, "numa=");
+	if (s != NULL)
+		numa_setup(s+5);
+#endif		
 	early_printk("booting x86_64 kernel... ");
 	setup_boot_cpu_data();
 	start_kernel();
diff -urN linux-2.4.21-pre7/arch/x86_64/kernel/pci-irq.c linux-2.4.21-rc1/arch/x86_64/kernel/pci-irq.c
--- linux-2.4.21-pre7/arch/x86_64/kernel/pci-irq.c	2002-11-28 15:53:12.000000000 -0800
+++ linux-2.4.21-rc1/arch/x86_64/kernel/pci-irq.c	2003-04-21 11:48:40.000000000 -0700
@@ -742,9 +742,15 @@
 void pcibios_enable_irq(struct pci_dev *dev)
 {
 		u8 pin;
+	extern int interrupt_line_quirk;
+
 		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
 			char *msg;
+		/* With IDE legacy devices the IRQ lookup failure is not a problem.. */
+		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
+			return;
+
 			if (io_apic_assign_pci_irqs)
 				msg = " Probably buggy MP table.";
 			else if (pci_probe & PCI_BIOS_IRQ_SCAN)
@@ -754,4 +760,8 @@
 			printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
 			       'A' + pin - 1, dev->slot_name, msg);
 	}
+	/* VIA bridges use interrupt line for apic/pci steering across
+	   the V-Link */
+	else if (interrupt_line_quirk)
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 }
diff -urN linux-2.4.21-pre7/arch/x86_64/kernel/process.c linux-2.4.21-rc1/arch/x86_64/kernel/process.c
--- linux-2.4.21-pre7/arch/x86_64/kernel/process.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/kernel/process.c	2003-04-21 11:48:40.000000000 -0700
@@ -9,7 +9,7 @@
  *  X86-64 port
  *	Andi Kleen.
  * 
- *  $Id: process.c,v 1.63 2003/02/19 13:23:19 ak Exp $
+ *  $Id: process.c,v 1.64 2003/03/31 15:11:26 ak Exp $
  */
 
 /*
@@ -243,8 +243,8 @@
 	 * other OSs see a clean IRQ state.
 	 */
 		smp_send_stop();
-	disable_IO_APIC();
 #endif
+	disable_IO_APIC();
 	/* Could do reset through the northbridge of the Hammer here. */
 
 	/* rebooting needs to touch the page at absolute addr 0 */
diff -urN linux-2.4.21-pre7/arch/x86_64/kernel/ptrace.c linux-2.4.21-rc1/arch/x86_64/kernel/ptrace.c
--- linux-2.4.21-pre7/arch/x86_64/kernel/ptrace.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/kernel/ptrace.c	2003-04-21 11:48:40.000000000 -0700
@@ -205,15 +205,10 @@
 		ret = ptrace_attach(child);
 		goto out_tsk;
 	}
-	ret = -ESRCH;
-	if (!(child->ptrace & PT_PTRACED))
-		goto out_tsk;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out_tsk;
-	}
-	if (child->p_pptr != current)
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0) 
 		goto out_tsk;
+
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -412,8 +407,10 @@
 			ret = -EIO;
 			break;
 		}
-		child->used_math = 1;
+		unlazy_fpu(child);
 		ret = set_fpregs(child, (struct user_i387_struct *)data);
+		if (!ret) 
+			child->used_math = 1;
 		break;
 	}
 
diff -urN linux-2.4.21-pre7/arch/x86_64/lib/copy_user.S linux-2.4.21-rc1/arch/x86_64/lib/copy_user.S
--- linux-2.4.21-pre7/arch/x86_64/lib/copy_user.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/lib/copy_user.S	2003-04-21 11:48:40.000000000 -0700
@@ -4,7 +4,7 @@
  * Functions to copy from and to user space.		
  */		 
 
-#define FIX_ALIGNMENT 1
+// #define FIX_ALIGNMENT 1
 
 	#include <asm/current.h>
 	#include <asm/offset.h>
@@ -59,11 +59,7 @@
 	.globl copy_user_generic	
 	.p2align 4
 copy_user_generic:	
-	/* Put the first cacheline into cache. This should handle
-	   the small movements in ioctls etc., but not penalize the bigger
-	   filesystem data copies too much. */
 	pushq %rbx
-	prefetch (%rsi)
 	xorl %eax,%eax		/*zero for the exception handler */
 
 #ifdef FIX_ALIGNMENT
@@ -77,40 +73,35 @@
 	movq %rdx,%rcx
 
 	movl $64,%ebx	
-	shrq $6,%rdx
-	decq %rdx
-	js   .Lhandle_tail
-	jz   .Lloop_no_prefetch
+	shrl $6,%edx
+	jz   .Lhandle_tail
+	decl %edx
 	
 	.p2align 4
 .Lloop:
-	prefetch 64(%rsi)		/* prefetch distance too short */
+	decl %edx
 	
-.Lloop_no_prefetch:	
 .Ls1:	movq (%rsi),%r11
 .Ls2:	movq 1*8(%rsi),%r8
-.Ls3:	movq 2*8(%rsi),%r9
-.Ls4:	movq 3*8(%rsi),%r10
 .Ld1:	movq %r11,(%rdi)
 .Ld2:	movq %r8,1*8(%rdi)
+.Ls3:	movq 2*8(%rsi),%r9
+.Ls4:	movq 3*8(%rsi),%r10
 .Ld3:	movq %r9,2*8(%rdi)
 .Ld4:	movq %r10,3*8(%rdi)
 		
 .Ls5:	movq 4*8(%rsi),%r11
 .Ls6:	movq 5*8(%rsi),%r8
-.Ls7:	movq 6*8(%rsi),%r9
-.Ls8:	movq 7*8(%rsi),%r10
 .Ld5:	movq %r11,4*8(%rdi)
 .Ld6:	movq %r8,5*8(%rdi)
+.Ls7:	movq 6*8(%rsi),%r9
+.Ls8:	movq 7*8(%rsi),%r10
 .Ld7:	movq %r9,6*8(%rdi)
 .Ld8:	movq %r10,7*8(%rdi)
 	
-	decq %rdx
-
 	leaq 64(%rsi),%rsi
 	leaq 64(%rdi),%rdi
 	
-	jz   .Lloop_no_prefetch
 	jns  .Lloop
 
 	.p2align 4
@@ -119,11 +110,10 @@
 	andl $63,%ecx
 	shrl $3,%ecx
 	jz   .Lhandle_7
-	movl $8,%ebx
 	.p2align 4
 .Lloop_8:
-.Ls9:	movq (%rsi),%r8
-.Ld9:	movq %r8,(%rdi)
+.Ls9:	movq (%rsi),%rbx
+.Ld9:	movq %rbx,(%rdi)
 	decl %ecx
 	leaq 8(%rdi),%rdi
 	leaq 8(%rsi),%rsi
@@ -174,18 +164,18 @@
 	.align 8
 	.quad .Ls1,.Ls1e
 	.quad .Ls2,.Ls2e
-	.quad .Ls3,.Ls3e
-	.quad .Ls4,.Ls4e	
 	.quad .Ld1,.Ls1e
 	.quad .Ld2,.Ls2e
+	.quad .Ls3,.Ls3e
+	.quad .Ls4,.Ls4e	
 	.quad .Ld3,.Ls3e
 	.quad .Ld4,.Ls4e
 	.quad .Ls5,.Ls5e
 	.quad .Ls6,.Ls6e
-	.quad .Ls7,.Ls7e
-	.quad .Ls8,.Ls8e	
 	.quad .Ld5,.Ls5e
 	.quad .Ld6,.Ls6e
+	.quad .Ls7,.Ls7e
+	.quad .Ls8,.Ls8e	
 	.quad .Ld7,.Ls7e
 	.quad .Ld8,.Ls8e
 	.quad .Ls9,.Le_quad
diff -urN linux-2.4.21-pre7/arch/x86_64/lib/csum-copy.S linux-2.4.21-rc1/arch/x86_64/lib/csum-copy.S
--- linux-2.4.21-pre7/arch/x86_64/lib/csum-copy.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/lib/csum-copy.S	2003-04-21 11:48:40.000000000 -0700
@@ -50,15 +50,25 @@
 	cmpl	 $3*64,%edx
 	jle	 1f
 
+	source
 	prefetch (%rdi)
+	source
 	prefetch 1*64(%rdi)
+	source
 	prefetch 2*64(%rdi)
+	source
 	prefetch 3*64(%rdi)
+	source
 	prefetch 4*64(%rdi)
+	dest
 	prefetchw (%rsi)
+	dest
 	prefetchw 1*64(%rsi)
+	dest
 	prefetchw 2*64(%rsi)
+	dest
 	prefetchw 3*64(%rsi)
+	dest
 	prefetchw 4*64(%rsi)
 
 1:			
@@ -107,6 +117,7 @@
 	source
 	movq  56(%rdi),%r13
 		
+	source
 	prefetch 5*64(%rdi)
 						
 	adcq  %rbx,%rax
@@ -138,6 +149,7 @@
 	dest
 	movq %r13,56(%rsi)
 	
+	dest
 	prefetchw 5*64(%rsi)
 	
 	leaq 64(%rdi),%rdi
diff -urN linux-2.4.21-pre7/arch/x86_64/lib/memcpy.S linux-2.4.21-rc1/arch/x86_64/lib/memcpy.S
--- linux-2.4.21-pre7/arch/x86_64/lib/memcpy.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/lib/memcpy.S	2003-04-21 11:48:40.000000000 -0700
@@ -12,49 +12,48 @@
  * rax original destination
  */	
 
- // #define FIX_ALIGNMENT
  	.globl __memcpy
 	.globl memcpy
-	.p2align
+	.p2align 4
 __memcpy:
 memcpy:		
 	pushq %rbx
 	movq %rdi,%rax
 
-#ifdef FIX_ALIGNMENT
-	movl %edi,%ecx
-	andl $7,%ecx
-	jnz  .Lbad_alignment	
-.Lafter_bad_alignment:
-#endif
-
-	movq %rdx,%rcx
-	movl $64,%ebx
-	shrq $6,%rcx
+	movl %edx,%ecx
+	shrl $6,%ecx
 	jz .Lhandle_tail
 	
+	.p2align 4
 .Lloop_64:
+	decl %ecx
+
 	movq (%rsi),%r11
 	movq 8(%rsi),%r8
-	movq 2*8(%rsi),%r9
-	movq 3*8(%rsi),%r10
+
 	movq %r11,(%rdi)
 	movq %r8,1*8(%rdi)
+
+	movq 2*8(%rsi),%r9
+	movq 3*8(%rsi),%r10
+
 	movq %r9,2*8(%rdi)
 	movq %r10,3*8(%rdi)
 		
 	movq 4*8(%rsi),%r11
 	movq 5*8(%rsi),%r8
-	movq 6*8(%rsi),%r9
-	movq 7*8(%rsi),%r10
+
 	movq %r11,4*8(%rdi)
 	movq %r8,5*8(%rdi)
+
+	movq 6*8(%rsi),%r9
+	movq 7*8(%rsi),%r10
+
 	movq %r9,6*8(%rdi)
 	movq %r10,7*8(%rdi)
 
-	addq %rbx,%rsi	
-	addq %rbx,%rdi
-	decl %ecx
+	leaq 64(%rsi),%rsi
+	leaq 64(%rdi),%rdi
 	jnz  .Lloop_64
 
 .Lhandle_tail:
@@ -62,19 +61,20 @@
 	andl $63,%ecx
 	shrl $3,%ecx
 	jz   .Lhandle_7
-	movl $8,%ebx
+	.p2align 4
 .Lloop_8: 
+	decl %ecx
 	movq (%rsi),%r8
 	movq %r8,(%rdi) 
-	addq %rbx,%rdi
-	addq %rbx,%rsi
-	decl %ecx
+	leaq 8(%rdi),%rdi
+	leaq 8(%rsi),%rsi
 	jnz  .Lloop_8
 
 .Lhandle_7:
 	movl %edx,%ecx
 	andl $7,%ecx
 	jz .Lende
+	.p2align 4
 .Lloop_1:
 	movb (%rsi),%r8b
 	movb %r8b,(%rdi) 
@@ -84,31 +84,6 @@
 	jnz .Lloop_1
 	
 .Lende: 	
-	sfence
 	popq %rbx
 	ret
 
-
-#ifdef FIX_ALIGNMENT
-	/* align destination */
-	/* This is simpleminded. For bigger blocks it may make sense to align
-	   src and dst to their aligned subset and handle the rest separately */
-.Lbad_alignment:
-	movl $8,%r9d
-	subl %ecx,%r9d
-	movl %r9d,%ecx
-	subq %r9,%rdx
-	js   .Lsmall_alignment
-	jz   .Lsmall_alignment
-.Lalign_1:
-	movb (%rsi),%r8b
-	movb %r8b,(%rdi) 
-	incq %rdi
-	incq %rsi
-	decl %ecx
-	jnz  .Lalign_1
-	jmp .Lafter_bad_alignment
-.Lsmall_alignment:
-	addq %r9,%rdx
-	jmp .Lhandle_7
-#endif	
diff -urN linux-2.4.21-pre7/arch/x86_64/lib/memset.S linux-2.4.21-rc1/arch/x86_64/lib/memset.S
--- linux-2.4.21-pre7/arch/x86_64/lib/memset.S	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/lib/memset.S	2003-04-21 11:48:40.000000000 -0700
@@ -11,7 +11,7 @@
  */	
  	.globl __memset
 	.globl memset
-	.p2align
+	.p2align 4
 memset:	
 __memset:
 	movq %rdi,%r10
@@ -28,12 +28,13 @@
 	jnz  .Lbad_alignment
 .Lafter_bad_alignment:
 
-	movq %r11,%rcx
-	movl $64,%r8d
-	shrq $6,%rcx
+	movl %r11d,%ecx
+	shrl $6,%ecx
 	jz	 .Lhandle_tail
 
+	.p2align 4
 .Lloop_64:	
+	decl   %ecx
 	movq  %rax,(%rdi) 
 	movq  %rax,8(%rdi) 
 	movq  %rax,16(%rdi) 
@@ -42,31 +43,33 @@
 	movq  %rax,40(%rdi) 
 	movq  %rax,48(%rdi) 
 	movq  %rax,56(%rdi) 
-	addq    %r8,%rdi
-	decl   %ecx
+	leaq  64(%rdi),%rdi
 	jnz    .Lloop_64
 
 	/* Handle tail in loops. The loops should be faster than hard
 	   to predict jump tables. */ 
+	.p2align 4	   
 .Lhandle_tail:
 	movl	%r11d,%ecx
 	andl    $63&(~7),%ecx
 	jz 		.Lhandle_7
 	shrl	$3,%ecx
+	.p2align 4
 .Lloop_8:
-	movq  %rax,(%rdi) 
-	addq    $8,%rdi
 	decl   %ecx
+	movq  %rax,(%rdi)
+	leaq  8(%rdi),%rdi
 	jnz    .Lloop_8
 
 .Lhandle_7:
 	movl	%r11d,%ecx
 	andl	$7,%ecx
 	jz      .Lende
+	.p2align 4
 .Lloop_1:
-	movb 	%al,(%rdi)
-	addq	$1,%rdi
 	decl    %ecx
+	movb 	%al,(%rdi)
+	leaq	1(%rdi),%rdi
 	jnz     .Lloop_1
 	
 .Lende:	
diff -urN linux-2.4.21-pre7/arch/x86_64/mm/k8topology.c linux-2.4.21-rc1/arch/x86_64/mm/k8topology.c
--- linux-2.4.21-pre7/arch/x86_64/mm/k8topology.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/mm/k8topology.c	2003-04-21 11:48:40.000000000 -0700
@@ -6,7 +6,7 @@
  * Instead the northbridge registers are read directly. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: k8topology.c,v 1.5 2003/03/10 14:33:40 ak Exp $
+ * $Id: k8topology.c,v 1.7 2003/04/02 21:36:22 ak Exp $
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -66,7 +66,8 @@
 			for (addr = nodes[i].start; 
 			     addr < nodes[i].end; 
 			     addr += (1UL << shift)) {
-				if (memnodemap[addr >> shift] != 0xff) { 
+				if (memnodemap[addr >> shift] != 0xff && 
+				    memnodemap[addr >> shift] != i) { 
 					printk("node %d shift %d addr %Lx conflict %d\n", 
 					       i, shift, addr, memnodemap[addr>>shift]);
 					goto next; 
@@ -127,6 +128,7 @@
 
 		limit >>= 16; 
 		limit <<= 24; 
+		limit |= (1<<24)-1;
 
 		if (limit > end_pfn << PAGE_SHIFT) 
 			limit = end_pfn << PAGE_SHIFT; 
diff -urN linux-2.4.21-pre7/arch/x86_64/mm/numa.c linux-2.4.21-rc1/arch/x86_64/mm/numa.c
--- linux-2.4.21-pre7/arch/x86_64/mm/numa.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/arch/x86_64/mm/numa.c	2003-04-21 11:48:40.000000000 -0700
@@ -1,7 +1,7 @@
 /* 
  * Generic VM initialization for x86-64 NUMA setups.
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: numa.c,v 1.5 2002/10/23 05:27:46 ak Exp $
+ * $Id: numa.c,v 1.6 2003/04/03 12:28:08 ak Exp $
  */ 
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -183,7 +183,7 @@
 }
 
 /* [numa=off] */
-static __init int numa_setup(char *opt) 
+__init int numa_setup(char *opt) 
 { 
 	if (!strncmp(opt,"off",3))
 		numa_off = 1;
diff -urN linux-2.4.21-pre7/drivers/atm/idt77105.c linux-2.4.21-rc1/drivers/atm/idt77105.c
--- linux-2.4.21-pre7/drivers/atm/idt77105.c	2001-09-13 15:21:32.000000000 -0700
+++ linux-2.4.21-rc1/drivers/atm/idt77105.c	2003-04-21 11:48:40.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/capability.h>
 #include <linux/atm_idt77105.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
@@ -38,6 +39,7 @@
         unsigned char old_mcr;          /* storage of MCR reg while signal lost */
 };
 
+static spinlock_t idt77105_priv_lock = SPIN_LOCK_UNLOCKED;
 
 #define PRIV(dev) ((struct idt77105_priv *) dev->phy_data)
 
@@ -146,12 +148,11 @@
 	unsigned long flags;
 	struct idt77105_stats stats;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&idt77105_priv_lock, flags);
 	memcpy(&stats, &PRIV(dev)->stats, sizeof(struct idt77105_stats));
 	if (zero)
 		memset(&PRIV(dev)->stats, 0, sizeof(struct idt77105_stats));
-	restore_flags(flags);
+	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
 	if (arg == NULL)
 		return 0;
 	return copy_to_user(arg, &PRIV(dev)->stats,
@@ -269,11 +270,10 @@
 	if (!(PRIV(dev) = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
 		return -ENOMEM;
 	PRIV(dev)->dev = dev;
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&idt77105_priv_lock, flags);
 	PRIV(dev)->next = idt77105_all;
 	idt77105_all = PRIV(dev);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
 	memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
         
         /* initialise dev->signal from Good Signal Bit */
@@ -307,11 +307,9 @@
 	idt77105_stats_timer_func(0); /* clear 77105 counters */
 	(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
         
-	cli();
-	if (!start_timer) restore_flags(flags);
-	else {
+	spin_lock_irqsave(&idt77105_priv_lock, flags);
+	if (start_timer) {
 		start_timer = 0;
-		restore_flags(flags);
                 
 		init_timer(&stats_timer);
 		stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD;
@@ -323,32 +321,11 @@
 		restart_timer.function = idt77105_restart_timer_func;
 		add_timer(&restart_timer);
 	}
+	spin_unlock_irqrestore(&idt77105_priv_lock, flags);
 	return 0;
 }
 
 
-static const struct atmphy_ops idt77105_ops = {
-	idt77105_start,
-	idt77105_ioctl,
-	idt77105_int
-};
-
-
-int __init idt77105_init(struct atm_dev *dev)
-{
-	MOD_INC_USE_COUNT;
-
-	dev->phy = &idt77105_ops;
-	return 0;
-}
-
-
-/*
- * TODO: this function should be called through phy_ops
- * but that will not be possible for some time as there is
- * currently a freeze on modifying that structure
- * -- Greg Banks, 13 Sep 1999
- */
 int idt77105_stop(struct atm_dev *dev)
 {
 	struct idt77105_priv *walk, *prev;
@@ -374,30 +351,33 @@
             }
         }
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 
+static const struct atmphy_ops idt77105_ops = {
+	.start = 	idt77105_start,
+	.ioctl =	idt77105_ioctl,
+	.interrupt =	idt77105_int,
+	.stop =		idt77105_stop,
+};
 
-EXPORT_SYMBOL(idt77105_init);
-EXPORT_SYMBOL(idt77105_stop);
-
-MODULE_LICENSE("GPL");
-
-#ifdef MODULE
 
-int init_module(void)
+int idt77105_init(struct atm_dev *dev)
 {
+	dev->phy = &idt77105_ops;
 	return 0;
 }
 
+EXPORT_SYMBOL(idt77105_init);
 
-void cleanup_module(void)
+static void __exit idt77105_exit(void)
 {
         /* turn off timers */
         del_timer(&stats_timer);
         del_timer(&restart_timer);
 }
 
-#endif
+module_exit(idt77105_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.21-pre7/drivers/atm/idt77252.c linux-2.4.21-rc1/drivers/atm/idt77252.c
--- linux-2.4.21-pre7/drivers/atm/idt77252.c	2001-12-21 09:41:53.000000000 -0800
+++ linux-2.4.21-rc1/drivers/atm/idt77252.c	2003-04-21 11:48:40.000000000 -0700
@@ -730,7 +730,7 @@
 		struct atm_vcc *vcc = vc->tx_vcc;
 
 		vc->estimator->cells += (skb->len + 47) / 48;
-		if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) {
+		if (atomic_read(&vcc->sk->wmem_alloc) > (vcc->sk->sndbuf >> 1)) {
 			u32 cps = vc->estimator->maxcps;
 
 			vc->estimator->cps = cps;
@@ -2025,7 +2025,7 @@
 		atomic_inc(&vcc->stats->tx_err);
 		return -ENOMEM;
 	}
-	atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse);
+	atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0;
 
 	memcpy(skb_put(skb, 52), cell, 52);
diff -urN linux-2.4.21-pre7/drivers/atm/iphase.c linux-2.4.21-rc1/drivers/atm/iphase.c
--- linux-2.4.21-pre7/drivers/atm/iphase.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/drivers/atm/iphase.c	2003-04-21 11:48:40.000000000 -0700
@@ -2931,7 +2931,7 @@
         struct tx_buf_desc *buf_desc_ptr;
         int desc;
         int comp_code;
-        int total_len, pad, last;
+        int total_len;
         struct cpcs_trailer *trailer;
         struct ia_vcc *iavcc;
 
@@ -3020,7 +3020,7 @@
            make it  aligned on a 48 byte boundary.  */
 	total_len = skb->len + sizeof(struct cpcs_trailer);  
 	total_len = ((total_len + 47) / 48) * 48;
-	IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);)  
+	IF_TX(printk("ia packet len:%d padding:%d\n", total_len, total_len - skb->len);)  
  
 	/* Put the packet in a tx buffer */   
 	trailer = iadev->tx_buf[desc-1].cpcs;
@@ -3326,7 +3326,7 @@
 	.name =         DEV_LABEL,
 	.id_table =     ia_pci_tbl,
 	.probe =        ia_init_one,
-	.remove =       ia_remove_one,
+	.remove =       __devexit_p(ia_remove_one),
 };
 
 static int __init ia_init_module(void)
diff -urN linux-2.4.21-pre7/drivers/atm/nicstar.c linux-2.4.21-rc1/drivers/atm/nicstar.c
--- linux-2.4.21-pre7/drivers/atm/nicstar.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/drivers/atm/nicstar.c	2003-04-21 11:48:40.000000000 -0700
@@ -359,11 +359,8 @@
 
       card = cards[i];
 
-#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
-      if (card->max_pcr == ATM_25_PCR) {
-        idt77105_stop(card->atmdev);
-      }
-#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
+      if (card->atmdev->phy && card->atmdev->phy->stop)
+        card->atmdev->phy->stop(card->atmdev);
 
       /* Stop everything */
       writel(0x00000000, card->membase + CFG);
@@ -549,11 +546,6 @@
    card->atmdev = NULL;
    card->pcidev = pcidev;
    card->membase = pci_resource_start(pcidev, 1);
-#ifdef __powerpc__
-   /* Compensate for different memory map between host CPU and PCI bus.
-      Shouldn't we use a macro for this? */
-   card->membase += KERNELBASE;
-#endif /* __powerpc__ */
    card->membase = (unsigned long) ioremap(card->membase, NS_IOREMAP_SIZE);
    if (card->membase == 0)
    {
@@ -964,22 +956,13 @@
    card->atmdev->phy = NULL;
 
 #ifdef CONFIG_ATM_NICSTAR_USE_SUNI
-   if (card->max_pcr == ATM_OC3_PCR) {
+   if (card->max_pcr == ATM_OC3_PCR)
       suni_init(card->atmdev);
-
-      MOD_INC_USE_COUNT;
-      /* Can't remove the nicstar driver or the suni driver would oops */
-   }
 #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
 
 #ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
-   if (card->max_pcr == ATM_25_PCR) {
+   if (card->max_pcr == ATM_25_PCR)
       idt77105_init(card->atmdev);
-      /* Note that for the IDT77105 PHY we don't need the awful
-       * module count hack that the SUNI needs because we can
-       * stop the '105 when the nicstar module is cleaned up.
-       */
-   }
 #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
 
    if (card->atmdev->phy && card->atmdev->phy->start)
@@ -2386,6 +2369,7 @@
          {
             push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data),
                         0, 0);
+            atomic_inc(&vcc->stats->rx_drop);
          }
          else
 	 {
@@ -2413,6 +2397,7 @@
             {
                push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
                            0, 0);
+               atomic_inc(&vcc->stats->rx_drop);
             }
             else
 	    {
@@ -2437,6 +2422,7 @@
             {
                push_rxbufs(card, BUF_LG, (u32) skb,
                            (u32) virt_to_bus(skb->data), 0, 0);
+               atomic_inc(&vcc->stats->rx_drop);
             }
             else
             {
@@ -2521,6 +2507,7 @@
             }
 	    else
 	       dev_kfree_skb_any(hb);
+	    atomic_inc(&vcc->stats->rx_drop);
          }
          else
 	 {
diff -urN linux-2.4.21-pre7/drivers/atm/suni.c linux-2.4.21-rc1/drivers/atm/suni.c
--- linux-2.4.21-pre7/drivers/atm/suni.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/drivers/atm/suni.c	2003-04-21 11:48:40.000000000 -0700
@@ -297,7 +297,7 @@
 	mri = GET(MRI); /* reset SUNI */
 	PUT(mri | SUNI_MRI_RESET,MRI);
 	PUT(mri,MRI);
-	PUT(0,MT); /* disable all tests */
+	PUT((GET(MT) & SUNI_MT_DS27_53),MT); /* disable all tests */
 	REG_CHANGE(SUNI_TPOP_APM_S,SUNI_TPOP_APM_S_SHIFT,SUNI_TPOP_S_SONET,
 	    TPOP_APM); /* use SONET */
 	REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP,
@@ -307,24 +307,6 @@
 	return 0;
 }
 
-
 EXPORT_SYMBOL(suni_init);
 
-
 MODULE_LICENSE("GPL");
-
-#ifdef MODULE
-
-
-int init_module(void)
-{
-	return 0;
-}
-
-
-void cleanup_module(void)
-{
-	/* Nay */
-}
-
-#endif
diff -urN linux-2.4.21-pre7/drivers/atm/suni.h linux-2.4.21-rc1/drivers/atm/suni.h
--- linux-2.4.21-pre7/drivers/atm/suni.h	2000-12-11 13:21:57.000000000 -0800
+++ linux-2.4.21-rc1/drivers/atm/suni.h	2003-04-21 11:48:40.000000000 -0700
@@ -198,6 +198,7 @@
 #define SUNI_MT_IOTST		0x04	/* RW, enable test mode */
 #define SUNI_MT_DBCTRL		0x08	/* W, control data bus by CSB pin */
 #define SUNI_MT_PMCTST		0x10	/* W, PMC test mode */
+#define SUNI_MT_DS27_53		0x80	/* RW, select between 8- or 16- bit */
 
 
 #define SUNI_IDLE_PATTERN       0x6a    /* idle pattern */
diff -urN linux-2.4.21-pre7/drivers/block/amiflop.c linux-2.4.21-rc1/drivers/block/amiflop.c
--- linux-2.4.21-pre7/drivers/block/amiflop.c	2003-04-21 11:48:28.000000000 -0700
+++ linux-2.4.21-rc1/drivers/block/amiflop.c	2003-04-21 11:48:40.000000000 -0700
@@ -366,10 +366,8 @@
 		unit[nr].motor = 1;
 		fd_select(nr);
 
-		del_timer(&motor_on_timer);
 		motor_on_timer.data = nr;
-		motor_on_timer.expires = jiffies + HZ/2;
-		add_timer(&motor_on_timer);
+		mod_timer(&motor_on_timer, jiffies + HZ/2);
 
 		on_attempts = 10;
 		sleep_on (&motor_wait);
@@ -427,11 +425,9 @@
 	int drive;
 
 	drive = nr & 3;
-	del_timer(motor_off_timer + drive);
-	motor_off_timer[drive].expires = jiffies + 3*HZ;
 	/* called this way it is always from interrupt */
 	motor_off_timer[drive].data = nr | 0x80000000;
-	add_timer(motor_off_timer + drive);
+	mod_timer(motor_off_timer + drive, jiffies + 3*HZ);
 }
 
 static int fd_calibrate(int drive)
@@ -1466,10 +1462,7 @@
 
 			unit[drive].dirty = 1;
 		        /* reset the timer */
-		        del_timer (flush_track_timer + drive);
-			    
-			flush_track_timer[drive].expires = jiffies + 1;
-			add_timer (flush_track_timer + drive);
+			mod_timer(flush_track_timer + drive, jiffies + 1);
 			restore_flags (flags);
 			break;
 		}
diff -urN linux-2.4.21-pre7/drivers/block/ll_rw_blk.c linux-2.4.21-rc1/drivers/block/ll_rw_blk.c
--- linux-2.4.21-pre7/drivers/block/ll_rw_blk.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/block/ll_rw_blk.c	2003-04-21 11:48:40.000000000 -0700
@@ -1375,11 +1375,12 @@
 
 void end_that_request_last(struct request *req)
 {
-	if (req->waiting != NULL)
-		complete(req->waiting);
-	req_finished_io(req);
+	struct completion *waiting = req->waiting;
 
+	req_finished_io(req);
 	blkdev_release_request(req);
+	if (waiting)
+		complete(waiting);
 }
 
 int __init blk_dev_init(void)
diff -urN linux-2.4.21-pre7/drivers/char/genrtc.c linux-2.4.21-rc1/drivers/char/genrtc.c
--- linux-2.4.21-pre7/drivers/char/genrtc.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/char/genrtc.c	2003-04-21 11:48:40.000000000 -0700
@@ -99,7 +99,7 @@
 static void gen_rtc_interrupt(unsigned long arg);
 
 /*
- * Routine to poll RTC seconds field for change as often as posible,
+ * Routine to poll RTC seconds field for change as often as possible,
  * after first RTC_UIE use timer to reduce polling
  */
 static void genrtc_troutine(void *data)
diff -urN linux-2.4.21-pre7/drivers/ide/ide-io.c linux-2.4.21-rc1/drivers/ide/ide-io.c
--- linux-2.4.21-pre7/drivers/ide/ide-io.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/ide-io.c	2003-04-21 11:48:41.000000000 -0700
@@ -788,7 +788,7 @@
 	ide_startstop_t	startstop;
 
 	/* for atari only: POSSIBLY BROKEN HERE(?) */
-	ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);
+	ide_get_lock(ide_intr, hwgroup);
 
 	/* necessary paranoia: ensure IRQs are masked on local CPU */
 	local_irq_disable();
@@ -828,7 +828,7 @@
 				 */
 
 				/* for atari only */
-				ide_release_lock(&ide_intr_lock);
+				ide_release_lock();
 				hwgroup->busy = 0;
 			}
 			/* no more work for this hwgroup (for now) */
diff -urN linux-2.4.21-pre7/drivers/ide/ide-iops.c linux-2.4.21-rc1/drivers/ide/ide-iops.c
--- linux-2.4.21-pre7/drivers/ide/ide-iops.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/ide-iops.c	2003-04-21 11:48:41.000000000 -0700
@@ -157,7 +157,7 @@
 
 static void ide_outsl (unsigned long port, void *addr, u32 count)
 {
-	return outsl(port, addr, count);
+	outsl(port, addr, count);
 }
 
 void default_hwif_iops (ide_hwif_t *hwif)
@@ -393,7 +393,7 @@
 		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
 		return;
 	}
-#endif /* CONFIG_ATARI */
+#endif /* CONFIG_ATARI || CONFIG_Q40 */
 	hwif->ata_input_data(drive, buffer, bytecount / 4);
 	if ((bytecount & 0x03) >= 2)
 		hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);
@@ -412,7 +412,7 @@
 		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
 		return;
 	}
-#endif /* CONFIG_ATARI */
+#endif /* CONFIG_ATARI || CONFIG_Q40 */
 	hwif->ata_output_data(drive, buffer, bytecount / 4);
 	if ((bytecount & 0x03) >= 2)
 		hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);
@@ -430,6 +430,23 @@
 	int i;
 	u16 *stringcast;
 
+#ifdef __mc68000__
+	if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
+		return;
+
+#ifdef M68K_IDE_SWAPW
+	if (M68K_IDE_SWAPW) {	/* fix bus byteorder first */
+		u_char *p = (u_char *)id;
+		u_char t;
+		for (i = 0; i < 512; i += 2) {
+			t = p[i];
+			p[i] = p[i+1];
+			p[i+1] = t;
+		}
+	}
+#endif
+#endif /* __mc68000__ */
+
 	id->config         = __le16_to_cpu(id->config);
 	id->cyls           = __le16_to_cpu(id->cyls);
 	id->reserved2      = __le16_to_cpu(id->reserved2);
diff -urN linux-2.4.21-pre7/drivers/ide/ide-probe.c linux-2.4.21-rc1/drivers/ide/ide-probe.c
--- linux-2.4.21-pre7/drivers/ide/ide-probe.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/ide-probe.c	2003-04-21 11:48:41.000000000 -0700
@@ -1136,7 +1136,7 @@
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
 #else
-	printk("%s at %x on irq 0x%08x", hwif->name,
+	printk("%s at 0x%08lx on irq %d", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
 #endif /* __mc68000__ && CONFIG_APUS */
 	if (match)
diff -urN linux-2.4.21-pre7/drivers/ide/ide-proc.c linux-2.4.21-rc1/drivers/ide/ide-proc.c
--- linux-2.4.21-pre7/drivers/ide/ide-proc.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/ide-proc.c	2003-04-21 11:48:41.000000000 -0700
@@ -74,6 +74,11 @@
 
 #include <asm/io.h>
 
+#ifdef CONFIG_ALL_PPC
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+
 #ifndef MIN
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
@@ -419,13 +424,35 @@
 		case ide_cmd646:	name = "cmd646";	break;
 		case ide_cy82c693:	name = "cy82c693";	break;
 		case ide_4drives:	name = "4drives";	break;
-		case ide_pmac:		name = "mac-io";	break;
+		case ide_pmac:		name = "pmac";		break;
 		default:		name = "(unknown)";	break;
 	}
 	len = sprintf(page, "%s\n", name);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+#ifdef CONFIG_ALL_PPC
+static int proc_ide_read_devspec
+	(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	ide_hwif_t		*hwif = (ide_hwif_t *) data;
+	int			len;
+	struct device_node	*ofnode = NULL;
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+	extern struct device_node* pmac_ide_get_of_node(int index);
+	if (hwif->chipset == ide_pmac)
+		ofnode = pmac_ide_get_of_node(hwif->index);
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#ifdef CONFIG_PCI
+	if (ofnode == NULL && hwif->pci_dev)
+		ofnode = pci_device_to_OF_node(hwif->pci_dev);
+#endif /* CONFIG_PCI */		
+	len = sprintf(page, "%s\n", ofnode ? ofnode->full_name : "");
+	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif /* CONFIG_ALL_PPC */
+
 EXPORT_SYMBOL(proc_ide_read_imodel);
 
 int proc_ide_read_mate
@@ -852,6 +879,9 @@
 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
 	{ "mate",	S_IFREG|S_IRUGO,	proc_ide_read_mate,	NULL },
 	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_imodel,	NULL },
+#ifdef CONFIG_ALL_PPC
+	{ "devspec",	S_IFREG|S_IRUGO,	proc_ide_read_devspec,	NULL },
+#endif	
 	{ NULL,	0, NULL, NULL }
 };
 
diff -urN linux-2.4.21-pre7/drivers/ide/ide.c linux-2.4.21-rc1/drivers/ide/ide.c
--- linux-2.4.21-pre7/drivers/ide/ide.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/ide.c	2003-04-21 11:48:41.000000000 -0700
@@ -174,14 +174,6 @@
 
 static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
 
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-/*
- * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
- * which is shared between several drivers.
- */
-static int ide_intr_lock;
-#endif /* __mc68000__ || CONFIG_APUS */
-
 #ifdef CONFIG_IDEDMA_AUTO
 int noautodma = 0;
 #else
@@ -2371,12 +2363,12 @@
 
 #ifdef CONFIG_BLK_DEV_IDE
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
-		ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */
+		ide_get_lock(NULL, NULL); /* for atari only */
 
 	(void) ideprobe_init();
 
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
-		ide_release_lock(&ide_intr_lock);	/* for atari only */
+		ide_release_lock();	/* for atari only */
 #endif /* CONFIG_BLK_DEV_IDE */
 
 #ifdef CONFIG_PROC_FS
diff -urN linux-2.4.21-pre7/drivers/ide/legacy/falconide.c linux-2.4.21-rc1/drivers/ide/legacy/falconide.c
--- linux-2.4.21-pre7/drivers/ide/legacy/falconide.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/legacy/falconide.c	2003-04-21 11:48:41.000000000 -0700
@@ -49,6 +49,14 @@
 
 
     /*
+     *  falconide_intr_lock is used to obtain access to the IDE interrupt,
+     *  which is shared between several drivers.
+     */
+
+int falconide_intr_lock;
+
+
+    /*
      *  Probe for a Falcon IDE interface
      */
 
diff -urN linux-2.4.21-pre7/drivers/ide/legacy/gayle.c linux-2.4.21-rc1/drivers/ide/legacy/gayle.c
--- linux-2.4.21-pre7/drivers/ide/legacy/gayle.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/legacy/gayle.c	2003-04-21 11:48:41.000000000 -0700
@@ -125,6 +125,7 @@
 	ide_ioreg_t base, ctrlport, irqport;
 	ide_ack_intr_t *ack_intr;
 	hw_regs_t hw;
+	ide_hwif_t *hwif;
 	int index;
 	unsigned long phys_base, res_start, res_n;
 
@@ -154,11 +155,12 @@
 
 	ide_setup_ports(&hw, base, gayle_offsets,
 			ctrlport, irqport, ack_intr,
-//			gaule_iops,
+//			&gayle_iops,
 			IRQ_AMIGA_PORTS);
 
-	index = ide_register_hw(&hw, NULL);
+	index = ide_register_hw(&hw, &hwif);
 	if (index != -1) {
+	    hwif->mmio = 2;
 	    switch (i) {
 		case 0:
 		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
diff -urN linux-2.4.21-pre7/drivers/ide/legacy/q40ide.c linux-2.4.21-rc1/drivers/ide/legacy/q40ide.c
--- linux-2.4.21-pre7/drivers/ide/legacy/q40ide.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/legacy/q40ide.c	2003-04-21 11:48:41.000000000 -0700
@@ -31,7 +31,7 @@
 #define PCIDE_BASE5	0x1e0
 #define PCIDE_BASE6	0x160
 
-static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
+static const ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
     PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
     PCIDE_BASE6 */
 };
@@ -41,23 +41,21 @@
      *  Offsets from one of the above bases
      */
 
+/* used to do addr translation here but it is easier to do in setup ports */
+/*#define IDE_OFF_B(x)	((unsigned long)Q40_ISA_IO_B((IDE_##x##_OFFSET)))*/
 
-/* HD_DATA was redefined in asm-m68k/ide.h */
-#undef HD_DATA
-#define HD_DATA  0x1f0
-
-
-#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
+#define IDE_OFF_B(x)	((ide_ioreg_t)((IDE_##x##_OFFSET)))
+#define IDE_OFF_W(x)	((ide_ioreg_t)((IDE_##x##_OFFSET)))
 
 static const int pcide_offsets[IDE_NR_PORTS] = {
-    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
-    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
-    PCIDE_REG(CMD)
+    IDE_OFF_W(DATA), IDE_OFF_B(ERROR), IDE_OFF_B(NSECTOR), IDE_OFF_B(SECTOR),
+    IDE_OFF_B(LCYL), IDE_OFF_B(HCYL), 6 /*IDE_OFF_B(CURRENT)*/, IDE_OFF_B(STATUS),
+    518/*IDE_OFF(CMD)*/
 };
 
-static int q40ide_default_irq(q40ide_ioreg_t base)
+static int q40ide_default_irq(ide_ioreg_t base)
 {
-           switch (base) { 
+           switch (base) {
 	            case 0x1f0: return 14;
 		    case 0x170: return 15;
 		    case 0x1e8: return 11;
@@ -67,14 +65,58 @@
 }
 
 
+/*
+ * This is very similar to ide_setup_ports except that addresses
+ * are pretranslated for q40 ISA access
+ */
+void q40_ide_setup_ports ( hw_regs_t *hw,
+			ide_ioreg_t base, int *offsets,
+			ide_ioreg_t ctrl, ide_ioreg_t intr,
+			ide_ack_intr_t *ack_intr,
+/*
+ *			ide_io_ops_t *iops,
+ */
+			int irq)
+{
+	int i;
 
-    /*
-     *  Probe for Q40 IDE interfaces
-     */
+	for (i = 0; i < IDE_NR_PORTS; i++) {
+		/* BIG FAT WARNING: 
+		   assumption: only DATA port is ever used in 16 bit mode */
+		if ( i==0 )
+			hw->io_ports[i] = Q40_ISA_IO_W(base + offsets[i]);
+		else
+			hw->io_ports[i] = Q40_ISA_IO_B(base + offsets[i]);
+	}
+	
+	hw->irq = irq;
+	hw->dma = NO_DMA;
+	hw->ack_intr = ack_intr;
+/*
+ *	hw->iops = iops;
+ */
+}
+
+
+
+/* 
+ * the static array is needed to have the name reported in /proc/ioports,
+ * hwif->name unfortunately isn´t available yet
+ */
+static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
+	"ide0", "ide1"
+};
+
+/*
+ *  Probe for Q40 IDE interfaces
+ */
 
 void q40ide_init(void)
 {
     int i;
+    ide_hwif_t *hwif;
+    int index;
+    const char *name;
 
     if (!MACH_IS_Q40)
       return ;
@@ -82,12 +124,27 @@
     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
 	hw_regs_t hw;
 
-	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
-			pcide_bases[i]+0x206, 
-			0, NULL,
-//			pcide_iops,
+	name = q40_ide_names[i];
+	if (!request_region(pcide_bases[i], 8, name)) {
+		printk("could not reserve ports %lx-%lx for %s\n",
+		       pcide_bases[i],pcide_bases[i]+8,name);
+		continue;
+	}
+	if (!request_region(pcide_bases[i]+0x206, 1, name)) {
+		printk("could not reserve port %lx for %s\n",
+		       pcide_bases[i]+0x206,name);
+		release_region(pcide_bases[i], 8);
+		continue;
+	}
+	q40_ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i],
+			(int *)pcide_offsets,
+			(ide_ioreg_t)pcide_bases[i]+0x206, 0, NULL,
+//			m68kide_iops,
 			q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw, NULL);
+	index = ide_register_hw(&hw, &hwif);
+	// **FIXME**
+	if (index != -1)
+		hwif->mmio = 2;
     }
 }
 
diff -urN linux-2.4.21-pre7/drivers/ide/ppc/pmac.c linux-2.4.21-rc1/drivers/ide/ppc/pmac.c
--- linux-2.4.21-pre7/drivers/ide/ppc/pmac.c	2003-04-21 11:48:29.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ide/ppc/pmac.c	2003-04-21 11:48:41.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/ppc/ide-pmac.c
+ * linux/drivers/ide/ppc/pmac.c
  *
  * Support for IDE interfaces on PowerMacs.
  * These IDE interfaces are memory-mapped and have a DBDMA channel
@@ -408,7 +408,7 @@
 	else
 		writel(pmif->timings[0],
 			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
-	io_flush(readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG)));
+	(void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
 }
 
 static void __pmac
@@ -430,7 +430,7 @@
 		writel(pmif->timings[2],
 		       (unsigned *)(IDE_DATA_REG + IDE_KAUAI_ULTRA_CONFIG));
 	}
-	io_flush(readl((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG)));
+	(void)readl((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG));
 }
 
 static void __pmac
@@ -454,7 +454,6 @@
 	
 	writeb(value, port);	
 	tmp = readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
-	io_flush(value);
 }
 
 static int __pmac
@@ -469,7 +468,7 @@
 	SELECT_MASK(drive, 0);
 	udelay(1);
 	/* Get rid of pending error state */
-	io_flush(hwif->INB(IDE_STATUS_REG));
+	(void)hwif->INB(IDE_STATUS_REG);
 	/* Timeout bumped for some powerbooks */
 	if (wait_for_ready(drive, 2000)) {
 		/* Timeout bumped for some powerbooks */
@@ -1139,7 +1138,7 @@
 		/* Tell common code _not_ to mess with resources */
 		hwif->mmio = 2;
 		hwif->hwif_data = pmif;
-		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
+		pmac_ide_init_hwif_ports(&hwif->hw, regbase, 0, &hwif->irq);
 		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;
@@ -1568,7 +1567,7 @@
 	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
 		writel(pmif->timings[unit]+0x00800000UL,
 			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
-		io_flush(readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG)));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
 	}
 
 	drive->waiting_for_dma = 1;	
@@ -1624,7 +1623,7 @@
 	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
 		writel(pmif->timings[unit],
 			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
-		io_flush(readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG)));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
 	}
 
 	drive->waiting_for_dma = 1;
@@ -1674,7 +1673,7 @@
 
 	writel((RUN << 16) | RUN, &dma->control);
 	/* Make sure it gets to the controller right now */
-	io_flush(readl(&dma->control));
+	(void)readl(&dma->control);
 	return 0;
 }
 
@@ -1791,11 +1790,10 @@
 			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);
 	}
 
-	pmif->dma_regs =
-		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
-
 	/*
 	 * Allocate space for the DBDMA commands.
 	 * The +2 is +1 for the stop command and +1 to allow for
@@ -1863,7 +1861,7 @@
 		SELECT_DRIVE(drive);
 		SELECT_MASK(drive, 0);
 		hwif->OUTB(drive->select.all, IDE_SELECT_REG);
-		io_flush(hwif->INB(IDE_SELECT_REG));
+		(void) hwif->INB(IDE_SELECT_REG);
 		udelay(100);
 		hwif->OUTB(0x00, IDE_SECTOR_REG);
 		hwif->OUTB(0x00, IDE_NSECTOR_REG);
diff -urN linux-2.4.21-pre7/drivers/ieee1394/csr.c linux-2.4.21-rc1/drivers/ieee1394/csr.c
--- linux-2.4.21-pre7/drivers/ieee1394/csr.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/csr.c	2003-04-21 11:48:41.000000000 -0700
@@ -54,8 +54,15 @@
 
         host->csr.bus_manager_id = 0x3f;
         host->csr.bandwidth_available = 4915;
-        host->csr.channels_available_hi = ~0;
+	host->csr.channels_available_hi = 0xfffffffe;	/* pre-alloc ch 31 per 1394a-2000 */
         host->csr.channels_available_lo = ~0;
+	host->csr.broadcast_channel = 0x80000000 | 31;
+
+	if (host->is_irm) {
+		if (host->driver->hw_csr_reg) {
+			host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
+		}
+	}
 
         host->csr.node_ids = host->node_id << 16;
 
@@ -95,8 +102,15 @@
         host->csr.bus_time              = 0;
         host->csr.bus_manager_id        = 0x3f;
         host->csr.bandwidth_available   = 4915;
-        host->csr.channels_available_hi = ~0;
+	host->csr.channels_available_hi = 0xfffffffe;	/* pre-alloc ch 31 per 1394a-2000 */
         host->csr.channels_available_lo = ~0;
+	host->csr.broadcast_channel = 0x80000000 | 31;
+
+	if (host->is_irm) {
+		if (host->driver->hw_csr_reg) {
+			host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
+		}
+	}
 }
 
 int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
@@ -268,6 +282,10 @@
                 *(buf++) = cpu_to_be32(ret);
                 out;
 
+	case CSR_BROADCAST_CHANNEL:
+		*(buf++) = cpu_to_be32(host->csr.broadcast_channel);
+		out;
+
                 /* address gap to end - fall through to default */
         default:
                 return RCODE_ADDRESS_ERROR;
@@ -345,6 +363,12 @@
                 /* these are not writable, only lockable */
                 return RCODE_TYPE_ERROR;
 
+	case CSR_BROADCAST_CHANNEL:
+		/* only the valid bit can be written */
+		host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
+                        | (be32_to_cpu(*data) & 0x40000000);
+		out;
+
                 /* address gap to end - fall through */
         default:
                 return RCODE_ADDRESS_ERROR;
@@ -373,6 +397,18 @@
         data = be32_to_cpu(data);
         arg = be32_to_cpu(arg);
 
+	/* Is somebody releasing the broadcast_channel on us? */
+	if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
+		/* Note: this is may not be the right way to handle
+		 * the problem, so we should look into the proper way
+		 * eventually. */
+		HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
+			  "broadcast channel 31.  Ignoring.",
+			  NODE_BUS_ARGS(nodeid));
+
+		data &= ~0x1;	/* keep broadcast channel allocated */
+	}
+
         if (host->driver->hw_csr_reg) {
                 quadlet_t old;
 
@@ -389,23 +425,84 @@
         switch (csraddr) {
         case CSR_BUS_MANAGER_ID:
                 regptr = &host->csr.bus_manager_id;
+		*store = cpu_to_be32(*regptr);
+		if (*regptr == arg)
+			*regptr = data;
                 break;
 
         case CSR_BANDWIDTH_AVAILABLE:
+        {
+                quadlet_t bandwidth;
+                quadlet_t old;
+                quadlet_t new;
+
                 regptr = &host->csr.bandwidth_available;
+                old = *regptr;
+
+                /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
+                if (arg > 0x1fff) {
+                        *store = cpu_to_be32(old);	/* change nothing */
                 break;
+                }
+                data &= 0x1fff;
+                if (arg >= data) {
+                        /* allocate bandwidth */
+                        bandwidth = arg - data;
+                        if (old >= bandwidth) {
+                                new = old - bandwidth;
+                                *store = cpu_to_be32(arg);
+                                *regptr = new;
+                        } else {
+                                *store = cpu_to_be32(old);
+                        }
+                } else {
+                        /* deallocate bandwidth */
+                        bandwidth = data - arg;
+                        if (old + bandwidth < 0x2000) {
+                                new = old + bandwidth;
+                                *store = cpu_to_be32(arg);
+                                *regptr = new;
+                        } else {
+                                *store = cpu_to_be32(old);
+                        }
+                }
+                break;
+        }
 
         case CSR_CHANNELS_AVAILABLE_HI:
+        {
+                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
+                quadlet_t affected_channels = arg ^ data;
+
                 regptr = &host->csr.channels_available_hi;
+
+                if ((arg & affected_channels) == (*regptr & affected_channels)) {
+                        *regptr ^= affected_channels;
+                        *store = cpu_to_be32(arg);
+                } else {
+                        *store = cpu_to_be32(*regptr);
+                }
+
                 break;
+        }
 
         case CSR_CHANNELS_AVAILABLE_LO:
+        {
+                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
+                quadlet_t affected_channels = arg ^ data;
+
                 regptr = &host->csr.channels_available_lo;
+
+                if ((arg & affected_channels) == (*regptr & affected_channels)) {
+                        *regptr ^= affected_channels;
+                        *store = cpu_to_be32(arg);
+                } else {
+                        *store = cpu_to_be32(*regptr);
+                }
                 break;
         }
+        }
 
-        *store = cpu_to_be32(*regptr);
-        if (*regptr == arg) *regptr = data;
         spin_unlock_irqrestore(&host->csr.lock, flags);
 
         return RCODE_COMPLETE;
@@ -420,10 +517,7 @@
         case CSR_SPLIT_TIMEOUT_LO:
         case CSR_CYCLE_TIME:
         case CSR_BUS_TIME:
-        case CSR_BUS_MANAGER_ID:
-        case CSR_BANDWIDTH_AVAILABLE:
-        case CSR_CHANNELS_AVAILABLE_HI:
-        case CSR_CHANNELS_AVAILABLE_LO:
+	case CSR_BROADCAST_CHANNEL:
                 return RCODE_TYPE_ERROR;
 
         case CSR_BUSY_TIMEOUT:
@@ -433,6 +527,97 @@
         }
 }
 
+static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
+		       u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
+{
+	int csraddr = addr - CSR_REGISTER_BASE;
+	unsigned long flags;
+
+	data = be64_to_cpu(data);
+	arg = be64_to_cpu(arg);
+
+	if (csraddr & 0x3)
+		return RCODE_TYPE_ERROR;
+
+	if (csraddr != CSR_CHANNELS_AVAILABLE
+	    || extcode != EXTCODE_COMPARE_SWAP)
+		goto unsupported_lock64req;
+
+	/* Is somebody releasing the broadcast_channel on us? */
+	if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
+		/* Note: this is may not be the right way to handle
+		 * the problem, so we should look into the proper way
+                 * eventually. */
+		HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
+			  "broadcast channel 31.  Ignoring.",
+			  NODE_BUS_ARGS(nodeid));
+
+		data &= ~0x100000000ULL;	/* keep broadcast channel allocated */
+	}
+
+	if (host->driver->hw_csr_reg) {
+		quadlet_t data_hi, data_lo;
+		quadlet_t arg_hi, arg_lo;
+		quadlet_t old_hi, old_lo;
+
+		data_hi = data >> 32;
+		data_lo = data & 0xFFFFFFFF;
+		arg_hi = arg >> 32;
+		arg_lo = arg & 0xFFFFFFFF;
+
+		old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
+                                                  data_hi, arg_hi);
+
+		old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
+                                                  data_lo, arg_lo);
+
+		*store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
+	} else {
+		octlet_t old;
+		octlet_t affected_channels = arg ^ data;
+
+		spin_lock_irqsave(&host->csr.lock, flags);
+
+		old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
+
+		if ((arg & affected_channels) == (old & affected_channels)) {
+			host->csr.channels_available_hi ^= (affected_channels >> 32);
+			host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
+			*store = cpu_to_be64(arg);
+		} else {
+			*store = cpu_to_be64(old);
+		}
+
+		spin_unlock_irqrestore(&host->csr.lock, flags);
+	}
+
+	/* Is somebody erroneously releasing the broadcast_channel on us? */
+	if (host->csr.channels_available_hi & 0x1)
+		host->csr.channels_available_hi &= ~0x1;
+
+	return RCODE_COMPLETE;
+
+ unsupported_lock64req:
+	switch (csraddr) {
+	case CSR_STATE_CLEAR:
+	case CSR_STATE_SET:
+	case CSR_RESET_START:
+	case CSR_NODE_IDS:
+	case CSR_SPLIT_TIMEOUT_HI:
+	case CSR_SPLIT_TIMEOUT_LO:
+	case CSR_CYCLE_TIME:
+	case CSR_BUS_TIME:
+	case CSR_BUS_MANAGER_ID:
+	case CSR_BROADCAST_CHANNEL:
+	case CSR_BUSY_TIMEOUT:
+	case CSR_BANDWIDTH_AVAILABLE:
+		return RCODE_TYPE_ERROR;
+
+	default:
+		return RCODE_ADDRESS_ERROR;
+	}
+}
+
 static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
 		     quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
@@ -474,6 +659,7 @@
         .read = read_regs,
         .write = write_regs,
         .lock = lock_regs,
+	.lock64 = lock64_regs,
 };
 
 static struct hpsb_highlevel *hl;
diff -urN linux-2.4.21-pre7/drivers/ieee1394/csr.h linux-2.4.21-rc1/drivers/ieee1394/csr.h
--- linux-2.4.21-pre7/drivers/ieee1394/csr.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/csr.h	2003-04-21 11:48:41.000000000 -0700
@@ -16,8 +16,10 @@
 #define CSR_BUSY_TIMEOUT          0x210
 #define CSR_BUS_MANAGER_ID        0x21c
 #define CSR_BANDWIDTH_AVAILABLE   0x220
+#define CSR_CHANNELS_AVAILABLE    0x224
 #define CSR_CHANNELS_AVAILABLE_HI 0x224
 #define CSR_CHANNELS_AVAILABLE_LO 0x228
+#define CSR_BROADCAST_CHANNEL     0x234
 #define CSR_CONFIG_ROM            0x400
 #define CSR_CONFIG_ROM_END        0x800
 #define CSR_FCP_COMMAND           0xB00
@@ -40,6 +42,7 @@
         quadlet_t bus_manager_id;
         quadlet_t bandwidth_available;
         quadlet_t channels_available_hi, channels_available_lo;
+	quadlet_t broadcast_channel;
 
         quadlet_t *rom;
         size_t rom_size;
diff -urN linux-2.4.21-pre7/drivers/ieee1394/dv1394.c linux-2.4.21-rc1/drivers/ieee1394/dv1394.c
--- linux-2.4.21-pre7/drivers/ieee1394/dv1394.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/dv1394.c	2003-04-21 11:48:41.000000000 -0700
@@ -117,6 +117,7 @@
 #include "hosts.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"	
+#include "ieee1394_hotplug.h"
 #include "dv1394.h"
 #include "dv1394-private.h"
 
@@ -2564,6 +2565,29 @@
 }
 #endif /* CONFIG_DEVFS_FS */
 
+
+/*** HOTPLUG STUFF **********************************************************/
+/*
+ * Export information about protocols/devices supported by this driver.
+ */
+static struct ieee1394_device_id dv1394_id_table[] = {
+	{
+		.match_flags =IEEE1394_MATCH_SPECIFIER_ID |
+		              IEEE1394_MATCH_VERSION,
+		.specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+		.version =    AVC_SW_VERSION_ENTRY & 0xffffff
+	},
+	{ }
+};
+
+static struct hpsb_protocol_driver dv1394_driver = {
+	.name =		"DV/1394 Driver",
+	.id_table = 	dv1394_id_table,
+};
+
+MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
+
+
 /*** IEEE1394 HPSB CALLBACKS ***********************************************/
 
 static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
@@ -2898,8 +2922,11 @@
 
 static void __exit dv1394_exit_module(void)
 {
+	hpsb_unregister_protocol(&dv1394_driver);
+
 	hpsb_unregister_highlevel (hl_handle);
 	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
+
 #ifdef CONFIG_DEVFS_FS
 	dv1394_devfs_del("dv");
 #endif
@@ -2948,6 +2975,8 @@
 		return -ENOMEM;
 	}
 
+	hpsb_register_protocol(&dv1394_driver);
+
 	return 0;
 }
 
diff -urN linux-2.4.21-pre7/drivers/ieee1394/eth1394.c linux-2.4.21-rc1/drivers/ieee1394/eth1394.c
--- linux-2.4.21-pre7/drivers/ieee1394/eth1394.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/eth1394.c	2003-04-21 11:48:41.000000000 -0700
@@ -65,6 +65,7 @@
 #include "ieee1394_transactions.h"
 #include "ieee1394.h"
 #include "highlevel.h"
+#include "iso.h"
 #include "eth1394.h"
 
 #define ETH1394_PRINT_G(level, fmt, args...) \
@@ -77,7 +78,7 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 807 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 827 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
@@ -101,6 +102,9 @@
 MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
 MODULE_LICENSE("GPL");
 
+static void ether1394_iso(struct hpsb_iso *iso);
+
+
 /* 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)
@@ -178,15 +182,26 @@
  * 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)
+                                          int proto, struct packet_task *ptask)
 {
 	union eth1394_hdr *hdr =
 		(union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]);
 
+	hdr->words.word1 = 0;
 	hdr->common.lf = ETH1394_HDR_LF_UF;
 	hdr->words.word1 = htons(hdr->words.word1);
 	hdr->uf.ether_type = proto;
 
+	/* Set the transmission type for the packet.  Right now only ARP
+	 * packets are sent via GASP.  IP broadcast and IP multicast are not
+	 * yet supported properly, they too should use GASP. */
+	switch(proto) {
+	case __constant_htons(ETH_P_ARP):
+		ptask->tx_type = ETH1394_GASP;
+		break;
+	default:
+		ptask->tx_type = ETH1394_WRREQ;
+	}
 	return;
 }
 
@@ -199,7 +214,7 @@
 {
 	struct eth1394_priv *priv =
 		(struct eth1394_priv *)(dev->priv);
-	u16 phy_id = priv->host->node_id & NODE_MASK;
+	u16 phy_id = NODEID_TO_NODE(priv->host->node_id);
 
 	unsigned char *arp_ptr = (unsigned char *)skb->data;
 	struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
@@ -279,7 +294,8 @@
 {
 	unsigned long flags;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-	int phy_id = priv->host->node_id & NODE_MASK;
+	int phy_id = NODEID_TO_NODE(priv->host->node_id);
+	struct hpsb_host *host = priv->host;
 
 	spin_lock_irqsave (&priv->lock, flags);
 
@@ -289,20 +305,23 @@
 	memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi));
 	memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo));
 
+	priv->bc_state = ETHER1394_BC_CHECK;
+
 	/* 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_register_limits (phy_id, (be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf,
+				   host->speed_map[(phy_id << 6) + phy_id],
+				   (u64)(((u64)be32_to_cpu(host->csr.rom[3]) << 32) |
+				   be32_to_cpu(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);
+		dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */
+			(sizeof (union eth1394_hdr) + 8);	/* (hdr + GASP) */
 
 	/* Set our hardware address while we're at it */
-	*(nodeid_t *)dev->dev_addr = htons (priv->host->node_id);
+	*(nodeid_t *)dev->dev_addr = htons (host->node_id);
 
 	spin_unlock_irqrestore (&priv->lock, flags);
 }
@@ -360,7 +379,7 @@
 	priv->host = host;
 
 	hi = (struct host_info *)kmalloc (sizeof (struct host_info),
-					  GFP_KERNEL);
+					  in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
 
 	if (hi == NULL)
 		goto out;
@@ -383,6 +402,15 @@
 	list_add_tail (&hi->list, &host_info_list);
 	spin_unlock_irq (&host_info_lock);
 
+	/* Ignore validity in hopes that it will be set in the future.  It'll
+	 * check it on transmit. */
+	priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
+
+	priv->iso = hpsb_iso_recv_init(host, 8 * 4096, 8, priv->broadcast_channel,
+				       1, ether1394_iso);
+	if (priv->iso == NULL) {
+		priv->bc_state = ETHER1394_BC_CLOSED;
+	}
 	return;
 
 out:
@@ -396,11 +424,14 @@
 /* Remove a card from our list */
 static void ether1394_remove_host (struct hpsb_host *host)
 {
+	struct eth1394_priv *priv;
 	struct host_info *hi;
 
 	spin_lock_irq (&host_info_lock);
 	hi = find_host_info (host);
 	if (hi != NULL) {
+		priv = (struct eth1394_priv *)hi->dev->priv;
+		priv->bc_state = ETHER1394_BC_CLOSED;
 		unregister_netdev (hi->dev);
 		kfree (hi->dev);
 		list_del (&hi->list);
@@ -480,7 +511,7 @@
 	 * about the sending machine.  */
 	if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) {
 		unsigned long flags;
-		u16 phy_id = srcid & NODE_MASK;
+		u16 phy_id = NODEID_TO_NODE(srcid);
 		struct eth1394_priv *priv =
 			(struct eth1394_priv *)dev->priv;
 		struct eth1394_arp arp1394;
@@ -591,6 +622,104 @@
 	return RCODE_COMPLETE;
 }
 
+static void ether1394_iso(struct hpsb_iso *iso)
+{
+	struct sk_buff *skb;
+	quadlet_t *data;
+	char *buf;
+	int flags;
+	struct net_device *dev = ether1394_find_dev(iso->host);
+	struct eth1394_priv *priv;
+	unsigned int len;
+	u32 specifier_id;
+	u16 source_id;
+	int i;
+	int nready;
+
+	if (dev == NULL) {
+		ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n",
+				 iso->host->driver->name);
+		return;
+	}
+
+	nready = hpsb_iso_n_ready(iso);
+	for(i = 0; i < nready; i++) {
+		struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet + i];
+		data = (quadlet_t*) (iso->data_buf.kvirt + info->offset);
+
+		/* skip over GASP header */
+		buf = (char *)data + 8;
+		len = info->len - 8;
+
+		specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) |
+				((be32_to_cpu(data[1]) & 0xff000000) >> 24));
+		source_id = be32_to_cpu(data[0]) >> 16;
+
+		priv = (struct eth1394_priv *)dev->priv;
+
+		if (info->channel != priv->broadcast_channel ||
+		    specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
+			/* This packet is not for us */
+			continue;
+		}
+
+		/* 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++;
+			break;
+		}
+
+		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, source_id,
+						       LOCAL_BUS | ALL_NODES);
+
+		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:
+		spin_unlock_irqrestore (&priv->lock, flags);
+	}
+
+	hpsb_iso_recv_release_packets(iso, i);
+
+	netif_start_queue(dev);
+	
+	dev->last_rx = jiffies;
+
+	return;
+}
+
+
 /* This function is our scheduled write */
 static void hpsb_write_sched (void *__ptask)
 {
@@ -599,12 +728,25 @@
 	struct net_device *dev = ptask->skb->dev;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
         unsigned long flags;
+	int status;
+ 
+	if (ptask->tx_type == ETH1394_GASP) {
+		status  = hpsb_send_gasp(priv->host, priv->broadcast_channel,
+					 get_hpsb_generation(priv->host),
+					 (quadlet_t *)skb->data, skb->len,
+					 ETHER1394_GASP_SPECIFIER_ID,
+					 ETHER1394_GASP_VERSION);
+	} else {
+		status = hpsb_write(priv->host, ptask->dest_node,
+				    get_hpsb_generation(priv->host),
+				    ptask->addr, (quadlet_t *)skb->data,
+				    skb->len);
+	}
+
 
 	/* 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)) {
+	if (!status) {
 		priv->stats.tx_bytes += skb->len;
 		priv->stats.tx_packets++;
 	} else {
@@ -636,6 +778,67 @@
 	struct packet_task *ptask = NULL;
 	int ret = 0;
 
+	spin_lock_irqsave (&priv->lock, flags);
+	if (priv->bc_state == ETHER1394_BC_CLOSED) {
+		ETH1394_PRINT(KERN_ERR, dev->name,
+			      "Cannot send packet, no broadcast channel available.");
+		ret = -EAGAIN;
+		goto fail;
+	}
+
+	/* First time sending?  Need a broadcast channel for ARP and for
+	 * listening on */
+	if (priv->bc_state == ETHER1394_BC_CHECK) {
+		quadlet_t bc;
+
+		/* Get the local copy of the broadcast channel and check its
+		 * validity (the IRM should validate it for us) */
+
+		bc = priv->host->csr.broadcast_channel;
+
+		if ((bc & 0xc0000000) != 0xc0000000) {
+			/* broadcast channel not validated yet */
+			ETH1394_PRINT(KERN_WARNING, dev->name,
+				      "Error BROADCAST_CHANNEL register valid "
+				      "bit not set, can't send IP traffic\n");
+			hpsb_iso_shutdown(priv->iso);
+			priv->bc_state = ETHER1394_BC_CLOSED;
+			ret = -EAGAIN;
+			spin_unlock_irqrestore (&priv->lock, flags);
+			goto fail;
+		}
+		if (priv->broadcast_channel != (bc & 0x3f)) {
+			/* This really shouldn't be possible, but just in case
+			 * the IEEE 1394 spec changes regarding broadcast
+			 * channels in the future. */
+			hpsb_iso_shutdown(priv->iso);
+
+			priv->broadcast_channel = bc & 0x3f;
+			ETH1394_PRINT(KERN_WARNING, dev->name,
+				      "Changing to broadcast channel %d...\n",
+				      priv->broadcast_channel);
+
+			priv->iso = hpsb_iso_recv_init(priv->host, 8 * 4096,
+						       8, priv->broadcast_channel,
+						       1, ether1394_iso);
+			if (priv->iso == NULL) {
+				ret = -EAGAIN;
+				goto fail;
+			}
+		}
+		if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) {
+			ETH1394_PRINT(KERN_ERR, dev->name,
+				      "Could not start async reception\n");
+			hpsb_iso_shutdown(priv->iso);
+			priv->bc_state = ETHER1394_BC_CLOSED;
+			ret = -EAGAIN;
+			spin_unlock_irqrestore (&priv->lock, flags);
+			goto fail;
+		}
+		priv->bc_state = ETHER1394_BC_OPENED;
+	}
+	spin_unlock_irqrestore (&priv->lock, flags);
+
 	if ((skb = skb_share_check (skb, kmflags)) == NULL) {
 		ret = -ENOMEM;
 		goto fail;
@@ -654,8 +857,14 @@
 	if (proto == __constant_htons (ETH_P_ARP))
 		ether1394_arp_to_1394arp (skb, dev);
 
+	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
+	if (ptask == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	/* Now add our encapsulation header */
-	ether1394_encapsulate (skb, dev, proto);
+	ether1394_encapsulate (skb, dev, proto, ptask);
 
 	/* TODO: The above encapsulate function needs to recognize when a
 	 * packet needs to be split for a specified node. It should create
@@ -663,26 +872,22 @@
 	 * 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
+	 * we do, we will send ARP requests via GASP format, and so we won't
 	 * 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];
+	addr = (u64)priv->fifo_hi[NODEID_TO_NODE(dest_node)] << 32 |
+		priv->fifo_lo[NODEID_TO_NODE(dest_node)];
 	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;
+	/* TODO: When 2.4 is out of the way, give each of our ethernet
+	 * dev's a workqueue to handle these.  */
 	INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
 	schedule_task(&ptask->tq);
 
@@ -700,7 +905,7 @@
 		netif_wake_queue (dev);
 	spin_unlock_irqrestore (&priv->lock, flags);
 
-	return ret;
+	return 0;  /* returning non-zero causes serious problems */
 }
 
 /* Function for incoming 1394 packets */
@@ -736,6 +941,19 @@
 
 static void __exit ether1394_exit_module (void)
 {
+	struct list_head *lh;
+	struct host_info *hi;
+	struct eth1394_priv *priv;
+
+	lh = host_info_list.next;
+	while (lh != &host_info_list) {
+		hi = list_entry (lh, struct host_info, list);
+		priv = (struct eth1394_priv*)hi->dev->priv;
+		if (priv->bc_state != ETHER1394_BC_CLOSED) {
+			hpsb_iso_shutdown(priv->iso);
+		}
+		lh = lh->next;
+	}
 	hpsb_unregister_highlevel (hl_handle);
 	kmem_cache_destroy(packet_task_cache);
 }
diff -urN linux-2.4.21-pre7/drivers/ieee1394/eth1394.h linux-2.4.21-rc1/drivers/ieee1394/eth1394.h
--- linux-2.4.21-pre7/drivers/ieee1394/eth1394.h	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.21-rc1/drivers/ieee1394/eth1394.h	2003-04-21 11:48:41.000000000 -0700
@@ -30,9 +30,16 @@
 #define ETHER1394_REGION_ADDR		0xfffff0200000ULL
 #define ETHER1394_REGION_ADDR_END	(ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
 
+/* GASP identifier numbers for IPv4 over IEEE 1394 */
+#define ETHER1394_GASP_SPECIFIER_ID	0x00005E
+#define ETHER1394_GASP_VERSION		1
+
 /* Node set == 64 */
 #define NODE_SET			(ALL_NODES + 1)
 
+enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED,
+			 ETHER1394_BC_CHECK };
+
 /* Private structure for our ethernet driver */
 struct eth1394_priv {
 	struct net_device_stats stats;	/* Device stats			 */
@@ -43,6 +50,9 @@
 	u32 fifo_lo[ALL_NODES];		/* 32bit lo fifo offset per node */
 	u64 eui[ALL_NODES];		/* EUI-64 per node		 */
 	spinlock_t lock;		/* Private lock			 */
+	int broadcast_channel;		/* Async stream Broadcast Channel */
+	enum eth1394_bc_states bc_state; /* broadcast channel state	 */
+	struct hpsb_iso *iso;		/* Async stream recv handle	 */
 };
 
 struct host_info {
@@ -51,12 +61,15 @@
 	struct net_device *dev;
 };
 
+typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
+
 /* This is our task struct. It's used for the packet complete 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 */
+	eth1394_tx_type tx_type;	/* Send data via GASP or Write Req. */
 };
 
 /* IP1394 headers */
diff -urN linux-2.4.21-pre7/drivers/ieee1394/highlevel.c linux-2.4.21-rc1/drivers/ieee1394/highlevel.c
--- linux-2.4.21-pre7/drivers/ieee1394/highlevel.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/highlevel.c	2003-04-21 11:48:41.000000000 -0700
@@ -98,6 +98,7 @@
         struct hpsb_address_serve *as;
         struct list_head *entry;
         int retval = 0;
+        unsigned long flags;
 
         if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
                 HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
@@ -116,7 +117,7 @@
         as->start = start;
         as->end = end;
 
-        write_lock_irq(&addr_space_lock);
+        write_lock_irqsave(&addr_space_lock, flags);
         entry = addr_space.next;
 
         while (list_entry(entry, struct hpsb_address_serve, as_list)->end
@@ -130,7 +131,7 @@
                 }
                 entry = entry->next;
         }
-        write_unlock_irq(&addr_space_lock);
+        write_unlock_irqrestore(&addr_space_lock, flags);
 
         if (retval == 0) {
                 kfree(as);
@@ -144,8 +145,9 @@
         int retval = 0;
         struct hpsb_address_serve *as;
         struct list_head *entry;
+        unsigned long flags;
 
-        write_lock_irq(&addr_space_lock);
+        write_lock_irqsave(&addr_space_lock, flags);
 
         entry = hl->addr_list.next;
 
@@ -161,7 +163,7 @@
                 }
         }
 
-        write_unlock_irq(&addr_space_lock);
+        write_unlock_irqrestore(&addr_space_lock, flags);
 
         return retval;
 }
@@ -237,12 +239,12 @@
 	read_unlock(&hl_drivers_lock);
 }
 
-void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
+void highlevel_iso_receive(struct hpsb_host *host, void *data,
                            unsigned int length)
 {
         struct list_head *entry;
         struct hpsb_highlevel *hl;
-        int channel = (data[0] >> 8) & 0x3f;
+        int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f;
 
         read_lock(&hl_drivers_lock);
         entry = hl_drivers.next;
@@ -258,11 +260,11 @@
 }
 
 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                           u8 *data, unsigned int length)
+                           void *data, unsigned int length)
 {
         struct list_head *entry;
         struct hpsb_highlevel *hl;
-        int cts = data[0] >> 4;
+        int cts = ((quadlet_t *)data)[0] >> 4;
 
         read_lock(&hl_drivers_lock);
         entry = hl_drivers.next;
@@ -278,7 +280,7 @@
         read_unlock(&hl_drivers_lock);
 }
 
-int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
                    u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
@@ -296,12 +298,13 @@
                         partlength = min(as->end - addr, (u64) length);
 
                         if (as->op->read != NULL) {
-                                rcode = as->op->read(host, nodeid, buffer,
+                                rcode = as->op->read(host, nodeid, data,
 						     addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
 
+			(u8 *)data += partlength;
                         length -= partlength;
                         addr += partlength;
 
@@ -324,7 +327,7 @@
 }
 
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length, u16 flags)
+		    void *data, u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -347,6 +350,7 @@
                                 rcode = RCODE_TYPE_ERROR;
                         }
 
+			(u8 *)data += partlength;
                         length -= partlength;
                         addr += partlength;
 
diff -urN linux-2.4.21-pre7/drivers/ieee1394/highlevel.h linux-2.4.21-rc1/drivers/ieee1394/highlevel.h
--- linux-2.4.21-pre7/drivers/ieee1394/highlevel.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/highlevel.h	2003-04-21 11:48:41.000000000 -0700
@@ -108,19 +108,19 @@
    later case, no response will be sent and the driver, that handled the request
    will send the response itself.
 */
-int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
                    u64 addr, unsigned int length, u16 flags);
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
+		    void *data, u64 addr, unsigned int length, u16 flags);
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
                    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
                      u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 
-void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
+void highlevel_iso_receive(struct hpsb_host *host, void *data,
                            unsigned int length);
 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                           u8 *data, unsigned int length);
+                           void *data, unsigned int length);
 
 
 /*
diff -urN linux-2.4.21-pre7/drivers/ieee1394/hosts.c linux-2.4.21-rc1/drivers/ieee1394/hosts.c
--- linux-2.4.21-pre7/drivers/ieee1394/hosts.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.21-rc1/drivers/ieee1394/hosts.c	2003-04-21 11:48:41.000000000 -0700
@@ -155,7 +155,7 @@
         spin_unlock_irqrestore(&hosts_lock, flags);
 
         highlevel_add_host(host);
-        host->driver->devctl(host, RESET_BUS, 0);
+        host->driver->devctl(host, RESET_BUS, LONG_RESET);
 }
 
 void hpsb_remove_host(struct hpsb_host *host)
diff -urN linux-2.4.21-pre7/drivers/ieee1394/hosts.h linux-2.4.21-rc1/drivers/ieee1394/hosts.h
--- linux-2.4.21-pre7/drivers/ieee1394/hosts.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/hosts.h	2003-04-21 11:48:41.000000000 -0700
@@ -142,7 +142,13 @@
 
         /* Short (arbitrated) reset -- only available on 1394a capable
            IEEE 1394 capable controllers */
-        SHORT_RESET
+        SHORT_RESET,
+
+	/* Variants, that set force_root before issueing the bus reset */
+	LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT,
+
+	/* Variants, that clear force_root before issueing the bus reset */
+	LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT
 };
 
 struct hpsb_host_driver {
diff -urN linux-2.4.21-pre7/drivers/ieee1394/ieee1394_core.c linux-2.4.21-rc1/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.21-pre7/drivers/ieee1394/ieee1394_core.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/ieee1394_core.c	2003-04-21 11:48:41.000000000 -0700
@@ -127,9 +127,8 @@
 {
         struct hpsb_packet *packet = NULL;
         void *data = NULL;
-        int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 
-        packet = kmem_cache_alloc(hpsb_packet_cache, kmflags);
+        packet = kmem_cache_alloc(hpsb_packet_cache, GFP_ATOMIC);
         if (packet == NULL)
                 return NULL;
 
@@ -137,7 +136,7 @@
         packet->header = packet->embedded_header;
 
         if (data_size) {
-                data = kmalloc(data_size + 8, kmflags);
+                data = kmalloc(data_size + 8, GFP_ATOMIC);
                 if (data == NULL) {
 			kmem_cache_free(hpsb_packet_cache, packet);
                         return NULL;
@@ -472,8 +471,7 @@
                 quadlet_t *data;
                 size_t size=packet->data_size+packet->header_size;
 
-                int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
-                data = kmalloc(packet->header_size + packet->data_size, kmflags);
+                data = kmalloc(packet->header_size + packet->data_size, GFP_ATOMIC);
                 if (!data) {
                         HPSB_ERR("unable to allocate memory for concatenating header and data");
                         return 0;
@@ -1196,6 +1194,8 @@
 EXPORT_SYMBOL(hpsb_read);
 EXPORT_SYMBOL(hpsb_write);
 EXPORT_SYMBOL(hpsb_lock);
+EXPORT_SYMBOL(hpsb_lock64);
+EXPORT_SYMBOL(hpsb_send_gasp);
 
 /** highlevel.c **/
 EXPORT_SYMBOL(hpsb_register_highlevel);
diff -urN linux-2.4.21-pre7/drivers/ieee1394/ieee1394_hotplug.h linux-2.4.21-rc1/drivers/ieee1394/ieee1394_hotplug.h
--- linux-2.4.21-pre7/drivers/ieee1394/ieee1394_hotplug.h	2001-10-01 21:24:24.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/ieee1394_hotplug.h	2003-04-21 11:48:41.000000000 -0700
@@ -9,6 +9,14 @@
 #define IEEE1394_MATCH_SPECIFIER_ID	0x0004
 #define IEEE1394_MATCH_VERSION		0x0008
 
+/*
+ * Unit spec id and sw version entry for some protocols
+ */
+#define AVC_UNIT_SPEC_ID_ENTRY					0x0000A02D
+#define AVC_SW_VERSION_ENTRY					0x00010001
+#define CAMERA_UNIT_SPEC_ID_ENTRY				0x0000A02D
+#define CAMERA_SW_VERSION_ENTRY					0x00000100
+
 struct ieee1394_device_id {
 	u32 match_flags;
 	u32 vendor_id;
diff -urN linux-2.4.21-pre7/drivers/ieee1394/ieee1394_transactions.c linux-2.4.21-rc1/drivers/ieee1394/ieee1394_transactions.c
--- linux-2.4.21-pre7/drivers/ieee1394/ieee1394_transactions.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/ieee1394_transactions.c	2003-04-21 11:48:41.000000000 -0700
@@ -12,6 +12,7 @@
 #include <linux/sched.h>
 #include <asm/errno.h>
 #include <asm/bitops.h>
+#include <linux/interrupt.h>
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -146,6 +147,17 @@
         packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */
 }
 
+void fill_async_stream_packet(struct hpsb_packet *packet, int length,
+				     int channel, int tag, int sync)
+{
+	packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
+		| (TCODE_STREAM_DATA << 4) | sync;
+
+	packet->header_size = 4;
+	packet->data_size = length;
+	packet->type = hpsb_async;
+	packet->tcode = TCODE_ISO_DATA;
+}
 
 /**
  * get_tlabel - allocate a transaction label
@@ -537,7 +549,6 @@
 }
 
 
-/* We need a hpsb_lock64 function for the 64 bit equivalent.  Probably. */
 int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
 {
@@ -591,3 +602,109 @@
 
         return retval;
 }
+
+int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+		u64 addr, int extcode, octlet_t *data, octlet_t arg)
+{
+	struct hpsb_packet *packet;
+	int retval = 0;
+
+	BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
+
+	packet = hpsb_make_lock64packet(host, node, addr, extcode);
+
+        switch (extcode) {
+        case EXTCODE_MASK_SWAP:
+        case EXTCODE_COMPARE_SWAP:
+        case EXTCODE_BOUNDED_ADD:
+        case EXTCODE_WRAP_ADD:
+                packet->data[0] = (arg >> 32);
+                packet->data[1] = (arg & 0xffffffff);
+                packet->data[2] = (*data >> 32);
+                packet->data[3] = (*data & 0xffffffff);
+                break;
+        case EXTCODE_FETCH_ADD:
+        case EXTCODE_LITTLE_ADD:
+                packet->data[0] = (*data >> 32);
+                packet->data[1] = (*data & 0xffffffff);
+                break;
+        default:
+                return -EINVAL;
+        }
+
+	if (!packet)
+		return -ENOMEM;
+
+	packet->generation = generation;
+	if (!hpsb_send_packet(packet)) {
+		retval = -EINVAL;
+		goto hpsb_lock64_fail;
+	}
+	down(&packet->state_change);
+	down(&packet->state_change);
+	retval = hpsb_packet_success(packet);
+
+	if (retval == 0)
+		*data = (u64)packet->data[1] << 32 | packet->data[0];
+
+hpsb_lock64_fail:
+        free_tlabel(host, node, packet->tlabel);
+	free_hpsb_packet(packet);
+
+        return retval;
+}
+
+int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
+		   quadlet_t *buffer, size_t length, u32 specifier_id,
+		   unsigned int version)
+{
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	int i;
+#endif
+
+	struct hpsb_packet *packet;
+	int retval = 0;
+	u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8;
+	u8 specifier_id_lo = specifier_id & 0xff;
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("Send GASP: channel = %d, length = %d", channel, length);
+#endif
+
+	length += 8;
+
+	packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
+	if (!packet)
+		return -ENOMEM;
+
+	if (length % 4) {
+		packet->data[length / 4] = 0;
+	}
+
+	packet->host = host;
+	fill_async_stream_packet(packet, length, channel, 3, 0);
+        
+	packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi);
+	packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff));
+
+	memcpy(&(packet->data[2]), buffer, length - 4);
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size);
+	HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size);
+
+	for(i=0; i<(packet->data_size/4); i++)
+		HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i]));
+#endif
+
+	packet->generation = generation;
+
+	packet->no_waiter = 1;
+
+	if (!hpsb_send_packet(packet)) {
+        free_hpsb_packet(packet);
+		retval = -EINVAL;
+	}
+
+        return retval;
+}
diff -urN linux-2.4.21-pre7/drivers/ieee1394/ieee1394_transactions.h linux-2.4.21-rc1/drivers/ieee1394/ieee1394_transactions.h
--- linux-2.4.21-pre7/drivers/ieee1394/ieee1394_transactions.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/ieee1394_transactions.h	2003-04-21 11:48:41.000000000 -0700
@@ -75,6 +75,11 @@
 	       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);
+int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+		u64 addr, int extcode, octlet_t *data, octlet_t arg);
+int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
+		   quadlet_t *buffer, size_t length, u32 specifier_id,
+		   unsigned int version);
 
 /* 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.4.21-pre7/drivers/ieee1394/ieee1394_types.h linux-2.4.21-rc1/drivers/ieee1394/ieee1394_types.h
--- linux-2.4.21-pre7/drivers/ieee1394/ieee1394_types.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/ieee1394_types.h	2003-04-21 11:48:41.000000000 -0700
@@ -32,6 +32,9 @@
 #define LOCAL_BUS 0xffc0
 #define ALL_NODES 0x003f
 
+#define NODEID_TO_BUS(nodeid)	((nodeid & BUS_MASK) >> BUS_SHIFT)
+#define NODEID_TO_NODE(nodeid)	(nodeid & NODE_MASK)
+
 /* Can be used to consistently print a node/bus ID. */
 #define NODE_BUS_FMT    "%02d:%04d"
 #define NODE_BUS_ARGS(nodeid) \
diff -urN linux-2.4.21-pre7/drivers/ieee1394/iso.c linux-2.4.21-rc1/drivers/ieee1394/iso.c
--- linux-2.4.21-pre7/drivers/ieee1394/iso.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/iso.c	2003-04-21 11:48:41.000000000 -0700
@@ -14,7 +14,7 @@
 
 void hpsb_iso_stop(struct hpsb_iso *iso)
 {
-	if(!iso->flags & HPSB_ISO_DRIVER_STARTED)
+	if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
 		return;
 
 	iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
diff -urN linux-2.4.21-pre7/drivers/ieee1394/nodemgr.c linux-2.4.21-rc1/drivers/ieee1394/nodemgr.c
--- linux-2.4.21-pre7/drivers/ieee1394/nodemgr.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.21-rc1/drivers/ieee1394/nodemgr.c	2003-04-21 11:48:41.000000000 -0700
@@ -92,7 +92,7 @@
 
 	list_for_each(lh, &node_list) {
 		struct list_head *l;
-		int ud_count = 0;
+		int ud_count = 0, lud_count = 0;
 
 		ne = list_entry(lh, struct node_entry, list);
 		if (!ne)
@@ -135,7 +135,10 @@
 			struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
 			int printed = 0; // small hack
 
-			PUTF("  Unit Directory %d:\n", ud_count++);
+			if (ud->parent == NULL)
+				PUTF("  Unit Directory %d:\n", lud_count++);
+			else
+				PUTF("  Logical 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);
@@ -282,6 +285,10 @@
 	
 	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
 		return NULL;
+
+	if (CONFIG_ROM_BUS_INFO_LENGTH(quad) == 1)  /* minimal config rom */
+		return NULL;
+
 	address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
 
 	if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
@@ -312,6 +319,7 @@
 	}
 	ne = kmalloc(total_size, SLAB_ATOMIC);
 	if (ne != NULL) {
+		memset(ne, 0, total_size);
 		if (size != 0) {
 			ne->vendor_name
 				= (const char *) &(ne->quadlets[2]);
@@ -432,7 +440,7 @@
 			   store?  Only count immediate values and
 			   CSR offsets for now.  */
 			code &= CONFIG_ROM_KEY_TYPE_MASK;
-			if ((code & 0x80) == 0)
+			if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0)
 				count++;
 			break;
 		}
@@ -480,19 +488,23 @@
  * software_version entries, in order to get driver autoloading working.
  */
 
-static void nodemgr_process_unit_directory(struct node_entry *ne, 
-					   octlet_t address)
+static struct unit_directory * nodemgr_process_unit_directory
+	(struct node_entry *ne, octlet_t address, struct unit_directory *parent)
 {
 	struct unit_directory *ud;
 	quadlet_t quad;
 	quadlet_t *infop;
 	int length;
-
+	struct unit_directory *ud_temp = NULL;
+	
 	if (!(ud = nodemgr_scan_unit_directory(ne, address)))
 		goto unit_directory_error;
 
 	ud->ne = ne;
 	ud->address = address;
+	
+	if (parent != NULL)
+		ud->parent = parent;
 
 	if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
 				 address, &quad))
@@ -568,12 +580,48 @@
 			/* TODO: read strings... icons? */
 			break;
 
+		case CONFIG_ROM_LOGICAL_UNIT_DIRECTORY:
+		{
+			ud_temp = nodemgr_process_unit_directory(ne, address + value * 4, ud);
+			/* inherit unspecified values */
+			if (ud_temp != NULL )
+			{
+				ud->n_children++;
+				if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) && 
+					!(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_VENDOR_ID;
+					ud_temp->vendor_id = ud->vendor_id;
+				}
+				if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
+					!(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_MODEL_ID;
+					ud_temp->model_id = ud->model_id;
+				}
+				if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
+					!(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;
+					ud_temp->specifier_id = ud->specifier_id;
+				}
+				if ((ud->flags & UNIT_DIRECTORY_VERSION) && 
+					!(ud_temp->flags & UNIT_DIRECTORY_VERSION))
+				{
+					ud_temp->flags |=  UNIT_DIRECTORY_VERSION;
+					ud_temp->version = ud->version;
+				}
+			}
+			
+		}
+			break;
+
 		default:
 			/* Which types of quadlets do we want to
 			   store?  Only count immediate values and
 			   CSR offsets for now.  */
 			code &= CONFIG_ROM_KEY_TYPE_MASK;
-			if ((code & 0x80) == 0)
+			if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0)
 				*infop = quad;
 			break;
 		}
@@ -582,11 +630,12 @@
 	list_add_tail(&ud->node_list, &ne->unit_directories);
 	list_add_tail(&ud->driver_list, &unit_directory_list);
 
-	return;
+	return ud;
 
 unit_directory_error:	
 	if (ud != NULL)
 		kfree(ud);
+	return NULL;
 }
 
 static void dump_directories (struct node_entry *ne)
@@ -669,7 +718,7 @@
 			break;
 
 		case CONFIG_ROM_UNIT_DIRECTORY:
-			nodemgr_process_unit_directory(ne, address + value * 4);
+			nodemgr_process_unit_directory(ne, address + value * 4, NULL);
 			break;			
 
 		case CONFIG_ROM_DESCRIPTOR_LEAF:
@@ -728,7 +777,7 @@
 	envp[i++] = scratch;
 	scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
 	envp[i++] = scratch;
-	scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->ne->vendor_id) + 1;
+	scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->vendor_id) + 1;
 	envp[i++] = scratch;
 	scratch += sprintf(scratch, "GUID=%016Lx", (long long unsigned)ud->ne->guid) + 1;
 	envp[i++] = scratch;
@@ -765,15 +814,13 @@
 					 struct hpsb_protocol_driver *driver)
 {
 	ud->driver = driver;
-	list_del(&ud->driver_list);
-	list_add_tail(&ud->driver_list, &driver->unit_directories);
+	list_move_tail(&ud->driver_list, &driver->unit_directories);
 }
 
 static void nodemgr_release_unit_directory(struct unit_directory *ud)
 {
 	ud->driver = NULL;
-	list_del(&ud->driver_list);
-	list_add_tail(&ud->driver_list, &unit_directory_list);
+	list_move_tail(&ud->driver_list, &unit_directory_list);
 }
 
 void hpsb_release_unit_directory(struct unit_directory *ud)
@@ -785,18 +832,21 @@
 
 static void nodemgr_free_unit_directories(struct node_entry *ne)
 {
-	struct list_head *lh;
+	struct list_head *lh, *next;
 	struct unit_directory *ud;
 
-	lh = ne->unit_directories.next;
-	while (lh != &ne->unit_directories) {
+	list_for_each_safe(lh, next, &ne->unit_directories) {
 		ud = list_entry(lh, struct unit_directory, node_list);
-		lh = lh->next;
+
 		if (ud->driver && ud->driver->disconnect)
 			ud->driver->disconnect(ud);
+
 		nodemgr_release_unit_directory(ud);
 		nodemgr_call_policy("remove", ud);
+
 		list_del(&ud->driver_list);
+		list_del(&ud->node_list);
+
 		kfree(ud);
 	}
 }
@@ -820,8 +870,9 @@
 		    id->specifier_id != ud->specifier_id)
 			continue;
 
+		/* software version does a bitwise comparison instead of equality */
 		if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
-		    id->version != ud->version)
+		    !(id->version & ud->version))
 			continue;
 
 		return id;
@@ -860,7 +911,7 @@
 	list_for_each(lh, &ne->unit_directories) {
 		ud = list_entry(lh, struct unit_directory, node_list);
 		driver = nodemgr_find_driver(ud);
-		if (driver != NULL && driver->probe(ud) == 0)
+		if (driver && (!driver->probe || driver->probe(ud) == 0))
 			nodemgr_claim_unit_directory(ud, driver);
 		nodemgr_call_policy("add", ud);
 	}
@@ -869,7 +920,7 @@
 int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
 {
 	struct unit_directory *ud;
-	struct list_head *lh;
+	struct list_head *lh, *next;
 
 	if (down_interruptible(&nodemgr_serialize))
 		return -EINTR;
@@ -877,11 +928,12 @@
 	list_add_tail(&driver->list, &driver_list);
 
 	INIT_LIST_HEAD(&driver->unit_directories);
-	lh = unit_directory_list.next;
-	while (lh != &unit_directory_list) {
+
+	list_for_each_safe (lh, next, &unit_directory_list) {
 		ud = list_entry(lh, struct unit_directory, driver_list);
-		lh = lh->next;
-		if (nodemgr_match_driver(driver, ud) && driver->probe(ud) == 0)
+
+		if (nodemgr_match_driver(driver, ud) &&
+		    (!driver->probe || driver->probe(ud) == 0))
 			nodemgr_claim_unit_directory(ud, driver);
 	}
 
@@ -890,6 +942,18 @@
 	/*
 	 * Right now registration always succeeds, but maybe we should
 	 * detect clashes in protocols handled by other drivers.
+     * DRD> No because multiple drivers are needed to handle certain devices.
+     * For example, a DV camera is an IEC 61883 device (dv1394) and AV/C (raw1394).
+     * This will become less an issue with libiec61883 using raw1394.
+     *
+     * BenC: But can we handle this with an ALLOW_SHARED flag for a
+     * protocol? When we get an SBP-3 driver, it will be nice if they were
+     * mutually exclusive, since SBP-3 can handle SBP-2 protocol.
+     *
+     * Not to mention that we currently do not seem to support multiple
+     * drivers claiming the same unitdirectory. If we implement both of
+     * those, then we'll need to keep probing when a driver claims a
+     * unitdirectory, but is sharable.
 	 */
 
 	return 0;
@@ -897,18 +961,19 @@
 
 void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
 {
-	struct list_head *lh;
+	struct list_head *lh, *next;
 	struct unit_directory *ud;
 
 	down(&nodemgr_serialize);
 
 	list_del(&driver->list);
-	lh = driver->unit_directories.next;
-	while (lh != &driver->unit_directories) {
+
+	list_for_each_safe (lh, next, &driver->unit_directories) {
 		ud = list_entry(lh, struct unit_directory, driver_list);
-		lh = lh->next;
+
 		if (ud->driver && ud->driver->disconnect)
 			ud->driver->disconnect(ud);
+
 		nodemgr_release_unit_directory(ud);
 	}
 
@@ -976,7 +1041,7 @@
 
 	list_for_each (lh, &ne->unit_directories) {
 		ud = list_entry (lh, struct unit_directory, node_list);
-		if (ud->driver != NULL && ud->driver->update != NULL)
+		if (ud->driver && ud->driver->update != NULL)
 			ud->driver->update(ud);
 	}
 }
@@ -1022,6 +1087,13 @@
 	header_size = buffer[0] >> 24;
 	addr += 4;
 
+	if (header_size == 1) {
+		HPSB_INFO("Node " NODE_BUS_FMT " has a minimal ROM.  "
+			  "Vendor is %08x",
+			  NODE_BUS_ARGS(nodeid), buffer[0] & 0x00ffffff);
+		return -1;
+	}
+
 	if (header_size < 4) {
 		HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM "
 			  "format (%d quads), cannot parse",
@@ -1120,26 +1192,11 @@
 	return;
 }
 
-static void nodemgr_node_probe(struct hpsb_host *host)
+static void nodemgr_node_probe(struct hpsb_host *host, int generation)
 {
 	int count;
 	struct selfid *sid = (struct selfid *)host->topology_map;
 	nodeid_t nodeid = LOCAL_BUS;
-	unsigned int generation;
-
-	/* Pause for 1/4 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/4))
-		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 (count = host->selfid_count; count; count--, sid++) {
@@ -1157,15 +1214,61 @@
 	/* 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. */
+	 * 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;
 }
 
+/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other
+ * nodes of the broadcast channel.  (Really we're only setting the validity
+ * bit). */
+static void nodemgr_do_irm_duties(struct hpsb_host *host)
+{
+	quadlet_t bc;
+        
+	if (!host->is_irm)
+		return;
+
+	host->csr.broadcast_channel |= 0x40000000;  /* set validity bit */
+
+	bc = cpu_to_be32(host->csr.broadcast_channel);
+
+	hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host),
+		   (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
+		   &bc,
+		   sizeof(quadlet_t));
+}
+
+/* We need to ensure that if we are not the IRM, that the IRM node is capable of
+ * everything we can do, otherwise issue a bus reset and try to become the IRM
+ * ourselves. */
+static int nodemgr_check_root_capability(struct hpsb_host *host)
+{
+	quadlet_t bc;
+	int status;
+
+	if (host->is_irm)
+		return 1;
+
+	status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
+			   get_hpsb_generation(host),
+			   (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
+			   &bc, sizeof(quadlet_t));
+
+	if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
+		/* The root node does not have a valid BROADCAST_CHANNEL
+		 * register and we do, so reset the bus with force_root set */
+		HPSB_INFO("Remote root is not IRM capable, resetting...");
+		hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
+		return 0;
+	}
+	return 1;
+}
+
 static int nodemgr_host_thread(void *__hi)
 {
 	struct host_info *hi = (struct host_info *)__hi;
@@ -1179,9 +1282,41 @@
 	 * happens when we get a bus reset. */
 	while (!down_interruptible(&hi->reset_sem) &&
 	       !down_interruptible(&nodemgr_serialize)) {
-		nodemgr_node_probe(hi->host);
+		unsigned int generation;
+		int i;
+
+		/* Pause for 1/4 second, to make sure things settle down. */
+		for (i = HZ/4; i > 0; i-= HZ/16) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (schedule_timeout(HZ/16))
+				goto caught_signal;
+
+			/* 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(hi->host);
+
+			/* If we get a reset before we are done waiting, then
+			 * start the the waiting over again */
+			while (!down_trylock(&hi->reset_sem))
+				i = HZ/4;
+		}
+
+		if (!nodemgr_check_root_capability(hi->host)) {
+			/* Do nothing, we are resetting */
+			up(&nodemgr_serialize);
+			continue;
+		}
+
+		nodemgr_node_probe(hi->host, generation);
+		nodemgr_do_irm_duties(hi->host);
+
 		up(&nodemgr_serialize);
 	}
+
+ caught_signal:
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 	HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name);
 #endif
@@ -1282,6 +1417,8 @@
 	init_completion(&hi->exited);
         sema_init(&hi->reset_sem, 0);
 
+	spin_lock_irqsave (&host_info_lock, flags);
+
 	hi->pid = kernel_thread(nodemgr_host_thread, hi,
 				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	
@@ -1289,11 +1426,12 @@
 		HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s",
 			  host->driver->name);
 		kfree(hi);
+		spin_unlock_irqrestore (&host_info_lock, flags);
 		return;
 	}
 
-	spin_lock_irqsave (&host_info_lock, flags);
-	list_add_tail (&hi->list, &host_info_list);
+	list_add_tail(&hi->list, &host_info_list);
+
 	spin_unlock_irqrestore (&host_info_lock, flags);
 
 	return;
diff -urN linux-2.4.21-pre7/drivers/ieee1394/nodemgr.h linux-2.4.21-rc1/drivers/ieee1394/nodemgr.h
--- linux-2.4.21-pre7/drivers/ieee1394/nodemgr.h	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/nodemgr.h	2003-04-21 11:48:41.000000000 -0700
@@ -53,6 +53,7 @@
 #define CONFIG_ROM_MODEL_ID			0x17
 #define CONFIG_ROM_NODE_CAPABILITES		0x0C
 #define CONFIG_ROM_UNIT_DIRECTORY		0xd1
+#define CONFIG_ROM_LOGICAL_UNIT_DIRECTORY	0xd4
 #define CONFIG_ROM_SPECIFIER_ID			0x12 
 #define CONFIG_ROM_UNIT_SW_VERSION		0x13
 #define CONFIG_ROM_DESCRIPTOR_LEAF		0x81
@@ -114,6 +115,10 @@
 
 	/* For linking directories belonging to a node */
 	struct list_head node_list;
+		
+	/* for tracking unit versus logical unit */
+	struct unit_directory *parent;
+	int n_children;
 
 	int count;		/* Number of quadlets */
 	quadlet_t quadlets[0];
diff -urN linux-2.4.21-pre7/drivers/ieee1394/ohci1394.c linux-2.4.21-rc1/drivers/ieee1394/ohci1394.c
--- linux-2.4.21-pre7/drivers/ieee1394/ohci1394.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/ohci1394.c	2003-04-21 11:48:41.000000000 -0700
@@ -30,8 +30,10 @@
  * . DMA mmap for iso receive
  * . Config ROM generation
  *
+ * Things implemented, but still in test phase:
+ * . Async Stream Packets Transmit (Receive done via Iso interface)
+ *
  * Things not implemented:
- * . Async Stream Packets
  * . DMA error recovery
  *
  * Known bugs:
@@ -76,6 +78,10 @@
  *
  * Dan Maas <dmaas@maasdigital.com>
  *  . New isochronous API (rawiso)
+ *
+ * Nandu Santhi <contactnandu@users.sourceforge.net>
+ *  . Added support for nVidia nForce2 onboard Firewire chipset
+ * 
  */
 
 #include <linux/config.h>
@@ -141,7 +147,7 @@
 #define OHCI_DMA_FREE(fmt, args...) \
 	HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
 		--global_outstanding_dmas, ## args)
-u32 global_outstanding_dmas = 0;
+static int global_outstanding_dmas = 0;
 #else
 #define OHCI_DMA_ALLOC(fmt, args...)
 #define OHCI_DMA_FREE(fmt, args...)
@@ -156,7 +162,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 810 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 866 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -348,18 +354,16 @@
 
 	DBGMSG(ohci->id, "SelfID complete");
 
-	hpsb_selfid_complete(host, phyid, isroot);
-
 	return;
 }
 
 static void ohci_soft_reset(struct ti_ohci *ohci) {
 	int i;
 
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
   
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		if (reg_read(ohci, OHCI1394_HCControlSet) & 0x00010000)
+		if (!reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset)
 			break;
 		mdelay(1);
 	}
@@ -516,7 +520,7 @@
 	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
 
 	/* Enable posted writes */
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00040000);
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
 
 	/* Clear link control register */
 	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
@@ -579,7 +583,7 @@
 		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
 
 	/* We don't want hardware swapping */
-	reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
+	reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
 
 	/* Enable interrupts */
 	reg_write(ohci, OHCI1394_IntMaskSet,
@@ -596,7 +600,7 @@
 		  OHCI1394_cycleInconsistent);
 
 	/* Enable link */
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
 
 	buf = reg_read(ohci, OHCI1394_Version);
 	PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  "
@@ -892,12 +896,61 @@
 	struct ti_ohci *ohci = host->hostdata;
 	int retval = 0;
 	unsigned long flags;
+	int phy_reg;
 
 	switch (cmd) {
 	case RESET_BUS:
 		DBGMSG(ohci->id, "devctl: Bus reset requested%s",
 		       attempt_root ? " and attempting to become root" : "");
-		set_phy_reg_mask (ohci, 1, 0x40 | (attempt_root ? 0x80 : 0));
+		switch (arg) {
+		case SHORT_RESET:
+			phy_reg = get_phy_reg(ohci, 5);
+			phy_reg |= 0x40;
+			set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
+			break;
+		case LONG_RESET:
+			phy_reg = get_phy_reg(ohci, 1);
+			phy_reg |= 0x40 | (attempt_root ? 0x80 : 0);
+			set_phy_reg(ohci, 1, phy_reg); /* set IBR */
+			break;
+		case SHORT_RESET_NO_FORCE_ROOT:
+			phy_reg = get_phy_reg(ohci, 1);
+			if (phy_reg & 0x80) {
+				phy_reg &= ~0x80 | (attempt_root ? 0x80 : 0);
+				set_phy_reg(ohci, 1, phy_reg); /* clear RHB */
+			}
+
+			phy_reg = get_phy_reg(ohci, 5);
+			phy_reg |= 0x40;
+			set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
+			break;
+		case LONG_RESET_NO_FORCE_ROOT:
+			phy_reg = get_phy_reg(ohci, 1);
+			phy_reg &= ~0x80;
+			phy_reg |= 0x40 | (attempt_root ? 0x80 : 0);
+			set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */
+			break;
+		case SHORT_RESET_FORCE_ROOT:
+			phy_reg = get_phy_reg(ohci, 1);
+			if (!(phy_reg & 0x80)) {
+				phy_reg |= 0x80;
+				set_phy_reg(ohci, 1, phy_reg); /* set RHB */
+			}
+
+			phy_reg = get_phy_reg(ohci, 5);
+			phy_reg |= 0x40;
+			set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
+			break;
+		case LONG_RESET_FORCE_ROOT:
+			phy_reg = get_phy_reg(ohci, 1);
+			phy_reg |= 0xc0;
+			set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */
+			break;
+		default:
+			retval = -1;
+		}
+
+
 		break;
 
 	case GET_CYCLE_COUNTER:
@@ -956,8 +1009,24 @@
 			return -EFAULT;
 		}
 
+		/* activate the legacy IR context */
+		if (ohci->ir_legacy_context.ohci == NULL) {
+			if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
+					      DMA_CTX_ISO, 0, IR_NUM_DESC,
+					      IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
+					      OHCI1394_IsoRcvContextBase) < 0) {
+				PRINT(KERN_ERR, ohci->id, "%s: failed to allocate an IR context",
+				      __FUNCTION__);
+				return -ENOMEM;
+			}
+			ohci->ir_legacy_channels = 0;
+			initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
+
+			DBGMSG(ohci->id, "ISO receive legacy context activated");
+		}
+
 		mask = (u64)0x1<<arg;
-		
+
                 spin_lock_irqsave(&ohci->IR_channel_lock, flags);
 
 		if (ohci->ISO_channel_usage & mask) {
@@ -968,23 +1037,6 @@
 			return -EFAULT;
 		}
 
-		/* activate the legacy IR context */
-		if(ohci->ir_legacy_context.ohci == NULL) {
-			if(alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
-					     DMA_CTX_ISO, 0, IR_NUM_DESC,
-					     IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-					     OHCI1394_IsoRcvContextBase) < 0) {
-				PRINT(KERN_ERR, ohci->id,
-				      "%s: failed to allocate an IR context", 
-				      __FUNCTION__);
-				return -ENOMEM;
-			}
-			ohci->ir_legacy_channels = 0;
-			initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
-
-			DBGMSG(ohci->id, "ISO receive legacy context activated");
-		}
-
 		ohci->ISO_channel_usage |= mask;
 		ohci->ir_legacy_channels |= mask;
 
@@ -1156,10 +1208,11 @@
 		/* iso->irq_interval is in packets - translate that to blocks */
 		/* (err, sort of... 1 is always the safest value) */
 		recv->block_irq_interval = iso->irq_interval / recv->nblocks;
+		if(recv->block_irq_interval*4 > recv->nblocks)
+			recv->block_irq_interval = recv->nblocks/4;
 		if(recv->block_irq_interval < 1)
 			recv->block_irq_interval = 1;
-		else if(recv->block_irq_interval*4 > recv->nblocks)
-			recv->block_irq_interval = recv->nblocks/4;
+
 	} else {
 		int max_packet_size;
 
@@ -2253,26 +2306,39 @@
 	}
 
 	if (event & OHCI1394_busReset) {
-		int loops = 0;
-
 		/* The busReset event bit can't be cleared during the
 		 * selfID phase, so we disable busReset interrupts, to
 		 * avoid burying the cpu in interrupt requests. */
 		spin_lock_irqsave(&ohci->event_lock, flags);
-  		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-		udelay(10);
-		while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
-			if (loops++ > 10000) {
-				hpsb_reset_bus(host, 1);
-				loops = 0;
-				DBGMSG(ohci->id, "Out of control loop, resetting");
-			}
+		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
+
+		if (ohci->check_busreset) {
+			int loop_count = 0;
 
-			reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-			spin_unlock_irqrestore(&ohci->event_lock, flags);
 			udelay(10);
-			spin_lock_irqsave(&ohci->event_lock, flags);
-  		}
+
+			while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
+				reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+
+				spin_unlock_irqrestore(&ohci->event_lock, flags);
+				udelay(10);
+				spin_lock_irqsave(&ohci->event_lock, flags);
+
+				/* The loop counter check is to prevent the driver
+				 * from remaining in this state forever. For the
+				 * initial bus reset, the loop continues for ever
+				 * and the system hangs, until some device is plugged-in
+				 * or out manually into a port! The forced reset seems
+				 * to solve this problem. This mainly effects nForce2. */
+				if (loop_count > 10000) {
+					ohci_devctl(host, RESET_BUS, LONG_RESET);
+					DBGMSG(ohci->id, "Detected bus-reset loop. Forced a bus reset!");
+					loop_count = 0;
+				}
+
+				loop_count++;
+			}
+		}
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
 
 		if (!host->in_bus_reset) {
@@ -2412,6 +2478,8 @@
 	if (event)
 		PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x",
 		      event);
+
+	return;
 }
 
 /* Put the buffer back into the dma context */
@@ -3250,6 +3318,18 @@
 		ohci->selfid_swap = 1;
 #endif
 
+#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e
+#endif
+
+	/* These chipsets require a bit of extra care when checking after
+	 * a busreset.  */
+	if ((dev->vendor == PCI_VENDOR_ID_APPLE &&
+	     dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) ||
+	    (dev->vendor ==  PCI_VENDOR_ID_NVIDIA &&
+	     dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW))
+		ohci->check_busreset = 1;
+
 	/* We hardwire the MMIO length, since some CardBus adaptors
 	 * fail to report the right length.  Anyway, the ohci spec
 	 * clearly says it's 2kb, so this shouldn't be a problem. */ 
@@ -3336,7 +3416,7 @@
 	 * accessing registers in the SClk domain without LPS enabled
 	 * will lock up the machine.  Wait 50msec to make sure we have
 	 * full link enabled.  */
-	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
 	mdelay(50);
 
 	/* Determine the number of available IR and IT contexts. */
diff -urN linux-2.4.21-pre7/drivers/ieee1394/ohci1394.h linux-2.4.21-rc1/drivers/ieee1394/ohci1394.h
--- linux-2.4.21-pre7/drivers/ieee1394/ohci1394.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/ohci1394.h	2003-04-21 11:48:41.000000000 -0700
@@ -233,6 +233,9 @@
 	unsigned int selfid_swap:1;
 	/* Some Apple chipset seem to swap incoming headers for us */
 	unsigned int no_swap_incoming:1;
+
+	/* Force extra paranoia checking on bus-reset handling */
+	unsigned int check_busreset:1;
 };
 
 static inline int cross_bound(unsigned long addr, unsigned int size)
@@ -288,6 +291,13 @@
 #define OHCI1394_VendorID                     0x040
 #define OHCI1394_HCControlSet                 0x050
 #define OHCI1394_HCControlClear               0x054
+#define  OHCI1394_HCControl_noByteSwap		0x40000000
+#define  OHCI1394_HCControl_programPhyEnable	0x00800000
+#define  OHCI1394_HCControl_aPhyEnhanceEnable	0x00400000
+#define  OHCI1394_HCControl_LPS			0x00080000
+#define  OHCI1394_HCControl_postedWriteEnable	0x00040000
+#define  OHCI1394_HCControl_linkEnable		0x00020000
+#define  OHCI1394_HCControl_softReset		0x00010000
 #define OHCI1394_SelfIDBuffer                 0x064
 #define OHCI1394_SelfIDCount                  0x068
 #define OHCI1394_IRMultiChanMaskHiSet         0x070
diff -urN linux-2.4.21-pre7/drivers/ieee1394/raw1394.c linux-2.4.21-rc1/drivers/ieee1394/raw1394.c
--- linux-2.4.21-pre7/drivers/ieee1394/raw1394.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/raw1394.c	2003-04-21 11:48:41.000000000 -0700
@@ -48,6 +48,7 @@
 #include "highlevel.h"
 #include "iso.h"
 #include "ieee1394_transactions.h"
+#include "ieee1394_hotplug.h"
 #include "raw1394.h"
 #include "raw1394-private.h"
 
@@ -2484,6 +2485,36 @@
         return 0;
 }
 
+/*** HOTPLUG STUFF **********************************************************/
+/*
+ * Export information about protocols/devices supported by this driver.
+ */
+static struct ieee1394_device_id raw1394_id_table[] = {
+	{
+		.match_flags =IEEE1394_MATCH_SPECIFIER_ID |
+		              IEEE1394_MATCH_VERSION,
+		.specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
+		.version =    AVC_SW_VERSION_ENTRY & 0xffffff
+	},
+	{
+		.match_flags =IEEE1394_MATCH_SPECIFIER_ID |
+		              IEEE1394_MATCH_VERSION,
+		.specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
+		.version =    CAMERA_SW_VERSION_ENTRY & 0xffffff
+	},
+	{ }
+};
+
+static struct hpsb_protocol_driver raw1394_driver = {
+	.name =		"raw1394 Driver",
+	.id_table = 	raw1394_id_table,
+};
+
+MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
+
+
+/******************************************************************************/
+
 static struct hpsb_highlevel_ops hl_ops = {
         .add_host =    add_host,
         .remove_host = remove_host,
@@ -2525,12 +2556,17 @@
                 hpsb_unregister_highlevel(hl_handle);
                 return -EBUSY;
         }
+
         printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
+
+	hpsb_register_protocol(&raw1394_driver);
+
         return 0;
 }
 
 static void __exit cleanup_raw1394(void)
 {
+	hpsb_unregister_protocol(&raw1394_driver);
         ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
         devfs_unregister(devfs_handle);
         hpsb_unregister_highlevel(hl_handle);
diff -urN linux-2.4.21-pre7/drivers/ieee1394/sbp2.c linux-2.4.21-rc1/drivers/ieee1394/sbp2.c
--- linux-2.4.21-pre7/drivers/ieee1394/sbp2.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/sbp2.c	2003-04-21 11:48:41.000000000 -0700
@@ -353,7 +353,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 792 $ James Goodwin <jamesg@filanet.com>";
+	"$Rev: 878 $ James Goodwin <jamesg@filanet.com>";
 
 /*
  * Module load parameter definitions
@@ -548,7 +548,7 @@
 static struct hpsb_protocol_driver sbp2_driver = {
 	.name =		"SBP2 Driver",
 	.id_table = 	sbp2_id_table,
-	.probe = 		sbp2_probe,
+	.probe = 	sbp2_probe,
 	.disconnect = 	sbp2_disconnect,
 	.update = 	sbp2_update
 };
@@ -846,7 +846,7 @@
 	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	for (i = 0; i < scsi_id->sbp2_total_command_orbs; i++) {
 		command = (struct sbp2_command_info *)
-		    kmalloc(sizeof(struct sbp2_command_info), GFP_KERNEL);
+		    kmalloc(sizeof(struct sbp2_command_info), GFP_ATOMIC);
 		if (!command) {
 			spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 			return(-ENOMEM);
@@ -1312,12 +1312,44 @@
 		goto alloc_fail;
 	SBP2_DMA_ALLOC("consistent DMA region for logout ORB");
 
+	/* Query logins ORB DMA */
+	scsi_id->query_logins_orb =
+		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb),
+				     &scsi_id->query_logins_orb_dma);
+	if (!scsi_id->query_logins_orb)
+		goto alloc_fail;
+	SBP2_DMA_ALLOC("consistent DMA region for query logins ORB");
+
+	/* Query logins response DMA */
+	scsi_id->query_logins_response =
+		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response),
+				     &scsi_id->query_logins_response_dma);
+	if (!scsi_id->query_logins_response)
+		goto alloc_fail;
+	SBP2_DMA_ALLOC("consistent DMA region for query logins response");
+
 	/* Login ORB DMA */
 	scsi_id->login_orb =
 		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb),
 				     &scsi_id->login_orb_dma);
 	if (scsi_id->login_orb == NULL) {
 alloc_fail:
+		if (scsi_id->query_logins_response) {
+			pci_free_consistent(hi->host->pdev,
+					sizeof(struct sbp2_query_logins_response),
+					scsi_id->query_logins_response,
+					scsi_id->query_logins_response_dma);
+			SBP2_DMA_FREE("query logins response DMA");
+		}
+
+		if (scsi_id->query_logins_orb) {
+			pci_free_consistent(hi->host->pdev,
+					sizeof(struct sbp2_query_logins_orb),
+					scsi_id->query_logins_orb,
+					scsi_id->query_logins_orb_dma);
+			SBP2_DMA_FREE("query logins ORB DMA");
+		}
+
 		if (scsi_id->logout_orb) {
 			pci_free_consistent(hi->host->pdev,
 					sizeof(struct sbp2_logout_orb),
@@ -1487,10 +1519,26 @@
 		pci_free_consistent(hi->host->pdev,
 				    sizeof(struct sbp2_logout_orb),
 				    scsi_id->logout_orb,
-				    scsi_id->reconnect_orb_dma);
+				    scsi_id->logout_orb_dma);
 		SBP2_DMA_FREE("single logout orb");
 	}
 
+	if (scsi_id->query_logins_orb) {
+		pci_free_consistent(hi->host->pdev,
+				    sizeof(struct sbp2_query_logins_orb),
+				    scsi_id->query_logins_orb,
+				    scsi_id->query_logins_orb_dma);
+		SBP2_DMA_FREE("single query logins orb");
+	}
+
+	if (scsi_id->query_logins_response) {
+		pci_free_consistent(hi->host->pdev,
+				    sizeof(struct sbp2_query_logins_response),
+				    scsi_id->query_logins_response,
+				    scsi_id->query_logins_response_dma);
+		SBP2_DMA_FREE("single query logins data");
+	}
+
 	SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id);
 	hi->scsi_id[scsi_id->id] = NULL;
 	kfree(scsi_id);
@@ -1546,6 +1594,99 @@
 }
 
 /*
+ * This function queries the device for the maximum concurrent logins it
+ * supports.
+ */
+static int sbp2_query_logins(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
+{
+	quadlet_t data[2];
+	int max_logins;
+	int active_logins;
+
+	SBP2_DEBUG("sbp2_query_logins");
+
+	scsi_id->query_logins_orb->reserved1 = 0x0;
+	scsi_id->query_logins_orb->reserved2 = 0x0;
+
+	scsi_id->query_logins_orb->query_response_lo = scsi_id->query_logins_response_dma;
+	scsi_id->query_logins_orb->query_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
+	SBP2_DEBUG("sbp2_query_logins: query_response_hi/lo initialized");
+
+	scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(QUERY_LOGINS_REQUEST);
+	scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
+	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
+		scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
+	}
+	SBP2_DEBUG("sbp2_query_logins: lun_misc initialized");
+
+	scsi_id->query_logins_orb->reserved_resp_length =
+		ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response));
+	SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized");
+
+	scsi_id->query_logins_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 
+						    SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
+	scsi_id->query_logins_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
+						     SBP2_STATUS_FIFO_ADDRESS_HI);
+	SBP2_DEBUG("sbp2_query_logins: status FIFO initialized");
+
+	sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb));
+
+	SBP2_DEBUG("sbp2_query_logins: orb byte-swapped");
+
+	memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
+	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
+
+	SBP2_DEBUG("sbp2_query_logins: query_logins_response/status FIFO memset");
+
+	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
+	data[1] = scsi_id->query_logins_orb_dma;
+	sbp2util_cpu_to_be32_buffer(data, 8);
+
+	atomic_set(&scsi_id->sbp2_login_complete, 0);
+
+	SBP2_DEBUG("sbp2_query_logins: prepared to write");
+	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
+	SBP2_DEBUG("sbp2_query_logins: written");
+
+	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
+		SBP2_ERR("Error querying logins to SBP-2 device - timed out");
+		return(-EIO);
+	}
+
+	if (scsi_id->status_block.ORB_offset_lo != scsi_id->query_logins_orb_dma) {
+		SBP2_ERR("Error querying logins to SBP-2 device - timed out");
+		return(-EIO);
+	}
+
+	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
+	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
+	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
+
+		SBP2_ERR("Error querying logins to SBP-2 device - timed out");
+		return(-EIO);
+	}
+
+	sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_response, sizeof(struct sbp2_query_logins_response));
+
+	SBP2_DEBUG("length_max_logins = %x",
+		   (unsigned int)scsi_id->query_logins_response->length_max_logins);
+
+	SBP2_INFO("Query logins to SBP-2 device successful");
+
+	max_logins = RESPONSE_GET_MAX_LOGINS(scsi_id->query_logins_response->length_max_logins);
+	SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
+
+	active_logins = RESPONSE_GET_ACTIVE_LOGINS(scsi_id->query_logins_response->length_max_logins);
+	SBP2_INFO("Number of active logins: %d", active_logins);
+
+	if (active_logins >= max_logins) {
+		return(-EIO);
+	}
+
+	return 0;
+}
+
+/*
  * This function is called in order to login to a particular SBP-2 device,
  * after a bus reset.
  */
@@ -1560,6 +1701,13 @@
 		return(-EIO);
 	}
 
+	if (!sbp2_exclusive_login) {
+		if (sbp2_query_logins(hi, scsi_id)) {
+			SBP2_ERR("Device does not support any more concurrent logins");
+			return(-EIO);
+		}
+	}
+
 	/* Set-up login ORB, assume no password */
 	scsi_id->login_orb->password_hi = 0; 
 	scsi_id->login_orb->password_lo = 0;
@@ -1840,28 +1988,11 @@
 	return(0);
 }
 
-/*
- * This function is called to parse sbp2 device's config rom unit
- * directory. Used to determine things like sbp2 management agent offset,
- * and command set used (SCSI or RBC). 
- */
-static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
+static void sbp2_parse_logical_unit_directory
+	(struct scsi_id_instance_data *scsi_id, struct unit_directory *ud)
 {
-	struct unit_directory *ud;
 	int i;
-
-	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 */
 	for (i = 0; i < ud->count; i++) {
 		switch (CONFIG_ROM_KEY(ud->quadlets[i])) {
@@ -1923,11 +2054,44 @@
 			else	SBP2_DEBUG("sbp2_firmware_revision = %x",
 				   (unsigned int) scsi_id->sbp2_firmware_revision);
 			break;
-
+#if 0
+		case SBP2_LOGICAL_UNIT_DIRECTORY_OFFSET_KEY:
+			SBP2_DEBUG("sbp2_parse_unit_directory: found logical unit directory");
+			break;
+#endif
 		default:
 			break;
 		}
 	}
+}
+
+/*
+ * This function is called to parse sbp2 device's config rom unit
+ * directory. Used to determine things like sbp2 management agent offset,
+ * and command set used (SCSI or RBC). 
+ */
+static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
+{
+	struct unit_directory *ud;
+	int i;
+
+	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;
+	if (ud->parent != NULL)
+		sbp2_parse_logical_unit_directory(scsi_id, ud->parent);
+	if (ud->n_children == 0)
+		sbp2_parse_logical_unit_directory(scsi_id, ud);
+	else 
+		return;
 
 	/* This is the start of our broken device checking. We try to hack
 	 * around oddities and known defects.  */
@@ -2803,6 +2967,7 @@
 		 * It's probably a login/logout/reconnect status.
 		 */
 		if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
+		    (scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
 		    (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
 		    (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
 			atomic_set(&scsi_id->sbp2_login_complete, 1);
diff -urN linux-2.4.21-pre7/drivers/ieee1394/sbp2.h linux-2.4.21-rc1/drivers/ieee1394/sbp2.h
--- linux-2.4.21-pre7/drivers/ieee1394/sbp2.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/sbp2.h	2003-04-21 11:48:41.000000000 -0700
@@ -111,6 +111,29 @@
 
 #define ORB_SET_LOGIN_ID(value)                 (value & 0xffff)
 
+#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(value) (value & 0xffff)
+
+struct sbp2_query_logins_orb {
+	u32 reserved1;
+	u32 reserved2;
+	u32 query_response_hi;
+	u32 query_response_lo;
+	u32 lun_misc;
+	u32 reserved_resp_length;
+	u32 status_FIFO_hi;
+	u32 status_FIFO_lo;
+};
+
+#define RESPONSE_GET_MAX_LOGINS(value)          (value & 0xffff)
+#define RESPONSE_GET_ACTIVE_LOGINS(value)       ((RESPONSE_GET_LENGTH(value) - 4) / 12)
+
+struct sbp2_query_logins_response {
+	u32 length_max_logins;
+	u32 misc_IDs;
+	u32 initiator_misc_hi;
+	u32 initiator_misc_lo;
+};
+
 struct sbp2_reconnect_orb {
 	u32 reserved1;
 	u32 reserved2;
@@ -372,6 +395,10 @@
 	dma_addr_t login_orb_dma;
 	struct sbp2_login_response *login_response;
 	dma_addr_t login_response_dma;
+	struct sbp2_query_logins_orb *query_logins_orb;
+	dma_addr_t query_logins_orb_dma;
+	struct sbp2_query_logins_response *query_logins_response;
+	dma_addr_t query_logins_response_dma;
 	struct sbp2_reconnect_orb *reconnect_orb;
 	dma_addr_t reconnect_orb_dma;
 	struct sbp2_logout_orb *logout_orb;
@@ -397,7 +424,7 @@
 	u32 sbp2_firmware_revision;
 
 	/* 
-	 * Variable used for logins, reconnects, logouts 
+	 * Variable used for logins, reconnects, logouts, query logins
 	 */
 	atomic_t sbp2_login_complete;
 
@@ -513,6 +540,7 @@
 /*
  * SBP-2 protocol related prototypes
  */
+static int sbp2_query_logins(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
 static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
 static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
diff -urN linux-2.4.21-pre7/drivers/ieee1394/video1394.c linux-2.4.21-rc1/drivers/ieee1394/video1394.c
--- linux-2.4.21-pre7/drivers/ieee1394/video1394.c	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/video1394.c	2003-04-21 11:48:41.000000000 -0700
@@ -52,6 +52,7 @@
 #include "highlevel.h"
 #include "video1394.h"
 #include "dma.h"
+#include "ieee1394_hotplug.h"
 
 #include "ohci1394.h"
 
@@ -1241,6 +1242,30 @@
 	return 0;
 }
 
+/*** HOTPLUG STUFF **********************************************************/
+/*
+ * Export information about protocols/devices supported by this driver.
+ */
+static struct ieee1394_device_id video1394_id_table[] = {
+	{
+		.match_flags =IEEE1394_MATCH_SPECIFIER_ID |
+		              IEEE1394_MATCH_VERSION,
+		.specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
+		.version =    CAMERA_SW_VERSION_ENTRY & 0xffffff
+	},
+	{ }
+};
+
+static struct hpsb_protocol_driver video1394_driver = {
+	.name =		"1394 Digital Camera Driver",
+	.id_table = 	video1394_id_table,
+};
+
+MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
+
+
+/******************************************************************************/
+
 static struct file_operations video1394_fops=
 {
 	.owner =	THIS_MODULE,
@@ -1346,6 +1371,8 @@
 
 static void __exit video1394_exit_module (void)
 {
+	hpsb_unregister_protocol(&video1394_driver);
+
 	hpsb_unregister_highlevel (hl_handle);
 
 	devfs_unregister(devfs_handle);
@@ -1372,6 +1399,8 @@
 		return -ENOMEM;
 	}
 
+	hpsb_register_protocol(&video1394_driver);
+
 	PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
 	return 0;
 }
diff -urN linux-2.4.21-pre7/drivers/ieee1394/video1394.h linux-2.4.21-rc1/drivers/ieee1394/video1394.h
--- linux-2.4.21-pre7/drivers/ieee1394/video1394.h	2003-04-21 11:48:30.000000000 -0700
+++ linux-2.4.21-rc1/drivers/ieee1394/video1394.h	2003-04-21 11:48:41.000000000 -0700
@@ -75,5 +75,4 @@
 	struct timeval filltime;	/* time of buffer full */
 };
 
-
 #endif
diff -urN linux-2.4.21-pre7/drivers/net/fc/iph5526.c linux-2.4.21-rc1/drivers/net/fc/iph5526.c
--- linux-2.4.21-pre7/drivers/net/fc/iph5526.c	2003-04-21 11:48:31.000000000 -0700
+++ linux-2.4.21-rc1/drivers/net/fc/iph5526.c	2003-04-21 11:48:43.000000000 -0700
@@ -3174,38 +3174,6 @@
 	LEAVE("rx_net_mfs_packet");
 }
 
-unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev) 
-{
-struct fch_hdr *fch=(struct fch_hdr *)skb->data;
-struct fcllc *fcllc;
-	skb->mac.raw = skb->data;
-	fcllc = (struct fcllc *)(skb->data + sizeof(struct fch_hdr) + 2);
-	skb_pull(skb,sizeof(struct fch_hdr) + 2);
-
-	if(*fch->daddr & 1) {
-		if(!memcmp(fch->daddr,dev->broadcast,FC_ALEN)) 	
-			skb->pkt_type = PACKET_BROADCAST;
-		else
-			skb->pkt_type = PACKET_MULTICAST;
-	}
-	else if(dev->flags & IFF_PROMISC) {
-		if(memcmp(fch->daddr, dev->dev_addr, FC_ALEN))
-			skb->pkt_type=PACKET_OTHERHOST;
-	}
-	
-	/* Strip the SNAP header from ARP packets since we don't 
-	 * pass them through to the 802.2/SNAP layers.
-	 */
-
-	if (fcllc->dsap == EXTENDED_SAP &&
-		(fcllc->ethertype == ntohs(ETH_P_IP) ||
-		 fcllc->ethertype == ntohs(ETH_P_ARP))) {
-		skb_pull(skb, sizeof(struct fcllc));
-		return fcllc->ethertype;
-	}
-	return ntohs(ETH_P_802_2);
-}
-
 static int tx_exchange(struct fc_info *fi, char *data, u_int len, u_int r_ctl, u_int type, u_int d_id, u_int mtu, int int_required, u_short tx_ox_id, u_int frame_class)
 {
 u_char df_ctl; 
diff -urN linux-2.4.21-pre7/drivers/net/fc/iph5526_ip.h linux-2.4.21-rc1/drivers/net/fc/iph5526_ip.h
--- linux-2.4.21-pre7/drivers/net/fc/iph5526_ip.h	1999-08-23 10:12:38.000000000 -0700
+++ linux-2.4.21-rc1/drivers/net/fc/iph5526_ip.h	2003-04-21 11:48:43.000000000 -0700
@@ -18,7 +18,6 @@
 
 static void rx_net_packet(struct fc_info *fi, u_char *buff_addr, int payload_size);
 static void rx_net_mfs_packet(struct fc_info *fi, struct sk_buff *skb);
-unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev); 
 static int tx_ip_packet(struct sk_buff *skb, unsigned long len, struct fc_info *fi);
 static int tx_arp_packet(char *data, unsigned long len, struct fc_info *fi);
 #endif
diff -urN linux-2.4.21-pre7/drivers/scsi/aic7xxx/Makefile linux-2.4.21-rc1/drivers/scsi/aic7xxx/Makefile
--- linux-2.4.21-pre7/drivers/scsi/aic7xxx/Makefile	2003-04-21 11:48:32.000000000 -0700
+++ linux-2.4.21-rc1/drivers/scsi/aic7xxx/Makefile	2003-04-21 11:48:49.000000000 -0700
@@ -83,7 +83,7 @@
 endif
 $(aic79xx_gen): aic79xx.seq aic79xx.reg aicasm/aicasm
 	$(aic79xx_asm_cmd)
+endif
 
 aicasm/aicasm: aicasm/*.[chyl]
 	$(MAKE) -C aicasm
-endif
diff -urN linux-2.4.21-pre7/drivers/scsi/sd.c linux-2.4.21-rc1/drivers/scsi/sd.c
--- linux-2.4.21-pre7/drivers/scsi/sd.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/scsi/sd.c	2003-04-21 11:48:50.000000000 -0700
@@ -731,15 +731,17 @@
 				 * check_disk_change */
 	}
 
-	/* Using Start/Stop enables differentiation between drive with
+	/*
+	 * Using TEST_UNIT_READY enables differentiation between drive with
 	 * no cartridge loaded - NOT READY, drive with changed cartridge -
 	 * UNIT ATTENTION, or with same cartridge - GOOD STATUS.
-	 * This also handles drives that auto spin down. eg iomega jaz 1GB
-	 * as this will spin up the drive.
+	 *
+	 * Drives that auto spin down. eg iomega jaz 1G, will be started
+	 * by sd_init_onedisk(), whenever revalidate_scsidisk() is called.
 	 */
 	retval = -ENODEV;
 	if (scsi_block_when_processing_errors(SDev))
-		retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL);
+		retval = scsi_ioctl(SDev, SCSI_IOCTL_TEST_UNIT_READY, NULL);
 
 	if (retval) {		/* Unable to test, unit probably not ready.
 				 * This usually means there is no disc in the
@@ -1003,7 +1005,7 @@
 			 */
 			int m;
 			int hard_sector = sector_size;
-			int sz = rscsi_disks[i].capacity * (hard_sector/256);
+			unsigned int sz = (rscsi_disks[i].capacity/2) * (hard_sector/256);
 
 			/* There are 16 minors allocated for each major device */
 			for (m = i << 4; m < ((i + 1) << 4); m++) {
@@ -1011,9 +1013,9 @@
 			}
 
 			printk("SCSI device %s: "
-			       "%d %d-byte hdwr sectors (%d MB)\n",
+			       "%u %d-byte hdwr sectors (%u MB)\n",
 			       nbuff, rscsi_disks[i].capacity,
-			       hard_sector, (sz/2 - sz/1250 + 974)/1950);
+			       hard_sector, (sz - sz/625 + 974)/1950);
 		}
 
 		/* Rescale capacity to 512-byte units */
diff -urN linux-2.4.21-pre7/drivers/usb/CDCEther.c linux-2.4.21-rc1/drivers/usb/CDCEther.c
--- linux-2.4.21-pre7/drivers/usb/CDCEther.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/CDCEther.c	2003-04-21 11:48:51.000000000 -0700
@@ -209,33 +209,42 @@
 {
 	ether_dev_t *ether_dev = urb->context;
 	struct net_device *net;
-	__u8	*d;
+	struct usb_ctrlrequest *event;
+#define bNotification	bRequest
 
 	if ( !ether_dev )
 		return;
-	dbg("got intr callback");
+	net = ether_dev->net;
 	switch ( urb->status ) {
 		case USB_ST_NOERROR:
 			break;
 		case USB_ST_URB_KILLED:
-			return;
 		default:
-			dbg("intr status %d", urb->status);
+			dbg("%s intr status %d", net->name, urb->status);
+			return;
 	}
 
-	d = urb->transfer_buffer;
-	dbg("d: %x", d[0]);
-	net = ether_dev->net;
-	if ( d[0] & 0xfc ) {
-		ether_dev->stats.tx_errors++;
-		if ( d[0] & TX_UNDERRUN )
-			ether_dev->stats.tx_fifo_errors++;
-		if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
-			ether_dev->stats.tx_aborted_errors++;
-		if ( d[0] & LATE_COL )
-			ether_dev->stats.tx_window_errors++;
-		if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
-			netif_carrier_off(net);
+	event = urb->transfer_buffer;
+	if (event->bRequestType != 0xA1)
+		dbg ("%s unknown event type %x", net->name,
+			event->bRequestType);
+	else switch (event->bNotification) {
+	case 0x00:		// NETWORK CONNECTION
+		dbg ("%s network %s", net->name,
+			event->wValue ? "connect" : "disconnect");
+		if (event->wValue)
+			netif_carrier_on (net);
+		else
+			netif_carrier_off (net);
+		break;
+	case 0x2A:		// CONNECTION SPEED CHANGE
+		dbg ("%s speed change", net->name);
+		/* ignoring eight bytes of data */
+		break;
+	case 0x01:		// RESPONSE AVAILABLE (none requested)
+	default:		// else undefined for CDC Ether
+		err ("%s illegal notification %02x", net->name,
+			event->bNotification);
 	}
 }
 
@@ -390,10 +399,13 @@
 			ether_dev->usb,
 			usb_rcvintpipe(ether_dev->usb, ether_dev->comm_ep_in),
 			ether_dev->intr_buff,
-			8, /* Transfer buffer length */
+			sizeof ether_dev->intr_buff,
 			intr_callback,
 			ether_dev,
-			ether_dev->intr_interval);
+			(ether_dev->usb->speed == USB_SPEED_HIGH)
+				? ( 1 << ether_dev->intr_interval)
+				: ether_dev->intr_interval
+			);
 		if ( (res = usb_submit_urb(&ether_dev->intr_urb)) ) {
 			warn("%s failed intr_urb %d", __FUNCTION__, res );
 		}
diff -urN linux-2.4.21-pre7/drivers/usb/CDCEther.h linux-2.4.21-rc1/drivers/usb/CDCEther.h
--- linux-2.4.21-pre7/drivers/usb/CDCEther.h	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.21-rc1/drivers/usb/CDCEther.h	2003-04-21 11:48:51.000000000 -0700
@@ -79,7 +79,8 @@
 	struct urb		rx_urb, tx_urb, intr_urb, ctrl_urb;
 	unsigned char		rx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES)));
 	unsigned char		tx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES)));
-	unsigned char		intr_buff[8] __attribute__((aligned(L1_CACHE_BYTES))) ;
+	unsigned char		intr_buff[16]
+				__attribute__((aligned(L1_CACHE_BYTES))) ;
 } ether_dev_t;
 
 /* These definitions used in the Ethernet Packet Filtering requests */
diff -urN linux-2.4.21-pre7/drivers/usb/acm.c linux-2.4.21-rc1/drivers/usb/acm.c
--- linux-2.4.21-pre7/drivers/usb/acm.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/acm.c	2003-04-21 11:48:51.000000000 -0700
@@ -651,6 +651,7 @@
 static struct usb_device_id acm_ids[] = {
 	{ USB_DEVICE(0x22B8, 0x1005) },		/* Motorola TimePort 280 */
 	{ USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
+	{ USB_DEVICE_INFO(USB_CLASS_COMM, 2, 0) },
 	{ }
 };
 
diff -urN linux-2.4.21-pre7/drivers/usb/host/ehci-mem.c linux-2.4.21-rc1/drivers/usb/host/ehci-mem.c
--- linux-2.4.21-pre7/drivers/usb/host/ehci-mem.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/host/ehci-mem.c	2003-04-21 11:48:51.000000000 -0700
@@ -62,6 +62,7 @@
 {
 	memset (qtd, 0, sizeof *qtd);
 	qtd->qtd_dma = dma;
+	qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
 	qtd->hw_next = EHCI_LIST_END;
 	qtd->hw_alt_next = EHCI_LIST_END;
 	INIT_LIST_HEAD (&qtd->qtd_list);
diff -urN linux-2.4.21-pre7/drivers/usb/host/ehci-q.c linux-2.4.21-rc1/drivers/usb/host/ehci-q.c
--- linux-2.4.21-pre7/drivers/usb/host/ehci-q.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/host/ehci-q.c	2003-04-21 11:48:51.000000000 -0700
@@ -137,7 +137,10 @@
 			if (QTD_CERR (token))
 				urb->status = -EPIPE;
 			else {
-				dbg ("3strikes");
+				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
+					urb->dev->devpath,
+					usb_pipeendpoint (urb->pipe),
+					usb_pipein (urb->pipe) ? "in" : "out");
 				urb->status = -EPROTO;
 			}
 		/* CERR nonzero + no errors + halt --> stall */
@@ -866,7 +869,7 @@
 			 * HC is allowed to fetch the old dummy (4.10.2).
 			 */
 			token = qtd->hw_token;
-			qtd->hw_token = 0;
+			qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
 			wmb ();
 			dummy = qh->dummy;
 
@@ -918,8 +921,7 @@
 	if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
 		epnum |= 0x10;
 
-	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		hcd_to_bus (&ehci->hcd)->bus_name,
+	ehci_vdbg (ehci, "submit_async urb %p len %d ep%d%s qtd %p [qh %p]\n",
 		urb, urb->transfer_buffer_length,
 		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
 		qtd, dev ? dev->ep [epnum] : (void *)~0);
diff -urN linux-2.4.21-pre7/drivers/usb/host/uhci.c linux-2.4.21-rc1/drivers/usb/host/uhci.c
--- linux-2.4.21-pre7/drivers/usb/host/uhci.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/host/uhci.c	2003-04-21 11:48:51.000000000 -0700
@@ -1221,7 +1221,7 @@
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	dma_addr_t data = urbp->transfer_buffer_dma_handle;
 
-	if (len < 0)
+	if (len < 0 || maxsze <= 0)
 		return -EINVAL;
 
 	/* Can't have low speed bulk transfers */
diff -urN linux-2.4.21-pre7/drivers/usb/pegasus.c linux-2.4.21-rc1/drivers/usb/pegasus.c
--- linux-2.4.21-pre7/drivers/usb/pegasus.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/pegasus.c	2003-04-21 11:48:51.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
+ *  Copyright (c) 1999-2003 Petko Manolov (petkan@users.sourceforge.net)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -42,7 +42,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.29 (2002/12/31)"
+#define DRIVER_VERSION "v0.4.30 (2003/04/01)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -625,8 +625,12 @@
 			pegasus->stats.tx_aborted_errors++;
 		if (d[0] & LATE_COL)
 			pegasus->stats.tx_window_errors++;
-		if (d[0] & (NO_CARRIER | LOSS_CARRIER))
+		if (d[5] & LINK_STATUS) {
+			netif_carrier_on(net);
+		} else {
+			netif_carrier_off(net);
 			pegasus->stats.tx_carrier_errors++;
+		}
 	}
 }
 #endif
diff -urN linux-2.4.21-pre7/drivers/usb/pegasus.h linux-2.4.21-rc1/drivers/usb/pegasus.h
--- linux-2.4.21-pre7/drivers/usb/pegasus.h	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/pegasus.h	2003-04-21 11:48:51.000000000 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
+ * Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as published
@@ -52,6 +52,8 @@
 #define	LOSS_CARRIER		0x08
 #define	JABBER_TIMEOUT		0x04
 
+#define	LINK_STATUS		0x01
+
 #define	PEGASUS_REQT_READ	0xc0
 #define	PEGASUS_REQT_WRITE	0x40
 #define	PEGASUS_REQ_GET_REGS	0xf0
@@ -232,8 +234,6 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
 		LINKSYS_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
diff -urN linux-2.4.21-pre7/drivers/usb/scanner.c linux-2.4.21-rc1/drivers/usb/scanner.c
--- linux-2.4.21-pre7/drivers/usb/scanner.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/scanner.c	2003-04-21 11:48:51.000000000 -0700
@@ -357,6 +357,11 @@
  *      Fujitsu, Hewlett-Packard, Lexmark, LG Electronics, Medion, Microtek,
  *      Primax, Prolink,  Plustek, SYSCAN, Trust and UMAX scanners.
  *
+ * 0.4.12  2003-04-16
+ *    - Fixed endpoint detection. The endpoints were numbered from 1 to n but
+ *      that assumption is not correct in all cases.
+ *
+ *
  * TODO
  *    - Performance
  *    - Select/poll methods
@@ -913,7 +918,7 @@
 				info ("probe_scanner: ignoring additional bulk_in_ep:%d", ep_cnt);
 				continue;
 			}
-			have_bulk_in = ep_cnt;
+			have_bulk_in = endpoint[ep_cnt - 1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 			dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
 			continue;
 		}
@@ -924,7 +929,7 @@
 				info ("probe_scanner: ignoring additional bulk_out_ep:%d", ep_cnt);
 				continue;
 			}
-			have_bulk_out = ep_cnt;
+			have_bulk_out = endpoint[ep_cnt - 1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 			dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
 			continue;
 		}
@@ -935,7 +940,7 @@
 				info ("probe_scanner: ignoring additional intr_ep:%d", ep_cnt);
 				continue;
 			}
-			have_intr = ep_cnt;
+			have_intr = endpoint[ep_cnt - 1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 			dbg("probe_scanner: intr_ep:%d", have_intr);
 			continue;
 		}
diff -urN linux-2.4.21-pre7/drivers/usb/scanner.h linux-2.4.21-rc1/drivers/usb/scanner.h
--- linux-2.4.21-pre7/drivers/usb/scanner.h	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/scanner.h	2003-04-21 11:48:51.000000000 -0700
@@ -44,7 +44,7 @@
 
 // #define DEBUG
 
-#define DRIVER_VERSION "0.4.11"
+#define DRIVER_VERSION "0.4.12"
 #define DRIVER_DESC "USB Scanner Driver"
 
 #include <linux/usb.h>
diff -urN linux-2.4.21-pre7/drivers/usb/serial/ftdi_sio.c linux-2.4.21-rc1/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.21-pre7/drivers/usb/serial/ftdi_sio.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/serial/ftdi_sio.c	2003-04-21 11:48:51.000000000 -0700
@@ -17,6 +17,42 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (23/Feb/2003) Bill Ryder
+ *      Added matrix orb device vid/pids from Wayne Wylupski
+ *
+ * (19/Feb/2003) Ian Abbott
+ *      For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
+ *      changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
+ *      ASYNC_SPD_SHI or ASYNC_SPD_WARP.  Also, unless ASYNC_SPD_CUST is in
+ *      force, don't bother changing baud rate when custom_divisor has changed.
+ *
+ * (18/Feb/2003) Ian Abbott
+ *      Fixed TIOCMGET handling to include state of DTR and RTS, the state
+ *      of which are now saved by set_dtr() and set_rts().
+ *      Fixed improper storage class for buf in set_dtr() and set_rts().
+ *      Added FT232BM chip type and support for its extra baud rates (compared
+ *      to FT8U232AM).
+ *      Took account of special case divisor values for highest baud rates of
+ *      FT8U232AM and FT232BM.
+ *      For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
+ *      as previous alt_speed setting is now stale.
+ *      Moved startup code common between the startup routines for the
+ *      different chip types into a common subroutine.
+ *
+ * (17/Feb/2003) Bill Ryder
+ *      Added write urb buffer pool on a per device basis
+ *      Added more checking for open file on callbacks (fixed OOPS)
+ *      Added CrystalFontz 632 and 634 PIDs 
+ *         (thanx to CrystalFontz for the sample devices - they flushed out
+ *           some driver bugs)
+ *      Minor debugging message changes
+ *      Added throttle, unthrottle and chars_in_buffer functions
+ *      Fixed FTDI_SIO (the original device) bug
+ *      Fixed some shutdown handling
+ *      
+ * 
+ * 
+ * 
  * (07/Jun/2002) Kuba Ober
  *	Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
  *	function. It was getting too complex.
@@ -139,7 +175,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.2.1"
+#define DRIVER_VERSION "v1.3.2"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
@@ -156,13 +192,44 @@
  *   so .. 8U232AM's baudrate setting codes are different
  * - it has a two byte status code.
  * - it returns characters every 16ms (the FTDI does it every 40ms)
+ *
+ * the bcdDevice value is used to differentiate FT232BM and FT245BM from
+ * the earlier FT8U232AM and FT8U232BM.  For now, include all known VID/PID
+ * combinations in both tables.
+ * FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know
+ * if those ever went into mass production. [Ian Abbott]
  */
 
 
 static struct usb_device_id id_table_8U232AM [] = {
-	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
-	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
-	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0, 0x3ff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0, 0x3ff) },
+	{ }						/* Terminating entry */
+};
+
+
+static struct usb_device_id id_table_FT232BM [] = {
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
+
 	{ }						/* Terminating entry */
 };
 
@@ -170,13 +237,27 @@
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
-	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
-	{ }						/* Terminating entry */
+	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID) },
+	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID) },
+	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID) },
+	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID) },
+	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID) },
+	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID) },
+	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID) },	{ }						/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
+
+/* constants which set the number of write urb buffers */
+#define NUM_URBS			32
+/* Don't be tempted to increase this buffer to > 64 ! I tried it and it doesn't work */
+#define URB_TRANSFER_BUFFER_SIZE	64 /* the device's max packet size */
+
+
 struct ftdi_private {
 	ftdi_chip_type_t chip_type;
 				/* type of the device, either SIO or FT8U232AM */
@@ -188,8 +269,13 @@
 				 * it is different between devices
 				 */
 	int flags;		/* some ASYNC_xxxx flags are supported */
+	unsigned long last_dtr_rts;	/* saved modem control outputs */
         wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
  	char prev_status, diff_status;        /* Used for TIOCMIWAIT */
+
+	struct urb	*write_urb_pool[NUM_URBS];
+	spinlock_t	write_urb_pool_lock;
+
 };
 
 /* Used for TIOCMIWAIT */
@@ -203,20 +289,25 @@
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_SIO_startup		(struct usb_serial *serial);
 static int  ftdi_8U232AM_startup	(struct usb_serial *serial);
+static int  ftdi_FT232BM_startup	(struct usb_serial *serial);
 static void ftdi_shutdown		(struct usb_serial *serial);
 static int  ftdi_open			(struct usb_serial_port *port, struct file *filp);
 static void ftdi_close			(struct usb_serial_port *port, struct file *filp);
 static int  ftdi_write			(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
 static int  ftdi_write_room		(struct usb_serial_port *port);
+static int  ftdi_chars_in_buffer	(struct usb_serial_port *port);
 static void ftdi_write_bulk_callback	(struct urb *urb);
 static void ftdi_read_bulk_callback	(struct urb *urb);
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_ioctl			(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 static void ftdi_break_ctl		(struct usb_serial_port *port, int break_state );
-static unsigned short int ftdi_baud_base_to_divisor
-					(int baud, int base);
-static unsigned short int ftdi_baud_to_divisor
-					(int baud);
+static void ftdi_throttle		(struct usb_serial_port *port);
+static void ftdi_unthrottle		(struct usb_serial_port *port);
+
+static unsigned short int ftdi_232am_baud_base_to_divisor (int baud, int base);
+static unsigned short int ftdi_232am_baud_to_divisor (int baud);
+static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
+static __u32 ftdi_232bm_baud_to_divisor (int baud);
 
 static struct usb_serial_device_type ftdi_SIO_device = {
 	.owner =		THIS_MODULE,
@@ -228,8 +319,11 @@
 	.num_ports =		1,
 	.open =			ftdi_open,
 	.close =		ftdi_close,
+	.throttle =		ftdi_throttle,
+	.unthrottle =		ftdi_unthrottle,
 	.write =		ftdi_write,
 	.write_room =		ftdi_write_room,
+	.chars_in_buffer =	ftdi_chars_in_buffer,
 	.read_bulk_callback =	ftdi_read_bulk_callback,
 	.write_bulk_callback =	ftdi_write_bulk_callback,
 	.ioctl =		ftdi_ioctl,
@@ -241,7 +335,7 @@
 
 static struct usb_serial_device_type ftdi_8U232AM_device = {
 	.owner =		THIS_MODULE,
-	.name =			"FTDI 8U232AM",
+	.name =			"FTDI 8U232AM Compatible",
 	.id_table =		id_table_8U232AM,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
@@ -249,8 +343,11 @@
 	.num_ports =		1,
 	.open =			ftdi_open,
 	.close =		ftdi_close,
+	.throttle =		ftdi_throttle,
+	.unthrottle =		ftdi_unthrottle,
 	.write =		ftdi_write,
 	.write_room =		ftdi_write_room,
+	.chars_in_buffer =	ftdi_chars_in_buffer,
 	.read_bulk_callback =	ftdi_read_bulk_callback,
 	.write_bulk_callback =	ftdi_write_bulk_callback,
 	.ioctl =		ftdi_ioctl,
@@ -260,8 +357,35 @@
 	.shutdown =		ftdi_shutdown,
 };
 
+static struct usb_serial_device_type ftdi_FT232BM_device = {
+	.owner =		THIS_MODULE,
+	.name =			"FTDI FT232BM Compatible",
+	.id_table =		id_table_FT232BM,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			ftdi_open,
+	.close =		ftdi_close,
+	.throttle =		ftdi_throttle,
+	.unthrottle =		ftdi_unthrottle,
+	.write =		ftdi_write,
+	.write_room =		ftdi_write_room,
+	.chars_in_buffer =	ftdi_chars_in_buffer,
+	.read_bulk_callback =	ftdi_read_bulk_callback,
+	.write_bulk_callback =	ftdi_write_bulk_callback,
+	.ioctl =		ftdi_ioctl,
+	.set_termios =		ftdi_set_termios,
+	.break_ctl =		ftdi_break_ctl,
+	.startup =		ftdi_FT232BM_startup,
+	.shutdown =		ftdi_shutdown,
+};
+
+
+
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
+/* High and low are for DTR, RTS etc etc */
 #define HIGH 1
 #define LOW 0
 
@@ -271,7 +395,7 @@
  * ***************************************************************************
  */
 
-static unsigned short int ftdi_baud_base_to_divisor(int baud, int base)
+static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
 {
 	unsigned short int divisor;
 	int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
@@ -281,22 +405,47 @@
 	if (divisor3 == 1) divisor |= 0xc000; else // 0.125
 	if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
 	if (divisor3 != 0) divisor |= 0x8000;      // 0.25
+	if (divisor == 1) divisor = 0;	/* special case for maximum baud rate */
+	return divisor;
+}
+
+static unsigned short int ftdi_232am_baud_to_divisor(int baud)
+{
+	 return(ftdi_232am_baud_base_to_divisor(baud, 48000000));
+}
+
+static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
+{
+	static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
+	__u32 divisor;
+	int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+	divisor = divisor3 >> 3;
+	divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
+	/* Deal with special cases for highest baud rates. */
+	if (divisor == 1) divisor = 0; else	// 1.0
+	if (divisor == 0x4001) divisor = 1;	// 1.5
 	return divisor;
 }
 
-static unsigned short int ftdi_baud_to_divisor(int baud)
+static __u32 ftdi_232bm_baud_to_divisor(int baud)
 {
-	 return(ftdi_baud_base_to_divisor(baud, 48000000));
+	 return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
 }
 
-static int set_rts(struct usb_device *dev,
-		   unsigned int pipe,
-		   int high_or_low)
+static int set_rts(struct usb_serial_port *port, int high_or_low)
 {
-	static char buf[1];
-	unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH : 
-				FTDI_SIO_SET_RTS_LOW);
-	return(usb_control_msg(dev, pipe,
+	struct ftdi_private * priv = (struct ftdi_private *)port->private;
+	char buf[1];
+	unsigned ftdi_high_or_low;
+	if (high_or_low) {
+		ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
+		priv->last_dtr_rts |= TIOCM_RTS;
+	} else {
+		ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
+		priv->last_dtr_rts &= ~TIOCM_RTS;
+	}
+	return(usb_control_msg(port->serial->dev,
+			       usb_sndctrlpipe(port->serial->dev, 0),
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
 			       ftdi_high_or_low, 0, 
@@ -304,14 +453,20 @@
 }
 
 
-static int set_dtr(struct usb_device *dev,
-                   unsigned int pipe,
-                   int high_or_low)
+static int set_dtr(struct usb_serial_port *port, int high_or_low)
 {
-	static char buf[1];
-	unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH : 
-				FTDI_SIO_SET_DTR_LOW);
-	return(usb_control_msg(dev, pipe,
+	struct ftdi_private * priv = (struct ftdi_private *)port->private;
+	char buf[1];
+	unsigned ftdi_high_or_low;
+	if (high_or_low) {
+		ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
+		priv->last_dtr_rts |= TIOCM_DTR;
+	} else {
+		ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
+		priv->last_dtr_rts &= ~TIOCM_DTR;
+	}
+	return(usb_control_msg(port->serial->dev,
+			       usb_sndctrlpipe(port->serial->dev, 0),
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
 			       ftdi_high_or_low, 0, 
@@ -319,30 +474,36 @@
 }
 
 
-static __u16 get_ftdi_divisor(struct usb_serial_port * port);
+static __u32 get_ftdi_divisor(struct usb_serial_port * port);
 
 
 static int change_speed(struct usb_serial_port *port)
 {
 	char buf[1];
         __u16 urb_value;
+	__u16 urb_index;
+	__u32 urb_index_value;
 
-	urb_value = get_ftdi_divisor(port);
+	urb_index_value = get_ftdi_divisor(port);
+	urb_value = (__u16)urb_index_value;
+	urb_index = (__u16)(urb_index_value >> 16);
 	
 	return (usb_control_msg(port->serial->dev,
 			    usb_sndctrlpipe(port->serial->dev, 0),
 			    FTDI_SIO_SET_BAUDRATE_REQUEST,
 			    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
-			    urb_value, 0,
+			    urb_value, urb_index,
 			    buf, 0, 100) < 0);
 }
 
 
-static __u16 get_ftdi_divisor(struct usb_serial_port * port)
+static __u32 get_ftdi_divisor(struct usb_serial_port * port)
 { /* get_ftdi_divisor */
 	
 	struct ftdi_private * priv = (struct ftdi_private *)port->private;
-	__u16 urb_value = 0;
+	__u32 div_value = 0;
+	int div_okay = 1;
+	char *chip_name = "";
 	int baud;
 
 	/*
@@ -387,37 +548,53 @@
 	if (!baud) baud = 9600;	
 	switch(priv->chip_type) {
 	case SIO: /* SIO chip */
+		chip_name = "SIO";
 		switch(baud) {
-		case 300: urb_value = ftdi_sio_b300; break;
-		case 600: urb_value = ftdi_sio_b600; break;
-		case 1200: urb_value = ftdi_sio_b1200; break;
-		case 2400: urb_value = ftdi_sio_b2400; break;
-		case 4800: urb_value = ftdi_sio_b4800; break;
-		case 9600: urb_value = ftdi_sio_b9600; break;
-		case 19200: urb_value = ftdi_sio_b19200; break;
-		case 38400: urb_value = ftdi_sio_b38400; break;
-		case 57600: urb_value = ftdi_sio_b57600;  break;
-		case 115200: urb_value = ftdi_sio_b115200; break;
+		case 300: div_value = ftdi_sio_b300; break;
+		case 600: div_value = ftdi_sio_b600; break;
+		case 1200: div_value = ftdi_sio_b1200; break;
+		case 2400: div_value = ftdi_sio_b2400; break;
+		case 4800: div_value = ftdi_sio_b4800; break;
+		case 9600: div_value = ftdi_sio_b9600; break;
+		case 19200: div_value = ftdi_sio_b19200; break;
+		case 38400: div_value = ftdi_sio_b38400; break;
+		case 57600: div_value = ftdi_sio_b57600;  break;
+		case 115200: div_value = ftdi_sio_b115200; break;
 		} /* baud */
-		if (urb_value == 0)
-			dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__,  baud);
+		if (div_value == 0) {
+  			dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__,  baud);
+			div_value = ftdi_sio_b9600;
+			div_okay = 0;
+		}
 		break;
 	case FT8U232AM: /* 8U232AM chip */
+		chip_name = "FT8U232AM";
+		if (baud <= 3000000) {
+			div_value = ftdi_232am_baud_to_divisor(baud);
+		} else {
+	                dbg("%s - Baud rate too high!", __FUNCTION__);
+			div_value = ftdi_232am_baud_to_divisor(9600);
+			div_okay = 0;
+		}
+		break;
+	case FT232BM: /* FT232BM chip */
+		chip_name = "FT232BM";
 		if (baud <= 3000000) {
-			urb_value = ftdi_baud_to_divisor(baud);
+			div_value = ftdi_232bm_baud_to_divisor(baud);
 		} else {
 	                dbg("%s - Baud rate too high!", __FUNCTION__);
+			div_value = ftdi_232bm_baud_to_divisor(9600);
+			div_okay = 0;
 		}
 		break;
 	} /* priv->chip_type */
 
-	if (urb_value == 0) {
-		urb_value = ftdi_sio_b9600;
-	} else {
-		dbg("%s - Baud rate set to %d (divisor %d) on chip %s", __FUNCTION__, baud, urb_value, (priv->chip_type == SIO) ? "SIO" : "FT8U232AM" );
+	if (div_okay) {
+		dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
+			__FUNCTION__, baud, (unsigned long)div_value, chip_name);
 	}
 
-	return(urb_value);
+	return(div_value);
 }
 
 
@@ -473,17 +650,23 @@
 	port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 check_and_exit:
-	if (((old_priv.flags & ASYNC_SPD_MASK) !=
-	     (priv->flags & ASYNC_SPD_MASK)) ||
-	    (old_priv.custom_divisor != priv->custom_divisor)) {
+	if ((old_priv.flags & ASYNC_SPD_MASK) !=
+	     (priv->flags & ASYNC_SPD_MASK)) {
 		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			port->tty->alt_speed = 57600;
-		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+		else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
 			port->tty->alt_speed = 115200;
-		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+		else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
 			port->tty->alt_speed = 230400;
-		if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+		else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			port->tty->alt_speed = 460800;
+		else
+			port->tty->alt_speed = 0;
+	}
+	if (((old_priv.flags & ASYNC_SPD_MASK) !=
+	     (priv->flags & ASYNC_SPD_MASK)) ||
+	    (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
+	     (old_priv.custom_divisor != priv->custom_divisor))) {
 		change_speed(port);
 	}
 	
@@ -497,66 +680,166 @@
  * ***************************************************************************
  */
 
-/* Startup for the SIO chip */
-static int ftdi_SIO_startup (struct usb_serial *serial)
+/* Common startup subroutine */
+/* Called from ftdi_SIO_startup, etc. */
+static int ftdi_common_startup (struct usb_serial *serial)
 {
 	struct ftdi_private *priv;
+	int i ;
+	struct urb *urb; 
+	
+	dbg("%s",__FUNCTION__);
 
 	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
 	if (!priv){
 		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
 		return -ENOMEM;
 	}
+	memset(priv, 0, sizeof(*priv));
 
-	priv->chip_type = SIO;
-	priv->baud_base = 12000000 / 16;
-	priv->custom_divisor = 0;
-	priv->write_offset = 1;
- 	priv->prev_status = priv->diff_status = 0;
+        init_waitqueue_head(&priv->delta_msr_wait);
 	/* This will push the characters through immediately rather
 	   than queue a task to deliver them */
 	priv->flags = ASYNC_LOW_LATENCY;
+
+	/* create our write urb pool and transfer buffers - shared across all ftdi devices */ 
+	spin_lock_init (&priv->write_urb_pool_lock);
+	for (i = 0; i < NUM_URBS; ++i) {
+		urb = usb_alloc_urb(0);
+		priv->write_urb_pool[i] = urb;
+		if (urb == NULL) {
+			err("Unable to create new urb in urb pool");
+			continue;
+		}
+
+		urb->transfer_buffer = NULL;
+		urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+		if (!urb->transfer_buffer) {
+			err("%s - out of memory for urb buffers.", 
+			    __FUNCTION__);
+			continue;
+		}
+	}
+
+	
+	return (0);
+}
+
+
+/* Startup for the SIO chip */
+/* Called from usbserial:serial_probe */
+static int ftdi_SIO_startup (struct usb_serial *serial)
+{
+	struct ftdi_private *priv;
+	int err;
+
+	dbg("%s",__FUNCTION__);
+
+	err = ftdi_common_startup(serial);
+	if (err){
+		return (err);
+	}
+
+	priv = serial->port->private;
+	priv->chip_type = SIO;
+	priv->baud_base = 12000000 / 16;
+	priv->write_offset = 1;
 	
 	return (0);
 }
 
 /* Startup for the 8U232AM chip */
+/* Called from usbserial:serial_probe */
 static int ftdi_8U232AM_startup (struct usb_serial *serial)
-{
+{ /* ftdi_8U232AM_startup */
 	struct ftdi_private *priv;
+	int err;
 
-	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
-	if (!priv){
-		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
-		return -ENOMEM;
+	dbg("%s",__FUNCTION__);
+	err = ftdi_common_startup(serial);
+	if (err){
+		return (err);
 	}
 
+	priv = serial->port->private;
 	priv->chip_type = FT8U232AM;
 	priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */
-	priv->custom_divisor = 0;
-	priv->write_offset = 0;
-        init_waitqueue_head(&priv->delta_msr_wait);
-	/* This will push the characters through immediately rather
-	   than queue a task to deliver them */
-	priv->flags = ASYNC_LOW_LATENCY;
 	
 	return (0);
-}
+} /* ftdi_8U232AM_startup */
+
+/* Startup for the FT232BM chip */
+/* Called from usbserial:serial_probe */
+static int ftdi_FT232BM_startup (struct usb_serial *serial)
+{ /* ftdi_FT232BM_startup */
+	struct ftdi_private *priv;
+	int err;
+
+	dbg("%s",__FUNCTION__);
+	err = ftdi_common_startup(serial);
+	if (err){
+		return (err);
+	}
+
+	priv = serial->port->private;
+	priv->chip_type = FT232BM;
+	priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */
+	
+	return (0);
+} /* ftdi_FT232BM_startup */
+
+/* ftdi_shutdown is called from usbserial:usb_serial_disconnect 
+ *   it is called when the usb device is disconnected
+ *
+ *   usbserial:usb_serial_disconnect
+ *      calls __serial_close for each open of the port
+ *      shutdown is called then (ie ftdi_shutdown)
+ */
 
 
 static void ftdi_shutdown (struct usb_serial *serial)
-{
+{ /* ftdi_shutdown */
+	
+	struct usb_serial_port *port = &serial->port[0];	
+	struct ftdi_private *priv = serial->port->private; 
+	int i;
+	unsigned long flags; 
+
 	dbg("%s", __FUNCTION__);
 
-	/* stop reads and writes on all ports */
-	while (serial->port[0].open_count > 0) {
-	        ftdi_close (&serial->port[0], NULL);
-	}
-	if (serial->port[0].private){
-		kfree(serial->port[0].private);
-		serial->port[0].private = NULL;
+	/* all open ports are closed at this point 
+         *    (by usbserial.c:__serial_close, which calls ftdi_close)  
+	 */
+
+	
+	/* Only execute this if this is the final open port for this device */
+	if (port->open_count == 0){
+		spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+		for (i = 0; i < NUM_URBS; ++i) {
+			if (priv->write_urb_pool[i]) {
+				/* FIXME - uncomment the following usb_unlink_urb call when
+				 * the host controllers get fixed to set urb->dev = NULL after
+				 * the urb is finished.  Otherwise this call oopses. */
+				/* usb_unlink_urb(priv->write_urb_pool[i]); */
+				if (priv->write_urb_pool[i]->transfer_buffer) {
+					kfree(priv->write_urb_pool[i]->transfer_buffer);
+					priv->write_urb_pool[i]->transfer_buffer = NULL;
+				}
+				usb_free_urb (priv->write_urb_pool[i]);
+				priv->write_urb_pool[i] = NULL;
+			}
+		}
+
+		spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+		/* usb_disconnect shuts down the port->read_urb so don't do it here */
+		/* as was done previously */
+	}
+	if (serial->port->private){
+		kfree(serial->port->private);
+		serial->port->private = NULL;
 	}
-}
+} /* ftdi_shutdown */
 
 
 static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
@@ -590,13 +873,17 @@
 	/* FIXME: Flow control might be enabled, so it should be checked -
 	   we have no control of defaults! */
 	/* Turn on RTS and DTR since we are not flow controlling by default */
-	if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+	if (set_dtr(port, HIGH) < 0) {
 		err("%s Error from DTR HIGH urb", __FUNCTION__);
 	}
-	if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+	if (set_rts(port, HIGH) < 0){
 		err("%s Error from RTS HIGH urb", __FUNCTION__);
 	}
 
+	/* Make sure write_urb is initialised since a write_pool is used now */
+	port->write_urb = NULL; /* prevents usbserial.c from trying something silly */
+
+
 	/* Start reading from the device */
 	FILL_BULK_URB(port->read_urb, serial->dev, 
 		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
@@ -606,18 +893,32 @@
 	if (result)
 		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 
+
 	return result;
 } /* ftdi_open */
 
 
+
+/* 
+ * usbserial:__serial_close  only calls ftdi_close if the point is open
+ *
+ *   This only gets called when it is the last close
+ *   
+ *   
+ */
+
 static void ftdi_close (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_close */
-	struct usb_serial *serial = port->serial; /* Checked in usbserial.c */
+	struct usb_serial *serial;
 	unsigned int c_cflag = port->tty->termios->c_cflag;
 	char buf[1];
 
 	dbg("%s", __FUNCTION__);
 
+	serial = get_usb_serial ( port, __FUNCTION__);
+	if (!serial)
+		return;
+
 	if (serial->dev) {
 		if (c_cflag & HUPCL){
 			/* Disable flow control */
@@ -630,115 +931,188 @@
 			}	    
 
 			/* drop DTR */
-			if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+			if (set_dtr(port, LOW) < 0){
 				err("Error from DTR LOW urb");
 			}
 			/* drop RTS */
-			if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+			if (set_rts(port, LOW) < 0) {
 				err("Error from RTS LOW urb");
 			}	
+			/* shutdown our bulk read */
+			if (port->read_urb) {
+				usb_unlink_urb (port->read_urb);	
+			}
+			/* unlink the running write urbs */
+			
+
 		} /* Note change no line is hupcl is off */
+	} /* if (serial->dev) */
+
 
-		/* shutdown our bulk reads and writes */
-		/* ***CHECK*** behaviour when there is nothing queued */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-	}
 } /* ftdi_close */
 
 
   
-/* The ftdi_sio requires the first byte to have:
+/* The SIO requires the first byte to have:
  *  B0 1
  *  B1 0
  *  B2..7 length of message excluding byte 0
+ *
+ * The new devices do not require this byte
  */
 static int ftdi_write (struct usb_serial_port *port, int from_user,
 			   const unsigned char *buf, int count)
 { /* ftdi_write */
-	struct usb_serial *serial = port->serial;
+	struct usb_serial *serial = get_usb_serial ( port, __FUNCTION__);
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;
-	unsigned char *first_byte = port->write_urb->transfer_buffer;
-	int data_offset ;
+	unsigned char *first_byte;
+	int data_offset ;       /* will be 1 for the SIO and 0 otherwise */
 	int result;
+	int user_bytes_sent = 0 ;   /* amount of user data sent */
+
+	/* Variables for urb pool management */
+	unsigned char *current_position = (unsigned char *)buf;
+	int i; 
+	struct urb *urb; /* pointer to urb from urb pool */
+	unsigned long flags;
+	/* end of urb pool management */
+	
 	
 	dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
 
 	if (count == 0) {
 		err("write request of 0 bytes");
-		return 0;
+		goto exit;
 	}
 	
 	data_offset = priv->write_offset;
         dbg("data_offset set to %d",data_offset);
 
-	if (port->write_urb->status == -EINPROGRESS) {
-		dbg("%s - already writing", __FUNCTION__);
-		return (0);
-	}		
-
-	count += data_offset;
-	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
-	/* Copy in the data to send */
-	if (from_user) {
-		if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
-				   buf, count - data_offset )){
-			return -EFAULT;
+	while (count > 0) {
+		/* urb_byte_count = user_byte_count + data_offset */
+		int urb_byte_count;  /* Number of bytes of URB data   */
+		int user_byte_count; /* Number of bytes of user data */
+
+		/* Find a free urb in the list */
+		urb = NULL;
+
+		spin_lock_irqsave (&(priv->write_urb_pool_lock), flags) ; 
+
+		for (i = 0 ; i < NUM_URBS; i++) {
+			if (priv->write_urb_pool[i] -> status != -EINPROGRESS) {
+			  urb = priv->write_urb_pool[i];
+			  /* Must make sure another device doesn't grab this */
+			  /* BUT unfortunately the uhci stack errors if it sees this */
+			  /* so have to increase the size of the spin_lock */
+			  /* urb->status = -EINPROGRESS; */
+				break;
+			}
 		}
-	} else {
-		memcpy(port->write_urb->transfer_buffer + data_offset,
-		       buf, count - data_offset );
-	}  
-
-	first_byte = port->write_urb->transfer_buffer;
-	if (data_offset > 0){
-		/* Write the control byte at the front of the packet*/
-		*first_byte = 1 | ((count-data_offset) << 2) ; 
-	}
 
-	dbg("%s Bytes: %d, First Byte: 0x%02x", __FUNCTION__,count, first_byte[0]);
-	usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
+
+		if (urb == NULL) {
+		        spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+			dbg("%s - no more free urbs", __FUNCTION__);
+			goto exit;
+		}
+
+		/* Allocate memory for the urb if necessary */
+		if (urb->transfer_buffer == NULL) {
+			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+			if (urb->transfer_buffer == NULL) {
+				spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+				err("%s ran out of kernel memory for urb ...", __FUNCTION__);
+				goto exit;
+			}
+		}
+		
+		/* The original sio needs the first byte to contain the bytecount 
+		 * so the urb may be one byte bigger than the user data 
+		 */
+		urb_byte_count = min (count + data_offset, URB_TRANSFER_BUFFER_SIZE);
+		user_byte_count = urb_byte_count - data_offset; 
+
+		/* Copy in the data to send */
+		if (from_user) {
+			if (copy_from_user(urb->transfer_buffer + data_offset,
+					   current_position, user_byte_count )){
+				spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+				return -EFAULT;
+			}
+		} else {
+			memcpy(urb->transfer_buffer + data_offset,
+			       current_position, user_byte_count );
+		}  
+
+		first_byte = urb->transfer_buffer;
+		if (data_offset > 0){
+			/* Write the control byte at the front of the packet*/
+			*first_byte = 1 | ((user_byte_count) << 2) ; 
+			dbg("%s Bytes: %d, First Byte: 0x%02x", __FUNCTION__,count, first_byte[0]);
+		}
 		
-	/* send the data out the bulk port */
-	FILL_BULK_URB(port->write_urb, serial->dev, 
-		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
-		      port->write_urb->transfer_buffer, count,
-		      ftdi_write_bulk_callback, port);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, urb_byte_count, first_byte);
 		
-	result = usb_submit_urb(port->write_urb);
-	if (result) {
-		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
-		return 0;
-	}
+		/* fill the buffer and send it */
+		FILL_BULK_URB(urb, serial->dev, 
+			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+			      urb->transfer_buffer, urb_byte_count,
+			      ftdi_write_bulk_callback, port);
+		urb->transfer_flags |= USB_QUEUE_BULK;
+		
+		result = usb_submit_urb(urb);
+		if (result) {
+			spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+			user_bytes_sent = result;
+			goto exit;
+		}
+		spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+		/* house keeping */
+		current_position += user_byte_count;
+		user_bytes_sent += user_byte_count;
+		count -= user_byte_count;
+		
+	} /* while  count > 0 */
+
+ exit:
+
+	dbg("%s write returning: %d", __FUNCTION__, user_bytes_sent);
+	return user_bytes_sent;
 
-	dbg("%s write returning: %d", __FUNCTION__, count - data_offset);
-	return (count - data_offset);
 } /* ftdi_write */
 
 
+/* This function may get called when the device is closed */
+
 static void ftdi_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
 	dbg("%s", __FUNCTION__);
 
-	if (port_paranoia_check (port, "ftdi_write_bulk_callback")) {
+	if (port_paranoia_check (port, __FUNCTION__))
 		return;
-	}
-	
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "ftdi_write_bulk_callback")) {
-		return;
-	}
 	
 	if (urb->status) {
 		dbg("nonzero write bulk status received: %d", urb->status);
 		return;
 	}
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+
+	if (!serial) {
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
+		return;
+	}
+
+	/* Have to check for validity of queueing up the tasks */
+	dbg("%s - port->open_count = %d", __FUNCTION__, port->open_count);
+
+ 	if (port->open_count > 0){
+		queue_task(&port->tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	} 
 
 	return;
 } /* ftdi_write_bulk_callback */
@@ -747,22 +1121,59 @@
 static int ftdi_write_room( struct usb_serial_port *port )
 {
 	struct ftdi_private *priv = (struct ftdi_private *)port->private;
-	int room;
+	int room = 0;
+	int i;
+	unsigned long flags;
 
-	if ( port->write_urb->status == -EINPROGRESS) {
-		/* There is a race here with the _write routines but it won't hurt */
-		room = 0;
-	} else { 
-		room = port->bulk_out_size - priv->write_offset;
+
+	spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+	for (i = 0; i < NUM_URBS; i++) {
+		if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+			room += URB_TRANSFER_BUFFER_SIZE - priv->write_offset;
+		}
 	}
+	
+	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+	dbg("%s - returns %d", __FUNCTION__, room);	
 	return(room);
 } /* ftdi_write_room */
 
 
+static int ftdi_chars_in_buffer (struct usb_serial_port *port)
+{ /* ftdi_chars_in_buffer */
+	unsigned long flags;
+	int i;
+	int chars = 0;
+	struct ftdi_private *priv = (struct ftdi_private *)port->private;
+	int data_offset = priv->write_offset;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+	/* tally up the number of bytes waiting */
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += URB_TRANSFER_BUFFER_SIZE - data_offset;
+		}
+	}
+
+	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+	dbg("%s - returns %d", __FUNCTION__, chars);
+
+	return (chars);
+
+} /* ftdi_chars_in_buffer */
+
+
+
 static void ftdi_read_bulk_callback (struct urb *urb)
 { /* ftdi_read_bulk_callback */
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct usb_serial *serial;
+	struct usb_serial *serial = get_usb_serial(port,__FUNCTION__);
        	struct tty_struct *tty = port->tty ;
 	struct ftdi_private *priv = (struct ftdi_private *) port->private;
 	char error_flag;
@@ -772,27 +1183,36 @@
 	int i;
 	int result;
 
-	dbg("%s - port %d", __FUNCTION__, port->number);
+	dbg("%s", __FUNCTION__);
 
-	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
+	if (port_paranoia_check (port, __FUNCTION__)) {
 		return;
 	}
+	if (port->open_count <= 0)
+		return;
 
-	serial = port->serial;
-	if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
+	if (!serial){
+		dbg("%s - bad serial pointer - exiting",__FUNCTION__);
+		return;
+	}
+	
+	if (!tty) {
+		dbg("%s - bad tty pointer - exiting",__FUNCTION__);
 		return;
 	}
 
+
 	if (urb->status) {
 		/* This will happen at close every time so it is a dbg not an err */
-		dbg("nonzero read bulk status received: %d", urb->status);
+		dbg("(this is ok on close) nonzero read bulk status received: %d", urb->status);
 		return;
 	}
 
+        /* The first two bytes of every read packet are status */
 	if (urb->actual_length > 2) {
 		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 	} else {
-                dbg("Just status 0o%03o0o%03o",data[0],data[1]);
+                dbg("Status only: %03oo %03oo",data[0],data[1]);
         }
 
 
@@ -847,8 +1267,6 @@
 			tty_insert_flip_char(tty, data[i], error_flag);
 		}
 	  	tty_flip_buffer_push(tty);
-
-
 	} 
 
 #ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
@@ -873,15 +1291,18 @@
 	}
 #endif
 
-	/* Continue trying to always read  */
-	FILL_BULK_URB(port->read_urb, serial->dev, 
-		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-		      ftdi_read_bulk_callback, port);
-
-	result = usb_submit_urb(port->read_urb);
-	if (result)
-		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+	/* if the port is closed stop trying to read */
+	if (port->open_count > 0){
+		/* Continue trying to always read  */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+			      ftdi_read_bulk_callback, port);
+
+		result = usb_submit_urb(port->read_urb);
+		if (result)
+			err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
+	}
 
 	return;
 } /* ftdi_read_bulk_callback */
@@ -985,10 +1406,10 @@
 			err("%s error from disable flowcontrol urb", __FUNCTION__);
 		}	    
 		/* Drop RTS and DTR */
-		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
+		if (set_dtr(port, LOW) < 0){
 			err("%s Error from DTR LOW urb", __FUNCTION__);
 		}
-		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
+		if (set_rts(port, LOW) < 0){
 			err("%s Error from RTS LOW urb", __FUNCTION__);
 		}	
 		
@@ -1060,6 +1481,7 @@
 			}
 			break;
 		case FT8U232AM:
+		case FT232BM:
 			/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
 			   format as the data returned from the in point */
 			if ((ret = usb_control_msg(serial->dev, 
@@ -1081,7 +1503,8 @@
 		return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
 				(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
 				(buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
-				(buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0),
+				(buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0) |
+				priv->last_dtr_rts,
 				(unsigned long *) arg);
 		break;
 
@@ -1090,13 +1513,16 @@
 		if (get_user(mask, (unsigned long *) arg))
 			return -EFAULT;
 		urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
-		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+		if ((ret = set_dtr(port, urb_value)) < 0){
 			err("Error from DTR set urb (TIOCMSET)");
+			return(ret);
 		}
 		urb_value = ((mask & TIOCM_RTS) ? HIGH : LOW);
-		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+		if ((ret = set_rts(port, urb_value)) < 0){
 			err("Error from RTS set urb (TIOCMSET)");
-		}	
+			return(ret);
+		}
+		return(0);
 		break;
 					
 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
@@ -1104,43 +1530,37 @@
  	        if (get_user(mask, (unsigned long *) arg))
 			return -EFAULT;
   	        if (mask & TIOCM_DTR){
-			if ((ret = set_dtr(serial->dev, 
-					   usb_sndctrlpipe(serial->dev, 0),
-					   HIGH)) < 0) {
+			if ((ret = set_dtr(port, HIGH)) < 0) {
 				err("Urb to set DTR failed");
 				return(ret);
 			}
 		}
 		if (mask & TIOCM_RTS) {
-			if ((ret = set_rts(serial->dev, 
-					   usb_sndctrlpipe(serial->dev, 0),
-					   HIGH)) < 0){
+			if ((ret = set_rts(port, HIGH)) < 0){
 				err("Urb to set RTS failed");
 				return(ret);
 			}
 		}
-					break;
+		return(0);
+		break;
 
 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
 		dbg("%s TIOCMBIC", __FUNCTION__);
  	        if (get_user(mask, (unsigned long *) arg))
 			return -EFAULT;
   	        if (mask & TIOCM_DTR){
-			if ((ret = set_dtr(serial->dev, 
-					   usb_sndctrlpipe(serial->dev, 0),
-					   LOW)) < 0){
+			if ((ret = set_dtr(port, LOW)) < 0){
 				err("Urb to unset DTR failed");
 				return(ret);
 			}
 		}	
 		if (mask & TIOCM_RTS) {
-			if ((ret = set_rts(serial->dev, 
-					   usb_sndctrlpipe(serial->dev, 0),
-					   LOW)) < 0){
+			if ((ret = set_rts(port, LOW)) < 0){
 				err("Urb to unset RTS failed");
 				return(ret);
 			}
 		}
+		return(0);
 		break;
 
 		/*
@@ -1195,25 +1615,58 @@
 				 */
 			}
 		}
-		/* NOTREACHED */
-
+		return(0);
+		break;
 	default:
-	  /* This is not an error - turns out the higher layers will do 
-	   *  some ioctls itself (see comment above)
- 	   */
-		dbg("%s arg not supported - it was 0x%04x", __FUNCTION__,cmd);
-		return(-ENOIOCTLCMD);
 		break;
+		
 	}
-	return 0;
+
+
+	/* This is not necessarily an error - turns out the higher layers will do 
+	 *  some ioctls itself (see comment above)
+	 */
+	dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
+
+	return(-ENOIOCTLCMD);
 } /* ftdi_ioctl */
 
 
+static void ftdi_throttle (struct usb_serial_port *port)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+	usb_unlink_urb (port->read_urb);
+}
+
+
+static void ftdi_unthrottle (struct usb_serial_port *port)
+{
+	int result;
+	struct usb_serial *serial = port->serial;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	port->read_urb->dev = serial->dev;
+
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ftdi_read_bulk_callback, port);
+
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+}
+
 static int __init ftdi_init (void)
 {
+
 	dbg("%s", __FUNCTION__);
 	usb_serial_register (&ftdi_SIO_device);
 	usb_serial_register (&ftdi_8U232AM_device);
+	usb_serial_register (&ftdi_FT232BM_device);
+
+
 	info(DRIVER_VERSION ":" DRIVER_DESC);
 	return 0;
 }
@@ -1221,9 +1674,13 @@
 
 static void __exit ftdi_exit (void)
 {
+
 	dbg("%s", __FUNCTION__);
-	usb_serial_deregister (&ftdi_SIO_device);
+
+	usb_serial_deregister (&ftdi_FT232BM_device);
 	usb_serial_deregister (&ftdi_8U232AM_device);
+	usb_serial_deregister (&ftdi_SIO_device);
+
 }
 
 
diff -urN linux-2.4.21-pre7/drivers/usb/serial/ftdi_sio.h linux-2.4.21-rc1/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.21-pre7/drivers/usb/serial/ftdi_sio.h	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/serial/ftdi_sio.h	2003-04-21 11:48:51.000000000 -0700
@@ -14,20 +14,39 @@
  * of the protocol required to talk to the device and ongoing assistence
  * during development.
  *
- * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the 
+ * Bill Ryder - bryder@sgi.com formerly of Silicon Graphics, Inc.- wrote the 
  * FTDI_SIO implementation.
  *
- * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
- * from Rudolf Gugler
  */
 
 #define FTDI_VID	0x0403	/* Vendor Id */
 #define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX  */
 #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
-#define FTDI_RELAIS_PID	0xFA10  /* Relais device from Rudolf Gugler */
 #define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
 #define FTDI_NF_RIC_PID	0x0001	/* Product Id */
 
+
+/* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
+/* they use the ftdi chipset for the USB interface and the vendor id is the same */
+#define FTDI_XF_634_PID  0xFC09	/* Four line device */
+#define FTDI_XF_632_PID  0xFC08	/* Two line device */
+
+
+/*
+ * The following are the values for the Matrix Orbital LCD displays,
+ * which are the FT232BM ( similar to the 8U232AM )
+ */
+#define FTDI_MTXORB_VID                FTDI_VID        /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_0_PID      0xFA00  /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_1_PID      0xFA01  /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_2_PID      0xFA02  /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_3_PID      0xFA03  /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_4_PID      0xFA04  /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_5_PID      0xFA05  /* Matrix Orbital Product Id */
+#define FTDI_MTXORB_6_PID      0xFA06  /* Matrix Orbital Product Id */
+
+
+/* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
 #define FTDI_SIO_SET_FLOW_CTRL	2 /* Set flow control register */
@@ -105,14 +124,37 @@
  *   automagically re-encode the resulting value to take fractions into consideration.
  * As all values are integers, some bit twiddling is in order:
  *   BaudDivisor = (BaseClock / 16 / BaudRate) |
- *   (((BaseClock / 2 / BaudRate) & 2) ? 0x8000 : 0) | // 0.25
- *   (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 : 0) | // 0.5
- *   (((BaseClock / 2 / BaudRate) & 0x7) == 1 ? 0xc000) // 0.125 - this line due to funny encoding only
+ *   (((BaseClock / 2 / BaudRate) & 4) ? 0x4000    // 0.5
+ *    : ((BaseClock / 2 / BaudRate) & 2) ? 0x8000  // 0.25
+ *    : ((BaseClock / 2 / BaudRate) & 1) ? 0xc000  // 0.125
+ *    : 0)
+ *
+ * For the FT232BM, a 17th divisor bit was introduced to encode the multiples
+ * of 0.125 missing from the FT8U232AM.  Bits 16 to 14 are coded as follows
+ * (the first four codes are the same as for the FT8U232AM, where bit 16 is
+ * always 0):
+ *   000 - add .000 to divisor
+ *   001 - add .500 to divisor
+ *   010 - add .250 to divisor
+ *   011 - add .125 to divisor
+ *   100 - add .375 to divisor
+ *   101 - add .625 to divisor
+ *   110 - add .750 to divisor
+ *   111 - add .875 to divisor
+ * Bits 15 to 0 of the 17-bit divisor are placed in the urb value.  Bit 16 is 
+ * placed in bit 0 of the urb index.
+ *
+ * Note that there are a couple of special cases to support the highest baud
+ * rates.  If the calculated divisor value is 1, this needs to be replaced with
+ * 0.  Additionally for the FT232BM, if the calculated divisor value is 0x4001
+ * (1.5), this needs to be replaced with 0x0001 (1) (but this divisor value is
+ * not supported by the FT8U232AM).
  */
 
 typedef enum {
 	SIO = 1,
 	FT8U232AM = 2,
+	FT232BM = 3,
 } ftdi_chip_type_t;
 
 typedef enum {
diff -urN linux-2.4.21-pre7/drivers/usb/serial/io_edgeport.c linux-2.4.21-rc1/drivers/usb/serial/io_edgeport.c
--- linux-2.4.21-pre7/drivers/usb/serial/io_edgeport.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/serial/io_edgeport.c	2003-04-21 11:48:51.000000000 -0700
@@ -25,6 +25,10 @@
  *
  * Version history:
  * 
+ * 2003_04_03 al borchers
+ *  - fixed a bug (that shows up with dosemu) where the tty struct is
+ *    used in a callback after it has been freed
+ *
  * 2.3 2002_03_08 greg kroah-hartman
  *	- fixed bug when multiple devices were attached at the same time.
  *
@@ -895,7 +899,7 @@
 
 	tty = edge_port->port->tty;
 
-	if (tty) {
+	if (tty && edge_port->open) {
 		/* let the tty driver wakeup if it has a special write_wakeup function */
 		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
 			(tty->ldisc.write_wakeup)(tty);
@@ -952,7 +956,7 @@
 	tty = edge_port->port->tty;
 
 	/* tell the tty driver that something has changed */
-	if (tty)
+	if (tty && edge_port->open)
 		wake_up_interruptible(&tty->write_wait);
 
 	/* we have completed the command */
diff -urN linux-2.4.21-pre7/drivers/usb/serial/ipaq.c linux-2.4.21-rc1/drivers/usb/serial/ipaq.c
--- linux-2.4.21-pre7/drivers/usb/serial/ipaq.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/serial/ipaq.c	2003-04-21 11:48:51.000000000 -0700
@@ -131,6 +131,7 @@
 	{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) },
 	{ USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) },
 	{ USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) },
+	{ USB_DEVICE(ASUS_VENDOR_ID, ASUS_A600_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -urN linux-2.4.21-pre7/drivers/usb/serial/ipaq.h linux-2.4.21-rc1/drivers/usb/serial/ipaq.h
--- linux-2.4.21-pre7/drivers/usb/serial/ipaq.h	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/serial/ipaq.h	2003-04-21 11:48:51.000000000 -0700
@@ -77,6 +77,9 @@
 #define NEC_VENDOR_ID		0x0409
 #define NEC_PRODUCT_ID		0x00d5
 
+#define ASUS_VENDOR_ID		0x0b05
+#define ASUS_A600_PRODUCT_ID	0x4201
+
 /*
  * Since we can't queue our bulk write urbs (don't know why - it just
  * doesn't work), we can send down only one write urb at a time. The simplistic
diff -urN linux-2.4.21-pre7/drivers/usb/storage/unusual_devs.h linux-2.4.21-rc1/drivers/usb/storage/unusual_devs.h
--- linux-2.4.21-pre7/drivers/usb/storage/unusual_devs.h	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/storage/unusual_devs.h	2003-04-21 11:48:51.000000000 -0700
@@ -285,6 +285,15 @@
 		"USB Hard Disk",
 		US_SC_RBC, US_PR_CB, NULL, 0 ), 
 
+/* Enable USB storage access to the MMC/SD and CompactFlash cards inside the
+ * Pontis SP600 MP3 player (entry found on http://www.pontis.de/).
+ */
+UNUSUAL_DEV(  0x09bc, 0x0003, 0x0000, 0x9999,
+		"PONTIS",
+		"SP600",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP ),
+
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0110,
                 "In-System",
diff -urN linux-2.4.21-pre7/drivers/usb/usb.c linux-2.4.21-rc1/drivers/usb/usb.c
--- linux-2.4.21-pre7/drivers/usb/usb.c	2003-04-21 11:48:33.000000000 -0700
+++ linux-2.4.21-rc1/drivers/usb/usb.c	2003-04-21 11:48:52.000000000 -0700
@@ -1005,7 +1005,7 @@
 	struct urb *urb;
 
 	urb = (struct urb *)kmalloc(sizeof(struct urb) + iso_packets * sizeof(struct iso_packet_descriptor),
-	      in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+			/* pessimize to prevent deadlocks */ GFP_ATOMIC);
 	if (!urb) {
 		err("alloc_urb: kmalloc failed");
 		return NULL;
diff -urN linux-2.4.21-pre7/drivers/video/modedb.c linux-2.4.21-rc1/drivers/video/modedb.c
--- linux-2.4.21-pre7/drivers/video/modedb.c	2001-12-21 09:41:55.000000000 -0800
+++ linux-2.4.21-rc1/drivers/video/modedb.c	2003-04-21 11:48:52.000000000 -0700
@@ -16,6 +16,7 @@
 #include <linux/fb.h>
 #include <linux/console_struct.h>
 #include <linux/sched.h>
+#include <video/fbcon.h>
 
 
 #undef DEBUG
@@ -257,28 +258,6 @@
     }
 }
 
-static int PROC_CONSOLE(const struct fb_info *info)
-{
-	int fgc;
-	
-	if (info->display_fg != NULL)
-		fgc = info->display_fg->vc_num;
-	else
-		return -1;
-		
-	if (!current->tty)
-		return fgc;
-
-	if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
-		/* XXX Should report error here? */
-		return fgc;
-
-	if (MINOR(current->tty->device) < 1)
-		return fgc;
-
-	return MINOR(current->tty->device) - 1;
-}
-
 
 /**
  *	__fb_try_mode - test a video mode
diff -urN linux-2.4.21-pre7/fs/ext2/balloc.c linux-2.4.21-rc1/fs/ext2/balloc.c
--- linux-2.4.21-pre7/fs/ext2/balloc.c	2002-02-25 11:38:08.000000000 -0800
+++ linux-2.4.21-rc1/fs/ext2/balloc.c	2003-04-21 11:48:52.000000000 -0700
@@ -269,7 +269,8 @@
 	}
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
-	if (block < le32_to_cpu(es->s_first_data_block) || 
+	if (block < le32_to_cpu(es->s_first_data_block) ||
+	    block + count < block ||
 	    (block + count) > le32_to_cpu(es->s_blocks_count)) {
 		ext2_error (sb, "ext2_free_blocks",
 			    "Freeing blocks not in datazone - "
@@ -302,22 +303,20 @@
 	if (!gdp)
 		goto error_return;
 
-	if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
-	    in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
-	    in_range (block, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext2_sb.s_itb_per_group) ||
-	    in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext2_sb.s_itb_per_group))
-		ext2_error (sb, "ext2_free_blocks",
-			    "Freeing blocks in system zones - "
-			    "Block = %lu, count = %lu",
-			    block, count);
+	for (i = 0; i < count; i++, block++) {
+		if (block == le32_to_cpu(gdp->bg_block_bitmap) ||
+		    block == le32_to_cpu(gdp->bg_inode_bitmap) ||
+		    in_range(block, le32_to_cpu(gdp->bg_inode_table),
+			     EXT2_SB(sb)->s_itb_per_group)) {
+			ext2_error(sb, __FUNCTION__,
+				   "Freeing block in system zone - block = %lu",
+				   block);
+			continue;
+		}
 
-	for (i = 0; i < count; i++) {
 		if (!ext2_clear_bit (bit + i, bh->b_data))
-			ext2_error (sb, "ext2_free_blocks",
-				      "bit already cleared for block %lu",
-				      block + i);
+			ext2_error(sb, __FUNCTION__,
+				   "bit already cleared for block %lu", block);
 		else {
 			DQUOT_FREE_BLOCK(inode, 1);
 			gdp->bg_free_blocks_count =
@@ -336,7 +335,6 @@
 		wait_on_buffer (bh);
 	}
 	if (overflow) {
-		block += count;
 		count = overflow;
 		goto do_more;
 	}
@@ -520,10 +518,14 @@
 	if (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
 	    tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
 	    in_range (tmp, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext2_sb.s_itb_per_group))
+		      EXT2_SB(sb)->s_itb_per_group)) {
 		ext2_error (sb, "ext2_new_block",
-			    "Allocating block in system zone - "
-			    "block = %u", tmp);
+			    "Allocating block in system zone - block = %lu",
+			    tmp);
+		ext2_set_bit(j, bh->b_data);
+		DQUOT_FREE_BLOCK(inode, 1);
+		goto repeat;
+	}
 
 	if (ext2_set_bit (j, bh->b_data)) {
 		ext2_warning (sb, "ext2_new_block",
diff -urN linux-2.4.21-pre7/fs/ext3/balloc.c linux-2.4.21-rc1/fs/ext3/balloc.c
--- linux-2.4.21-pre7/fs/ext3/balloc.c	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-rc1/fs/ext3/balloc.c	2003-04-21 11:48:52.000000000 -0700
@@ -276,7 +276,8 @@
 	}
 	lock_super (sb);
 	es = sb->u.ext3_sb.s_es;
-	if (block < le32_to_cpu(es->s_first_data_block) || 
+	if (block < le32_to_cpu(es->s_first_data_block) ||
+	    block + count < block ||
 	    (block + count) > le32_to_cpu(es->s_blocks_count)) {
 		ext3_error (sb, "ext3_free_blocks",
 			    "Freeing blocks not in datazone - "
@@ -309,17 +310,6 @@
 	if (!gdp)
 		goto error_return;
 
-	if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
-	    in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
-	    in_range (block, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext3_sb.s_itb_per_group) ||
-	    in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext3_sb.s_itb_per_group))
-		ext3_error (sb, "ext3_free_blocks",
-			    "Freeing blocks in system zones - "
-			    "Block = %lu, count = %lu",
-			    block, count);
-
 	/*
 	 * We are about to start releasing blocks in the bitmap,
 	 * so we need undo access.
@@ -345,14 +335,24 @@
 	if (err)
 		goto error_return;
 
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < count; i++, block++) {
+		if (block == le32_to_cpu(gdp->bg_block_bitmap) ||
+		    block == le32_to_cpu(gdp->bg_inode_bitmap) ||
+		    in_range(block, le32_to_cpu(gdp->bg_inode_table),
+			     EXT3_SB(sb)->s_itb_per_group)) {
+			ext3_error(sb, __FUNCTION__,
+				   "Freeing block in system zone - block = %lu",
+				   block);
+			continue;
+		}
+
 		/*
 		 * An HJ special.  This is expensive...
 		 */
 #ifdef CONFIG_JBD_DEBUG
 		{
 			struct buffer_head *debug_bh;
-			debug_bh = sb_get_hash_table(sb, block + i);
+			debug_bh = sb_get_hash_table(sb, block);
 			if (debug_bh) {
 				BUFFER_TRACE(debug_bh, "Deleted!");
 				if (!bh2jh(bitmap_bh)->b_committed_data)
@@ -365,9 +365,8 @@
 #endif
 		BUFFER_TRACE(bitmap_bh, "clear bit");
 		if (!ext3_clear_bit (bit + i, bitmap_bh->b_data)) {
-			ext3_error (sb, __FUNCTION__,
-				      "bit already cleared for block %lu", 
-				      block + i);
+			ext3_error(sb, __FUNCTION__,
+				   "bit already cleared for block %lu", block);
 			BUFFER_TRACE(bitmap_bh, "bit already cleared");
 		} else {
 			dquot_freed_blocks++;
@@ -415,7 +414,6 @@
 	if (!err) err = ret;
 
 	if (overflow && !err) {
-		block += count;
 		count = overflow;
 		goto do_more;
 	}
@@ -576,6 +574,7 @@
 
 	ext3_debug ("goal=%lu.\n", goal);
 
+repeat:
 	/*
 	 * First, test whether the goal block is free.
 	 */
@@ -684,10 +683,21 @@
 	if (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
 	    tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
 	    in_range (tmp, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext3_sb.s_itb_per_group))
-		ext3_error (sb, "ext3_new_block",
-			    "Allocating block in system zone - "
-			    "block = %u", tmp);
+		      EXT3_SB(sb)->s_itb_per_group)) {
+		ext3_error(sb, __FUNCTION__,
+			   "Allocating block in system zone - block = %u", tmp);
+
+		/* Note: This will potentially use up one of the handle's
+		 * buffer credits.  Normally we have way too many credits,
+		 * so that is OK.  In _very_ rare cases it might not be OK.
+		 * We will trigger an assertion if we run out of credits,
+		 * and we will have to do a full fsck of the filesystem -
+		 * better than randomly corrupting filesystem metadata.
+		 */
+		ext3_set_bit(j, bh->b_data);
+		goto repeat;
+	}
+
 
 	/* The superblock lock should guard against anybody else beating
 	 * us to this point! */
diff -urN linux-2.4.21-pre7/fs/hfs/super.c linux-2.4.21-rc1/fs/hfs/super.c
--- linux-2.4.21-pre7/fs/hfs/super.c	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-rc1/fs/hfs/super.c	2003-04-21 11:48:52.000000000 -0700
@@ -434,6 +434,12 @@
 		goto bail2;
 	}
 
+	if (mdb->attrib & (HFS_SB_ATTRIB_HLOCK | HFS_SB_ATTRIB_SLOCK)) {
+		if (!silent)
+			hfs_warn("hfs_fs: Filesystem is marked locked, mounting read-only.\n");
+		s->s_flags |= MS_RDONLY;
+	}
+
 	HFS_SB(s)->s_mdb = mdb;
 	if (HFS_ITYPE(mdb->next_id) != 0) {
 		hfs_warn("hfs_fs: too many files.\n");
diff -urN linux-2.4.21-pre7/fs/jbd/revoke.c linux-2.4.21-rc1/fs/jbd/revoke.c
--- linux-2.4.21-pre7/fs/jbd/revoke.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/fs/jbd/revoke.c	2003-04-21 11:48:52.000000000 -0700
@@ -136,7 +136,7 @@
 oom:
 	if (!journal_oom_retry)
 		return -ENOMEM;
-	jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n");
+	jbd_debug(1, "ENOMEM in %s, retrying.\n", __FUNCTION__);
 	yield();
 	goto repeat;
 }
diff -urN linux-2.4.21-pre7/fs/reiserfs/journal.c linux-2.4.21-rc1/fs/reiserfs/journal.c
--- linux-2.4.21-pre7/fs/reiserfs/journal.c	2003-04-21 11:48:35.000000000 -0700
+++ linux-2.4.21-rc1/fs/reiserfs/journal.c	2003-04-21 11:48:53.000000000 -0700
@@ -1401,7 +1401,7 @@
 		     *newest_mount_id) ;
       return -1 ;
     }
-    if ( le32_to_cpu(desc->j_len) > sb_journal_trans_max(SB_DISK_SUPER_BLOCK(p_s_sb)) ) {
+    if ( le32_to_cpu(desc->j_len) > JOURNAL_TRANS_MAX ) {
       reiserfs_warning("journal-2018: Bad transaction length %d encountered, ignoring transaction\n", le32_to_cpu(desc->j_len));
       return -1 ;
     }
@@ -1637,11 +1637,9 @@
 }
 static int journal_read(struct super_block *p_s_sb) {
   struct reiserfs_journal_desc *desc ;
-  unsigned long last_flush_trans_id = 0 ;
   unsigned long oldest_trans_id = 0;
   unsigned long oldest_invalid_trans_id = 0 ;
   time_t start ;
-  unsigned long last_flush_start = 0;
   unsigned long oldest_start = 0;
   unsigned long cur_dblock = 0 ;
   unsigned long newest_mount_id = 9 ;
@@ -1671,13 +1669,14 @@
   if (le32_to_cpu(jh->j_first_unflushed_offset) >= 0 && 
       le32_to_cpu(jh->j_first_unflushed_offset) < JOURNAL_BLOCK_COUNT &&
       le32_to_cpu(jh->j_last_flush_trans_id) > 0) {
-    last_flush_start = reiserfs_get_journal_block(p_s_sb) + 
+    oldest_start = reiserfs_get_journal_block(p_s_sb) + 
                        le32_to_cpu(jh->j_first_unflushed_offset) ;
-    last_flush_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) ;
+    oldest_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1;
+    newest_mount_id = le32_to_cpu(jh->j_mount_id);
     reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1153: found in "
                    "header: first_unflushed_offset %d, last_flushed_trans_id "
 		   "%lu\n", le32_to_cpu(jh->j_first_unflushed_offset), 
-		   last_flush_trans_id) ;
+		   le32_to_cpu(jh->j_last_flush_trans_id)) ;
     valid_journal_header = 1 ;
 
     /* now, we try to read the first unflushed offset.  If it is not valid, 
@@ -1690,6 +1689,7 @@
       continue_replay = 0 ;
     }
     brelse(d_bh) ;
+    goto start_log_replay;
   }
 
   if (continue_replay && is_read_only(p_s_sb->s_dev)) {
@@ -1732,17 +1732,13 @@
 	              "newest_mount_id to %d\n", le32_to_cpu(desc->j_mount_id));
       }
       cur_dblock += le32_to_cpu(desc->j_len) + 2 ;
-    } 
-    else {
+    } else {
       cur_dblock++ ;
     }
     brelse(d_bh) ;
   }
-  /* step three, starting at the oldest transaction, replay */
-  if (last_flush_start > 0) {
-    oldest_start = last_flush_start ;
-    oldest_trans_id = last_flush_trans_id + 1 ;
-  } 
+
+start_log_replay:
   cur_dblock = oldest_start ;
   if (oldest_trans_id)  {
     reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1206: Starting replay "
diff -urN linux-2.4.21-pre7/include/asm-i386/highmem.h linux-2.4.21-rc1/include/asm-i386/highmem.h
--- linux-2.4.21-pre7/include/asm-i386/highmem.h	2003-04-21 11:48:35.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-i386/highmem.h	2003-04-21 11:48:54.000000000 -0700
@@ -109,7 +109,7 @@
 static inline void kunmap_atomic(void *kvaddr, enum km_type type)
 {
 #if HIGHMEM_DEBUG
-	unsigned long vaddr = (unsigned long) kvaddr;
+	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
 	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
 	if (vaddr < FIXADDR_START) // FIXME
diff -urN linux-2.4.21-pre7/include/asm-i386/io_apic.h linux-2.4.21-rc1/include/asm-i386/io_apic.h
--- linux-2.4.21-pre7/include/asm-i386/io_apic.h	2003-04-21 11:48:35.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-i386/io_apic.h	2003-04-21 11:48:54.000000000 -0700
@@ -22,9 +22,12 @@
  * The structure of the IO-APIC:
  */
 struct IO_APIC_reg_00 {
-	__u32	__reserved_2	: 24,
+	__u32	__reserved_2	: 14,
+		LTS		:  1,
+		delivery_type	:  1,
+		__reserved_1	:  8,
 		ID		:  4,
-		__reserved_1	:  4;
+		__reserved_0	:  4;
 } __attribute__ ((packed));
 
 struct IO_APIC_reg_01 {
diff -urN linux-2.4.21-pre7/include/asm-m68k/delay.h linux-2.4.21-rc1/include/asm-m68k/delay.h
--- linux-2.4.21-pre7/include/asm-m68k/delay.h	2001-01-04 13:00:55.000000000 -0800
+++ linux-2.4.21-rc1/include/asm-m68k/delay.h	2003-04-21 11:48:57.000000000 -0700
@@ -16,6 +16,7 @@
 }
 
 extern void __bad_udelay(void);
+extern void __bad_ndelay(void);
 
 /*
  * Use only for very small delays ( < 1 msec).  Should probably use a
@@ -39,10 +40,19 @@
 	__const_udelay(usecs * 4295);	/* 2**32 / 1000000 */
 }
 
+static inline void __ndelay(unsigned long nsecs)
+{
+	__const_udelay(nsecs * 5);	/* 2**32 / 1000000000 */
+}
+
 #define udelay(n) (__builtin_constant_p(n) ? \
 	((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 4295)) : \
 	__udelay(n))
 
+#define ndelay(n) (__builtin_constant_p(n) ? \
+	((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5)) : \
+	__ndelay(n))
+
 extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
 {
 	unsigned long tmp;
diff -urN linux-2.4.21-pre7/include/asm-m68k/hdreg.h linux-2.4.21-rc1/include/asm-m68k/hdreg.h
--- linux-2.4.21-pre7/include/asm-m68k/hdreg.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-m68k/hdreg.h	2003-04-21 11:48:57.000000000 -0700
@@ -7,8 +7,6 @@
 #ifndef _M68K_HDREG_H
 #define _M68K_HDREG_H
 
-typedef unsigned int   q40ide_ioreg_t;
-typedef unsigned char * ide_ioreg_t;
-//typedef unsigned long ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* _M68K_HDREG_H */
diff -urN linux-2.4.21-pre7/include/asm-m68k/ide.h linux-2.4.21-rc1/include/asm-m68k/ide.h
--- linux-2.4.21-pre7/include/asm-m68k/ide.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-m68k/ide.h	2003-04-21 11:48:57.000000000 -0700
@@ -50,9 +50,6 @@
 #define MAX_HWIFS	4	/* same as the other archs */
 #endif
 
-/*
- * FIXME: IOPS struct calls needed for taskfile.
- */
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
@@ -69,7 +66,9 @@
  * Set up a hw structure for a specified data port, control port and IRQ.
  * This should follow whatever the default interface uses.
  */
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw,
+					   ide_ioreg_t data_port,
+					   ide_ioreg_t ctrl_port, int *irq)
 {
 	if (data_port || ctrl_port)
 		printk("ide_init_hwif_ports: must not be called\n");
@@ -83,170 +82,94 @@
 {
 }
 
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-#ifdef CONFIG_AMIGA
-	if (MACH_IS_AMIGA)
-		return request_irq(irq, handler, 0, device, dev_id);
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_Q40
-	if (MACH_IS_Q40)
-	  	return request_irq(irq, handler, 0, device, dev_id);
-#endif /* CONFIG_Q40*/
-#ifdef CONFIG_MAC
-	if (MACH_IS_MAC)
-		return request_irq(irq, handler, 0, device, dev_id);
-#endif /* CONFIG_MAC */
-	return 0;
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-#ifdef CONFIG_AMIGA
-	if (MACH_IS_AMIGA)
-		free_irq(irq, dev_id);
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_Q40
-	if (MACH_IS_Q40)
-	  	free_irq(irq, dev_id);
-#endif /* CONFIG_Q40*/
-#ifdef CONFIG_MAC
-	if (MACH_IS_MAC)
-		free_irq(irq, dev_id);
-#endif /* CONFIG_MAC */
-}
-
 /*
- * We should really implement those some day.
- */
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	return 0;
-}
-
-static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
-{
-#ifdef CONFIG_Q40
-        if (MACH_IS_Q40)
-            request_region((q40ide_ioreg_t)from,extent,name);
-#endif
-}
-
-static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_Q40
-        if (MACH_IS_Q40)
-            release_region((q40ide_ioreg_t)from,extent);
-#endif
-}
-
-#undef SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS 0
-
-#undef SUPPORT_VLB_SYNC
-#define SUPPORT_VLB_SYNC 0
-
-/* this definition is used only on startup .. */
-#undef HD_DATA
-#define HD_DATA NULL
-
-
-/*
- * get rid of defs from io.h
- * ide still has some private and conflicting versions
+ * Get rid of defs from io.h - ide has its private and conflicting versions
+ * Since so far no single m68k platform uses ISA/PCI I/O space for IDE, we
+ * always use the `raw' MMIO versions
  */
+#undef inb
+#undef inw
 #undef insw
+#undef inl
 #undef insl
+#undef outb
+#undef outw
 #undef outsw
+#undef outl
 #undef outsl
-
-
-/*
- * define IO method and translation,
- * so far only Q40 has ide-if on ISA
- */
-#ifndef CONFIG_Q40
-
-#define ADDR_TRANS_B(_addr_) (_addr_)
-#define ADDR_TRANS_W(_addr_) (_addr_)
-#define ADDR_TRANS_L(_addr_) (_addr_)
-
-#else
-
-#define ADDR_TRANS_B(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_B(_addr_)) : (_addr_))
-#define ADDR_TRANS_W(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
-#define ADDR_TRANS_L(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_L(_addr_)) : (_addr_))
-#endif
-
-#define HAVE_ARCH_OUT_BYTE 1
-
-#define OUT_BYTE(v,p)	out_8(ADDR_TRANS_B((p)), (v))
-#define OUT_WORD(v,p)	out_be16(ADDR_TRANS_W((p)), (v))
-#define OUT_LONG(v,p)	out_be32(ADDR_TRANS_L((p)), (v))
-
-#define HAVE_ARCH_IN_BYTE 1
-
-#define IN_BYTE(p)	in_8(ADDR_TRANS_B((p)))
-#define IN_WORD(p)	in_be16(ADDR_TRANS_W((p)))
-#define IN_LONG(p)	in_be32(ADDR_TRANS_L((p)))
-
-#define insw(port, buf, nr) raw_insw(ADDR_TRANS_W(port), buf, nr)
-#define outsw(port, buf, nr) raw_outsw(ADDR_TRANS_W(port), buf, nr)
-
-#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
-#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
-
-
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+
+#define inb				in_8
+#define inw				in_be16
+#define insw(port, addr, n)		raw_insw((u16 *)port, addr, n)
+#define inl				in_be32
+#define insl(port, addr, n)		raw_insl((u32 *)port, addr, n)
+#define outb(val, port)			out_8(port, val)
+#define outw(val, port)			out_be16(port, val)
+#define outsw(port, addr, n)		raw_outsw((u16 *)port, addr, n)
+#define outl(val, port)			out_be32(port, val)
+#define outsl(port, addr, n)		raw_outsl((u32 *)port, addr, n)
+#define readb				in_8
+#define readw				in_be16
+#define __ide_mm_insw(port, addr, n)	raw_insw((u16 *)port, addr, n)
+#define readl				in_be32
+#define __ide_mm_insl(port, addr, n)	raw_insl((u32 *)port, addr, n)
+#define writeb(val, port)		out_8(port, val)
+#define writew(val, port)		out_be16(port, val)
+#define __ide_mm_outsw(port, addr, n)	raw_outsw((u16 *)port, addr, n)
+#define writel(val, port)		out_be32(port, val)
+#define __ide_mm_outsl(port, addr, n)	raw_outsl((u32 *)port, addr, n)
 #if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-
-#define insl_swapw(data_reg, buffer, wcount) \
-    insw_swapw(data_reg, buffer, (wcount)<<1)
-#define outsl_swapw(data_reg, buffer, wcount) \
-    outsw_swapw(data_reg, buffer, (wcount)<<1)
-
-#define insw_swapw(port, buf, nr) raw_insw_swapw(ADDR_TRANS_W(port), buf, nr)
-#define outsw_swapw(port, buf, nr) raw_outsw_swapw(ADDR_TRANS_W(port),buf,nr)
-
-#endif /* CONFIG_ATARI || CONFIG_Q40 */
+#define insw_swapw(port, addr, n)	raw_insw_swapw((u16 *)port, addr, n)
+#define outsw_swapw(port, addr, n)	raw_outsw_swapw((u16 *)port, addr, n)
+#endif
 
 
-/* Q40 and Atari have byteswapped IDE bus and since many interesting
+/* Q40 and Atari have byteswapped IDE busses and since many interesting
  * values in the identification string are text, chars and words they
- * happened to be almost correct without swapping.. However *_capacity 
+ * happened to be almost correct without swapping.. However *_capacity
  * is needed for drives over 8 GB. RZ */
 #if defined(CONFIG_Q40) || defined(CONFIG_ATARI)
 #define M68K_IDE_SWAPW  (MACH_IS_Q40 || MACH_IS_ATARI)
 #endif
 
-#ifdef CONFIG_ATARI
-#define IDE_ARCH_LOCK 1
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+#define IDE_ARCH_LOCK
+
+extern int falconide_intr_lock;
 
-static __inline__ void ide_release_lock (int *ide_lock)
+static __inline__ void ide_release_lock(void)
 {
 	if (MACH_IS_ATARI) {
-		if (*ide_lock == 0) {
+		if (falconide_intr_lock == 0) {
 			printk("ide_release_lock: bug\n");
 			return;
 		}
-		*ide_lock = 0;
+		falconide_intr_lock = 0;
 		stdma_release();
 	}
 }
 
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
+static __inline__ void ide_get_lock(void (*handler)(int, void *, struct pt_regs *), void *data)
 {
 	if (MACH_IS_ATARI) {
-		if (*ide_lock == 0) {
+		if (falconide_intr_lock == 0) {
 			if (in_interrupt() > 0)
 				panic( "Falcon IDE hasn't ST-DMA lock in interrupt" );
 			stdma_lock(handler, data);
-			*ide_lock = 1;
+			falconide_intr_lock = 1;
 		}
 	}
 }
-#endif /* CONFIG_ATARI */
+#endif /* CONFIG_BLK_DEV_FALCON_IDE */
 
-#endif /* __KERNEL__ */
+#define IDE_ARCH_ACK_INTR
+#define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
 
+#endif /* __KERNEL__ */
 #endif /* _M68K_IDE_H */
diff -urN linux-2.4.21-pre7/include/asm-m68k/io.h linux-2.4.21-rc1/include/asm-m68k/io.h
--- linux-2.4.21-pre7/include/asm-m68k/io.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-m68k/io.h	2003-04-21 11:48:57.000000000 -0700
@@ -120,66 +120,66 @@
  * be compiled in so the case statement will be optimised away
  */
 
-static inline unsigned long isa_itb(long addr)
+static inline unsigned char *isa_itb(long addr)
 {
   switch(ISA_TYPE)
     {
 #ifdef CONFIG_Q40
-    case Q40_ISA: return Q40_ISA_IO_B(addr);
+    case Q40_ISA: return (unsigned char *)Q40_ISA_IO_B(addr);
 #endif
 #ifdef CONFIG_GG2
-    case GG2_ISA: return GG2_ISA_IO_B(addr);
+    case GG2_ISA: return (unsigned char *)GG2_ISA_IO_B(addr);
 #endif
 #ifdef CONFIG_AMIGA_PCMCIA
-    case AG_ISA: return AG_ISA_IO_B(addr);
+    case AG_ISA: return (unsigned char *)AG_ISA_IO_B(addr);
 #endif
     default: return 0; /* avoid warnings, just in case */
     }
 }
-static inline unsigned long isa_itw(long addr)
+static inline unsigned short *isa_itw(long addr)
 {
   switch(ISA_TYPE)
     {
 #ifdef CONFIG_Q40
-    case Q40_ISA: return Q40_ISA_IO_W(addr);
+    case Q40_ISA: return (unsigned short *)Q40_ISA_IO_W(addr);
 #endif
 #ifdef CONFIG_GG2
-    case GG2_ISA: return GG2_ISA_IO_W(addr);
+    case GG2_ISA: return (unsigned short *)GG2_ISA_IO_W(addr);
 #endif
 #ifdef CONFIG_AMIGA_PCMCIA
-    case AG_ISA: return AG_ISA_IO_W(addr);
+    case AG_ISA: return (unsigned short *)AG_ISA_IO_W(addr);
 #endif
     default: return 0; /* avoid warnings, just in case */
     }
 }
-static inline unsigned long isa_mtb(long addr)
+static inline unsigned char *isa_mtb(long addr)
 {
   switch(ISA_TYPE)
     {
 #ifdef CONFIG_Q40
-    case Q40_ISA: return Q40_ISA_MEM_B(addr);
+    case Q40_ISA: return (unsigned char *)Q40_ISA_MEM_B(addr);
 #endif
 #ifdef CONFIG_GG2
-    case GG2_ISA: return GG2_ISA_MEM_B(addr);
+    case GG2_ISA: return (unsigned char *)GG2_ISA_MEM_B(addr);
 #endif
 #ifdef CONFIG_AMIGA_PCMCIA
-    case AG_ISA: return addr;
+    case AG_ISA: return (unsigned char *)addr;
 #endif
     default: return 0; /* avoid warnings, just in case */
     }
 }
-static inline unsigned long isa_mtw(long addr)
+static inline unsigned short *isa_mtw(long addr)
 {
   switch(ISA_TYPE)
     {
 #ifdef CONFIG_Q40
-    case Q40_ISA: return Q40_ISA_MEM_W(addr);
+    case Q40_ISA: return (unsigned short *)Q40_ISA_MEM_W(addr);
 #endif
 #ifdef CONFIG_GG2
-    case GG2_ISA: return GG2_ISA_MEM_W(addr);
+    case GG2_ISA: return (unsigned short *)GG2_ISA_MEM_W(addr);
 #endif
 #ifdef CONFIG_AMIGA_PCMCIA
-    case AG_ISA: return addr;
+    case AG_ISA: return (unsigned short *)addr;
 #endif
     default: return 0; /* avoid warnings, just in case */
     }
@@ -255,7 +255,7 @@
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
 
-/* those can be defined for both ISA and PCI - it wont work though */
+/* those can be defined for both ISA and PCI - it won't work though */
 #define readb(addr)       in_8(addr)
 #define readw(addr)       in_le16(addr)
 #define writeb(val,addr)  out_8((addr),(val))
diff -urN linux-2.4.21-pre7/include/asm-m68k/machdep.h linux-2.4.21-rc1/include/asm-m68k/machdep.h
--- linux-2.4.21-pre7/include/asm-m68k/machdep.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-m68k/machdep.h	2003-04-21 11:48:57.000000000 -0700
@@ -5,6 +5,7 @@
 struct kbd_repeat;
 struct mktime;
 struct rtc_time;
+struct rtc_pll_info;
 struct gendisk;
 struct buffer_head;
 
@@ -29,6 +30,9 @@
 extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
 			   int *min, int *sec);
 extern int (*mach_hwclk)(int, struct rtc_time*);
+extern unsigned int (*mach_get_ss)(void);
+extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
+extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_clock_mmss)(unsigned long);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
diff -urN linux-2.4.21-pre7/include/asm-m68k/page.h linux-2.4.21-rc1/include/asm-m68k/page.h
--- linux-2.4.21-pre7/include/asm-m68k/page.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-m68k/page.h	2003-04-21 11:48:57.000000000 -0700
@@ -127,6 +127,7 @@
 
 #ifndef CONFIG_SUN3
 
+#define WANT_PAGE_VIRTUAL
 #ifdef CONFIG_SINGLE_MEMORY_CHUNK
 extern unsigned long m68k_memoffset;
 
diff -urN linux-2.4.21-pre7/include/asm-m68k/raw_io.h linux-2.4.21-rc1/include/asm-m68k/raw_io.h
--- linux-2.4.21-pre7/include/asm-m68k/raw_io.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-m68k/raw_io.h	2003-04-21 11:48:57.000000000 -0700
@@ -52,208 +52,290 @@
 #define raw_outw(val,port) out_be16((port),(val))
 #define raw_outl(val,port) out_be32((port),(val))
 
-#define raw_insb(port, buf, len) ({	   \
-	volatile unsigned char *_port = (volatile unsigned char *) (port);   \
-        unsigned char *_buf =(unsigned char *)(buf);	   \
-        unsigned int  _i,_len=(unsigned int)(len);	   \
-        for(_i=0; _i< _len; _i++)  \
-           *_buf++=in_8(_port);      \
-  })
-
-#define raw_outsb(port, buf, len) ({	   \
-	volatile unsigned char *_port = (volatile unsigned char *) (port);   \
-        unsigned char *_buf =(unsigned char *)(buf);	   \
-        unsigned int  _i,_len=(unsigned int)(len);	   \
-        for( _i=0; _i< _len; _i++)  \
-           out_8(_port,*_buf++);      \
-  })
- 
-
-#define raw_insw(port, buf, nr) ({				\
-	volatile unsigned char *_port = (volatile unsigned char *) (port);	\
-	unsigned char *_buf = (unsigned char *)(buf);			\
-	unsigned int _nr = (unsigned int)(nr);					\
-	unsigned long _tmp;				\
-							\
-	if (_nr & 15) {					\
-		_tmp = (_nr & 15) - 1;			\
-		asm volatile (				\
-			"1: movew %2@,%0@+; dbra %1,1b"	\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-	if (_nr >> 4) {					\
-		_tmp = (_nr >> 4) - 1;			\
-		asm volatile (				\
-			"1: "				\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"movew %2@,%0@+; "		\
-			"dbra %1,1b"			\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-})
-
-#define raw_outsw(port, buf, nr) ({				\
-	volatile unsigned char *_port = (volatile unsigned char *) (port);	\
-	unsigned char *_buf = (unsigned char *)(buf);			\
-	unsigned int _nr = (unsigned int)(nr);					\
-	unsigned long _tmp;				\
-							\
-	if (_nr & 15) {					\
-		_tmp = (_nr & 15) - 1;			\
-		asm volatile (				\
-			"1: movew %0@+,%2@; dbra %1,1b"	\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-	if (_nr >> 4) {					\
-		_tmp = (_nr >> 4) - 1;			\
-		asm volatile (				\
-			"1: "				\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"movew %0@+,%2@; "		\
-			"dbra %1,1b"	   		\
-			: "=a" (_buf), "=d" (_tmp)	\
-			: "a" (_port), "0" (_buf),	\
-			  "1" (_tmp));			\
-	}						\
-})
-
-
-#define raw_insw_swapw(port, buf, nr) \
-({  if ((nr) % 8) \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 dbra %/d6,1b"  \
-		:               \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6"); \
-    else \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 lsrl  #3,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 movew %/a0@,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a1@+; \
-		 dbra %/d6,1b"  \
-                :               \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6"); \
-})
-
-
-#define raw_outsw_swapw(port, buf, nr) \
-({  if ((nr) % 8) \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 dbra %/d6,1b"  \
-                :               \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6"); \
-    else \
-	__asm__ __volatile__ \
-	       ("movel %0,%/a0; \
-		 movel %1,%/a1; \
-		 movel %2,%/d6; \
-		 lsrl  #3,%/d6; \
-		 subql #1,%/d6; \
-	       1:movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 movew %/a1@+,%/d0; \
-		 rolw  #8,%/d0; \
-		 movew %/d0,%/a0@; \
-		 dbra %/d6,1b"  \
-                :               \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6"); \
-})
+static inline void raw_insb(volatile unsigned char *port, unsigned char *buf,
+			    unsigned int len)
+{
+	unsigned int i;
+
+        for (i = 0; i < len; i++)
+		*buf++ = in_8(port);
+}
+
+static inline void raw_outsb(volatile unsigned char *port,
+			     const unsigned char *buf, unsigned int len)
+{
+	unsigned int i;
+
+        for (i = 0; i < len; i++)
+		out_8(port, *buf++);
+}
+
+static inline void raw_insw(volatile unsigned short *port, unsigned short *buf,
+			    unsigned int nr)
+{
+	unsigned int tmp;
+
+	if (nr & 15) {
+		tmp = (nr & 15) - 1;
+		asm volatile (
+			"1: movew %2@,%0@+; dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+	if (nr >> 4) {
+		tmp = (nr >> 4) - 1;
+		asm volatile (
+			"1: "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"movew %2@,%0@+; "
+			"dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+}
+
+static inline void raw_outsw(volatile unsigned short *port,
+			     const unsigned short *buf, unsigned int nr)
+{
+	unsigned int tmp;
+
+	if (nr & 15) {
+		tmp = (nr & 15) - 1;
+		asm volatile (
+			"1: movew %0@+,%2@; dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+	if (nr >> 4) {
+		tmp = (nr >> 4) - 1;
+		asm volatile (
+			"1: "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"movew %0@+,%2@; "
+			"dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+}
+
+static inline void raw_insl(volatile unsigned int *port, unsigned int *buf,
+			    unsigned int nr)
+{
+	unsigned int tmp;
+
+	if (nr & 15) {
+		tmp = (nr & 15) - 1;
+		asm volatile (
+			"1: movel %2@,%0@+; dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+	if (nr >> 4) {
+		tmp = (nr >> 4) - 1;
+		asm volatile (
+			"1: "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"movel %2@,%0@+; "
+			"dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+}
+
+static inline void raw_outsl(volatile unsigned int *port,
+			     const unsigned int *buf, unsigned int nr)
+{
+	unsigned int tmp;
+
+	if (nr & 15) {
+		tmp = (nr & 15) - 1;
+		asm volatile (
+			"1: movel %0@+,%2@; dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+	if (nr >> 4) {
+		tmp = (nr >> 4) - 1;
+		asm volatile (
+			"1: "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"movel %0@+,%2@; "
+			"dbra %1,1b"
+			: "=a" (buf), "=d" (tmp)
+			: "a" (port), "0" (buf),
+			  "1" (tmp));
+	}
+}
+
+
+static inline void raw_insw_swapw(volatile unsigned short *port,
+				  unsigned short *buf, unsigned int nr)
+{
+    if ((nr) % 8)
+	__asm__ __volatile__
+	       ("\tmovel %0,%/a0\n\t"
+		"movel %1,%/a1\n\t"
+		"movel %2,%/d6\n\t"
+		"subql #1,%/d6\n"
+		"1:\tmovew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"dbra %/d6,1b"
+		:
+		: "g" (port), "g" (buf), "g" (nr)
+		: "d0", "a0", "a1", "d6");
+    else
+	__asm__ __volatile__
+	       ("movel %0,%/a0\n\t"
+		"movel %1,%/a1\n\t"
+		"movel %2,%/d6\n\t"
+		"lsrl  #3,%/d6\n\t"
+		"subql #1,%/d6\n"
+		"1:\tmovew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"movew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"movew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"movew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"movew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"movew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"movew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"movew %/a0@,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a1@+\n\t"
+		"dbra %/d6,1b"
+                :
+		: "g" (port), "g" (buf), "g" (nr)
+		: "d0", "a0", "a1", "d6");
+}
+
+static inline void raw_outsw_swapw(volatile unsigned short *port,
+				   const unsigned short *buf, unsigned int nr)
+{
+    if ((nr) % 8)
+	__asm__ __volatile__
+	       ("movel %0,%/a0\n\t"
+		"movel %1,%/a1\n\t"
+		"movel %2,%/d6\n\t"
+		"subql #1,%/d6\n"
+		"1:\tmovew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"dbra %/d6,1b"
+                :
+		: "g" (port), "g" (buf), "g" (nr)
+		: "d0", "a0", "a1", "d6");
+    else
+	__asm__ __volatile__
+	       ("movel %0,%/a0\n\t"
+		"movel %1,%/a1\n\t"
+		"movel %2,%/d6\n\t"
+		"lsrl  #3,%/d6\n\t"
+		"subql #1,%/d6\n"
+		"1:\tmovew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"movew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"movew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"movew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"movew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"movew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"movew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"movew %/a1@+,%/d0\n\t"
+		"rolw  #8,%/d0\n\t"
+		"movew %/d0,%/a0@\n\t"
+		"dbra %/d6,1b"
+                :
+		: "g" (port), "g" (buf), "g" (nr)
+		: "d0", "a0", "a1", "d6");
+}
 
 
 #endif /* __KERNEL__ */
diff -urN linux-2.4.21-pre7/include/asm-m68k/rtc.h linux-2.4.21-rc1/include/asm-m68k/rtc.h
--- linux-2.4.21-pre7/include/asm-m68k/rtc.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-m68k/rtc.h	2003-04-21 11:48:58.000000000 -0700
@@ -13,24 +13,64 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
 #include <linux/rtc.h>
-#include <linux/delay.h>
+#include <asm/errno.h>
 #include <asm/machdep.h>
 
 #define RTC_PIE 0x40		/* periodic interrupt enable */
 #define RTC_AIE 0x20		/* alarm interrupt enable */
 #define RTC_UIE 0x10		/* update-finished interrupt enable */
 
-extern void gen_rtc_interrupt(unsigned long);
-
 /* some dummy definitions */
+#define RTC_BATT_BAD 0x100	/* battery bad */
 #define RTC_SQWE 0x08		/* enable square-wave output */
 #define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
 #define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
 #define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
 
-
+static inline unsigned int get_rtc_time(struct rtc_time *time)
+{
+	/*
+	 * Only the values that we read from the RTC are set. We leave
+	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
+	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+	 * by the RTC when initially set to a non-zero value.
+	 */
+	mach_hwclk(0, time);
+	return RTC_24H;
+}
+
+static inline int set_rtc_time(struct rtc_time *time)
+{
+	return mach_hwclk(1, time);
+}
+
+static inline unsigned int get_rtc_ss(void)
+{
+	if (mach_get_ss)
+		return mach_get_ss();
+	else{
+		struct rtc_time h;
+		
+		get_rtc_time(&h);
+		return h.tm_sec;
+	}
+}
+
+static inline int get_rtc_pll(struct rtc_pll_info *pll)
+{
+	if (mach_get_rtc_pll)
+		return mach_get_rtc_pll(pll);
+	else
+		return -EINVAL;
+}
+static inline int set_rtc_pll(struct rtc_pll_info *pll)
+{
+	if (mach_set_rtc_pll)
+		return mach_set_rtc_pll(pll);
+	else
+		return -EINVAL;
+}
 #endif /* __KERNEL__ */
 
 #endif /* _ASM__RTC_H */
diff -urN linux-2.4.21-pre7/include/asm-ppc/bootinfo.h linux-2.4.21-rc1/include/asm-ppc/bootinfo.h
--- linux-2.4.21-pre7/include/asm-ppc/bootinfo.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-ppc/bootinfo.h	2003-04-21 11:48:58.000000000 -0700
@@ -16,9 +16,9 @@
 #else
 
 struct bi_record {
-    unsigned long tag;			/* tag ID */
-    unsigned long size;			/* size of record (in bytes) */
-    unsigned long data[0];		/* data */
+	unsigned long tag;		/* tag ID */
+	unsigned long size;		/* size of record (in bytes) */
+	unsigned long data[0];		/* data */
 };
 
 #define BI_FIRST		0x1010  /* first record - marker */
diff -urN linux-2.4.21-pre7/include/asm-ppc/io.h linux-2.4.21-rc1/include/asm-ppc/io.h
--- linux-2.4.21-pre7/include/asm-ppc/io.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-ppc/io.h	2003-04-21 11:48:58.000000000 -0700
@@ -77,9 +77,22 @@
 
 #ifdef CONFIG_ALL_PPC
 /*
- * We have to handle possible machine checks here on powermacs
- * and potentially some CHRPs -- paulus.
+ * On powermacs, we will get a machine check exception if we
+ * try to read data from a non-existent I/O port.  Because the
+ * machine check is an asynchronous exception, it isn't
+ * well-defined which instruction SRR0 will point to when the
+ * exception occurs.
+ * With the sequence below (twi; isync; nop), we have found that
+ * the machine check occurs on one of the three instructions on
+ * all PPC implementations tested so far.  The twi and isync are
+ * needed on the 601 (in fact twi; sync works too), the isync and
+ * nop are needed on 604[e|r], and any of twi, sync or isync will
+ * work on 603[e], 750, 74x0.
+ * The twi creates an explicit data dependency on the returned
+ * value which seems to be needed to make the 601 wait for the
+ * load to finish.
  */
+
 #define __do_in_asm(name, op)				\
 extern __inline__ unsigned int name(unsigned int port)	\
 {							\
@@ -193,6 +206,15 @@
 			     unsigned int size, int flags);
 
 /*
+ * This makes sure that a value has been returned from a device
+ * before any subsequent loads or stores are performed.
+ */
+extern inline void io_flush(int value)
+{
+	__asm__ __volatile__("twi 0,%0,0; isync" : : "r" (value));
+}
+
+/*
  * The PCI bus is inherently Little-Endian.  The PowerPC is being
  * run Big-Endian.  Thus all values which cross the [PCI] barrier
  * must be endian-adjusted.  Also, the local DRAM has a different
@@ -268,12 +290,19 @@
 
 /*
  * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ *
+ * Read operations have additional twi & isync to make sure the read
+ * is actually performed (i.e. the data has come back) before we start
+ * executing any following instructions.
  */
 extern inline int in_8(volatile unsigned char *addr)
 {
 	int ret;
 
-	__asm__ __volatile__("lbz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+	__asm__ __volatile__(
+		"lbz%U1%X1 %0,%1;\n"
+		"twi 0,%0,0;\n"
+		"isync" : "=r" (ret) : "m" (*addr));
 	return ret;
 }
 
@@ -286,7 +315,9 @@
 {
 	int ret;
 
-	__asm__ __volatile__("lhbrx %0,0,%1; eieio" : "=r" (ret) :
+	__asm__ __volatile__("lhbrx %0,0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) :
 			      "r" (addr), "m" (*addr));
 	return ret;
 }
@@ -295,7 +326,9 @@
 {
 	int ret;
 
-	__asm__ __volatile__("lhz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+	__asm__ __volatile__("lhz%U1%X1 %0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) : "m" (*addr));
 	return ret;
 }
 
@@ -314,7 +347,9 @@
 {
 	unsigned ret;
 
-	__asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
+	__asm__ __volatile__("lwbrx %0,0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) :
 			     "r" (addr), "m" (*addr));
 	return ret;
 }
@@ -323,7 +358,9 @@
 {
 	unsigned ret;
 
-	__asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+	__asm__ __volatile__("lwz%U1%X1 %0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) : "m" (*addr));
 	return ret;
 }
 
diff -urN linux-2.4.21-pre7/include/asm-ppc/rtc.h linux-2.4.21-rc1/include/asm-ppc/rtc.h
--- linux-2.4.21-pre7/include/asm-ppc/rtc.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/include/asm-ppc/rtc.h	2003-04-21 11:48:58.000000000 -0700
@@ -0,0 +1,98 @@
+/* 
+ * inclue/asm-ppc/rtc.h
+ *
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Based on:
+ * include/asm-m68k/rtc.h
+ *
+ * Copyright Richard Zidlicky
+ * implementation details for genrtc/q40rtc driver
+ *
+ * And the old drivers/macintosh/rtc.c which was heavily based on:
+ * Linux/SPARC Real Time Clock Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * With additional work by Paul Mackerras and Franz Sirl.
+ */
+
+#ifndef __ASM_RTC_H__
+#define __ASM_RTC_H__
+
+#ifdef __KERNEL__
+
+#include <linux/rtc.h>
+
+#include <asm/machdep.h>
+#include <asm/time.h>
+
+#define RTC_PIE 0x40		/* periodic interrupt enable */
+#define RTC_AIE 0x20		/* alarm interrupt enable */
+#define RTC_UIE 0x10		/* update-finished interrupt enable */
+
+extern void gen_rtc_interrupt(unsigned long);
+
+/* some dummy definitions */
+#define RTC_BATT_BAD 0x100	/* battery bad */
+#define RTC_SQWE 0x08		/* enable square-wave output */
+#define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+#define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+#define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
+
+static inline unsigned int get_rtc_time(struct rtc_time *time)
+{
+	if (ppc_md.get_rtc_time) {
+		unsigned long nowtime;
+
+		nowtime = (ppc_md.get_rtc_time)();
+
+		to_tm(nowtime, time);
+
+		time->tm_year -= 1900;
+		time->tm_mon -= 1; /* Make sure userland has a 0-based month */
+	}
+
+	return RTC_24H;
+}
+
+/* Set the current date and time in the real time clock. */
+static inline int set_rtc_time(struct rtc_time *time)
+{
+	if (ppc_md.get_rtc_time) {
+		unsigned long nowtime;
+
+		nowtime = mktime(time->tm_year+1900, time->tm_mon+1,
+				time->tm_mday, time->tm_hour, time->tm_min,
+				time->tm_sec);
+
+		(ppc_md.set_rtc_time)(nowtime);
+
+		return 0;
+	} else
+		return -EINVAL;
+}
+
+static inline unsigned int get_rtc_ss(void)
+{
+	struct rtc_time h;
+
+	get_rtc_time(&h);
+	return h.tm_sec;
+}
+
+static inline int get_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+static inline int set_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_RTC_H__ */
diff -urN linux-2.4.21-pre7/include/asm-sparc64/head.h linux-2.4.21-rc1/include/asm-sparc64/head.h
--- linux-2.4.21-pre7/include/asm-sparc64/head.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/include/asm-sparc64/head.h	2003-04-21 11:49:00.000000000 -0700
@@ -6,7 +6,7 @@
 
 #define KERNBASE	0x400000
 
-#define	PTREGS_OFF	(STACK_BIAS + REGWIN_SZ)
+#define	PTREGS_OFF	(STACK_BIAS + STACKFRAME_SZ)
 
 #define __CHEETAH_ID	0x003e0014
 
diff -urN linux-2.4.21-pre7/include/asm-sparc64/processor.h linux-2.4.21-rc1/include/asm-sparc64/processor.h
--- linux-2.4.21-pre7/include/asm-sparc64/processor.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-sparc64/processor.h	2003-04-21 11:49:01.000000000 -0700
@@ -223,7 +223,7 @@
 	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
 	"wrpr		%%g0, (1 << 3), %%wstate\n\t" \
 	: \
-	: "r" (regs), "r" (sp - REGWIN_SZ - STACK_BIAS), \
+	: "r" (regs), "r" (sp - sizeof(struct reg_window) - STACK_BIAS), \
 	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
 } while(0)
 
@@ -263,7 +263,7 @@
 	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
 	"wrpr		%%g0, (2 << 3), %%wstate\n\t" \
 	: \
-	: "r" (regs), "r" (sp - REGWIN32_SZ), \
+	: "r" (regs), "r" (sp - sizeof(struct reg_window32)), \
 	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
 } while(0)
 
diff -urN linux-2.4.21-pre7/include/asm-sparc64/ptrace.h linux-2.4.21-rc1/include/asm-sparc64/ptrace.h
--- linux-2.4.21-pre7/include/asm-sparc64/ptrace.h	1998-01-12 15:15:58.000000000 -0800
+++ linux-2.4.21-rc1/include/asm-sparc64/ptrace.h	2003-04-21 11:49:01.000000000 -0700
@@ -89,11 +89,9 @@
 
 #define TRACEREG_SZ	sizeof(struct pt_regs)
 #define STACKFRAME_SZ	sizeof(struct sparc_stackf)
-#define REGWIN_SZ	sizeof(struct reg_window)
 
 #define TRACEREG32_SZ	sizeof(struct pt_regs32)
 #define STACKFRAME32_SZ	sizeof(struct sparc_stackf32)
-#define REGWIN32_SZ	sizeof(struct reg_window32)
 
 #ifdef __KERNEL__
 #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV))
@@ -105,11 +103,9 @@
 /* For assembly code. */
 #define TRACEREG_SZ		0xa0
 #define STACKFRAME_SZ		0xc0
-#define REGWIN_SZ		0x80
 
 #define TRACEREG32_SZ		0x50
 #define STACKFRAME32_SZ		0x60
-#define REGWIN32_SZ		0x40
 
 #include <asm/asm_offsets.h>
 #endif
diff -urN linux-2.4.21-pre7/include/asm-sparc64/system.h linux-2.4.21-rc1/include/asm-sparc64/system.h
--- linux-2.4.21-pre7/include/asm-sparc64/system.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-sparc64/system.h	2003-04-21 11:49:01.000000000 -0700
@@ -183,11 +183,6 @@
 	 * not preserve it's value.  Hairy, but it lets us remove 2 loads
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
-#if __GNUC__ >= 3
-#define EXTRA_CLOBBER ,"%l1"
-#else
-#define EXTRA_CLOBBER
-#endif
 #define switch_to(prev, next, last)						\
 do {	CHECK_LOCKS(prev);							\
 	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
@@ -240,7 +235,7 @@
                 "g1", "g2", "g3",       "g5",       "g7",			\
 	              "l2", "l3", "l4", "l5", "l6", "l7",			\
 	  "i0", "i1", "i2", "i3", "i4", "i5",					\
-	  "o0", "o1", "o2", "o3", "o4", "o5",       "o7" EXTRA_CLOBBER);	\
+	  "o0", "o1", "o2", "o3", "o4", "o5",       "o7");			\
 	/* If you fuck with this, update ret_from_syscall code too. */		\
 	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
 		write_pcr(current->thread.pcr_reg);				\
diff -urN linux-2.4.21-pre7/include/asm-sparc64/ttable.h linux-2.4.21-rc1/include/asm-sparc64/ttable.h
--- linux-2.4.21-pre7/include/asm-sparc64/ttable.h	2001-12-21 09:42:03.000000000 -0800
+++ linux-2.4.21-rc1/include/asm-sparc64/ttable.h	2003-04-21 11:49:01.000000000 -0700
@@ -24,7 +24,7 @@
 	ba,pt	%xcc, etrap;				\
 109:	 or	%g7, %lo(109b), %g7;			\
 	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
 	 clr	%l6;					\
 	nop;
@@ -34,7 +34,7 @@
 	ba,pt	%xcc, etrap;				\
 109:	 or	%g7, %lo(109b), %g7;			\
 	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
 	 clr	%l6;
 
@@ -43,7 +43,7 @@
 	ba,pt	%xcc, do_fptrap;			\
 109:	 or	%g7, %lo(109b), %g7;			\
 	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
 	 clr	%l6;					\
 	nop;
@@ -63,7 +63,7 @@
 	ba,pt	%xcc, etraptl1;				\
 109:	 or	%g7, %lo(109b), %g7;			\
 	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,pt	%xcc, rtrap;				\
 	 clr	%l6;					\
 	nop;
@@ -72,7 +72,7 @@
 	sethi	%hi(109f), %g7;				\
 	ba,pt	%xcc, etrap;				\
 109:	 or	%g7, %lo(109b), %g7;			\
-	add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	add	%sp, PTREGS_OFF, %o0;			\
 	call	routine;				\
 	 mov	arg, %o1;				\
 	ba,pt	%xcc, rtrap;				\
@@ -82,7 +82,7 @@
 	sethi	%hi(109f), %g7;				\
 	ba,pt	%xcc, etraptl1;				\
 109:	 or	%g7, %lo(109b), %g7;			\
-	add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	add	%sp, PTREGS_OFF, %o0;			\
 	call	routine;				\
 	 mov	arg, %o1;				\
 	ba,pt	%xcc, rtrap;				\
@@ -139,7 +139,7 @@
 	 rd	%pc, %g7;				\
 	mov	level, %o0;				\
 	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1;	\
+	 add	%sp, PTREGS_OFF, %o1;			\
 	ba,a,pt	%xcc, rtrap_clr_l6;
 	
 #define TICK_SMP_IRQ					\
@@ -149,7 +149,7 @@
 	b,pt	%xcc, etrap_irq;			\
 109:	 or	%g7, %lo(109b), %g7;			\
 	call	smp_percpu_timer_interrupt;		\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	 add	%sp, PTREGS_OFF, %o0;			\
 	ba,a,pt	%xcc, rtrap_clr_l6;
 
 #define TRAP_IVEC TRAP_NOSAVE(do_ivec)
@@ -162,11 +162,11 @@
 	ba,pt	%xcc, etrap;						\
 	 rd	%pc, %g7;						\
 	flushw;								\
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1;	\
+	ldx	[%sp + PTREGS_OFF + PT_V9_TNPC], %l1;			\
 	add	%l1, 4, %l2;						\
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC];	\
+	stx	%l1, [%sp + PTREGS_OFF + PT_V9_TPC];			\
 	ba,pt	%xcc, rtrap_clr_l6;					\
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
+	 stx	%l2, [%sp + PTREGS_OFF + PT_V9_TNPC];
 	        
 /* Before touching these macros, you owe it to yourself to go and
  * see how arch/sparc64/kernel/winfixup.S works... -DaveM
diff -urN linux-2.4.21-pre7/include/asm-x86_64/processor.h linux-2.4.21-rc1/include/asm-x86_64/processor.h
--- linux-2.4.21-pre7/include/asm-x86_64/processor.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/asm-x86_64/processor.h	2003-04-21 11:49:02.000000000 -0700
@@ -411,8 +411,8 @@
 #define ARCH_HAS_PREFETCHW
 #define ARCH_HAS_SPINLOCK_PREFETCH
 
-#define prefetch(x) __builtin_prefetch((x),0)
-#define prefetchw(x) __builtin_prefetch((x),1)
+#define prefetch(x) __builtin_prefetch((x),0,1)
+#define prefetchw(x) __builtin_prefetch((x),1,1)
 #define spin_lock_prefetch(x)  prefetchw(x)
 #define cpu_relax()   rep_nop()
 
diff -urN linux-2.4.21-pre7/include/asm-x86_64/xor.h linux-2.4.21-rc1/include/asm-x86_64/xor.h
--- linux-2.4.21-pre7/include/asm-x86_64/xor.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/include/asm-x86_64/xor.h	2003-04-21 11:49:03.000000000 -0700
@@ -28,9 +28,6 @@
 /* 
  * x86-64 changes / gcc fixes from Andi Kleen. 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- *
- * This hasn't been optimized for the hammer yet, but there are likely
- * no advantages to be gotten from x86-64 here anyways.
  */
 
 typedef struct { unsigned long a,b; } __attribute__((aligned(16))) xmm_store_t;
@@ -62,10 +59,10 @@
 		: "memory")
 
 #define OFFS(x)		"16*("#x")"
-#define PF_OFFS(x)	"256+16*("#x")"
+#define PF_OFFS(x)	"320+16*("#x")"
 #define	PF0(x)		"	prefetchnta "PF_OFFS(x)"(%[p1])		;\n"
 #define LD(x,y)		"       movaps   "OFFS(x)"(%[p1]), %%xmm"#y"	;\n"
-#define ST(x,y)		"       movaps %%xmm"#y",   "OFFS(x)"(%[p1])	;\n"
+#define ST(x,y)		"       movntdq %%xmm"#y",   "OFFS(x)"(%[p1])	;\n"
 #define PF1(x)		"	prefetchnta "PF_OFFS(x)"(%[p2])		;\n"
 #define PF2(x)		"	prefetchnta "PF_OFFS(x)"(%[p3])		;\n"
 #define PF3(x)		"	prefetchnta "PF_OFFS(x)"(%[p4])		;\n"
@@ -77,11 +74,10 @@
 #define XO4(x,y)	"       xorps   "OFFS(x)"(%[p5]), %%xmm"#y"	;\n"
 #define XO5(x,y)	"       xorps   "OFFS(x)"(%[p6]), %%xmm"#y"	;\n"
 
-
 static void
 xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
 {
-        unsigned int lines = bytes >> 8;
+        unsigned int lines = bytes >> 7;
 	unsigned long cr0;
 	xmm_store_t xmm_save[4];
 
@@ -93,37 +89,33 @@
 		LD(i,0)					\
 			LD(i+1,1)			\
 		PF1(i)					\
-				PF1(i+2)		\
 				LD(i+2,2)		\
 					LD(i+3,3)	\
 		PF0(i+4)				\
-				PF0(i+6)		\
 		XO1(i,0)				\
 			XO1(i+1,1)			\
-				XO1(i+2,2)		\
-					XO1(i+3,3)	\
 		ST(i,0)					\
 			ST(i+1,1)			\
+				XO1(i+2,2)		\
+					XO1(i+3,3)	\
 				ST(i+2,2)		\
 					ST(i+3,3)	\
 
 
 		PF0(0)
-				PF0(2)
 
-	" .align 32			;\n"
+	" .p2align 4			;\n"
         " 1:                            ;\n"
 
 		BLOCK(0)
 		BLOCK(4)
-		BLOCK(8)
-		BLOCK(12)
 
-        "       addq %[inc], %[p1]           ;\n"
-        "       addq %[inc], %[p2]           ;\n"
-		"		decl %[cnt] ; jnz 1b"
+	"       decl %[cnt]\n"
+        "       leaq 128(%[p1]),%[p1]\n"
+        "       leaq 128(%[p2]),%[p2]\n"
+	"       jnz 1b\n"
 	: [p1] "+r" (p1), [p2] "+r" (p2), [cnt] "+r" (lines)
-	: [inc] "r" (256UL) 
+	:
         : "memory");
 
 	XMMS_RESTORE;
@@ -133,7 +125,7 @@
 xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
 	  unsigned long *p3)
 {
-	unsigned int lines = bytes >> 8;
+	unsigned int lines = bytes >> 7;
 	xmm_store_t xmm_save[4];
 	unsigned long cr0;
 
@@ -143,47 +135,42 @@
 #undef BLOCK
 #define BLOCK(i) \
 		PF1(i)					\
-				PF1(i+2)		\
 		LD(i,0)					\
 			LD(i+1,1)			\
+		XO1(i,0)				\
+			XO1(i+1,1)			\
 				LD(i+2,2)		\
 					LD(i+3,3)	\
 		PF2(i)					\
-				PF2(i+2)		\
 		PF0(i+4)				\
-				PF0(i+6)		\
-		XO1(i,0)				\
-			XO1(i+1,1)			\
 				XO1(i+2,2)		\
 					XO1(i+3,3)	\
 		XO2(i,0)				\
 			XO2(i+1,1)			\
-				XO2(i+2,2)		\
-					XO2(i+3,3)	\
 		ST(i,0)					\
 			ST(i+1,1)			\
+				XO2(i+2,2)		\
+					XO2(i+3,3)	\
 				ST(i+2,2)		\
 					ST(i+3,3)	\
 
 
 		PF0(0)
-				PF0(2)
 
-	" .align 32			;\n"
+	" .p2align 4			;\n"
         " 1:                            ;\n"
 
 		BLOCK(0)
 		BLOCK(4)
-		BLOCK(8)
-		BLOCK(12)
 
-        "       addq %[inc], %[p1]           ;\n"
-        "       addq %[inc], %[p2]          ;\n"
-        "       addq %[inc], %[p3]           ;\n"
-		"		decl %[cnt] ; jnz 1b"
+	"	decl %[cnt]\n"	
+        "       leaq 128(%[p1]),%[p1]\n" 
+        "       leaq 128(%[p2]),%[p2]\n" 
+        "       leaq 128(%[p3]),%[p3]\n" 
+	"       jnz  1b"
 	: [cnt] "+r" (lines),
 	  [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
-	: [inc] "r" (256UL)
+	:
 	: "memory"); 
 	XMMS_RESTORE;
 }
@@ -192,7 +179,7 @@
 xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
 	  unsigned long *p3, unsigned long *p4)
 {
-	unsigned int lines = bytes >> 8;
+	unsigned int lines = bytes >> 7;
 	xmm_store_t xmm_save[4]; 
 	unsigned long cr0;
 
@@ -202,54 +189,48 @@
 #undef BLOCK
 #define BLOCK(i) \
 		PF1(i)					\
-				PF1(i+2)		\
 		LD(i,0)					\
 			LD(i+1,1)			\
+		XO1(i,0)				\
+			XO1(i+1,1)			\
 				LD(i+2,2)		\
 					LD(i+3,3)	\
 		PF2(i)					\
-				PF2(i+2)		\
-		XO1(i,0)				\
-			XO1(i+1,1)			\
 				XO1(i+2,2)		\
 					XO1(i+3,3)	\
 		PF3(i)					\
-				PF3(i+2)		\
 		PF0(i+4)				\
-				PF0(i+6)		\
 		XO2(i,0)				\
 			XO2(i+1,1)			\
 				XO2(i+2,2)		\
 					XO2(i+3,3)	\
 		XO3(i,0)				\
 			XO3(i+1,1)			\
-				XO3(i+2,2)		\
-					XO3(i+3,3)	\
 		ST(i,0)					\
 			ST(i+1,1)			\
+				XO3(i+2,2)		\
+					XO3(i+3,3)	\
 				ST(i+2,2)		\
 					ST(i+3,3)	\
 
 
 		PF0(0)
-				PF0(2)
 
 	" .align 32			;\n"
         " 1:                            ;\n"
 
 		BLOCK(0)
 		BLOCK(4)
-		BLOCK(8)
-		BLOCK(12)
 
-        "       addq %[inc], %[p1]           ;\n"
-        "       addq %[inc], %[p2]           ;\n"
-        "       addq %[inc], %[p3]           ;\n"
-        "       addq %[inc], %[p4]           ;\n"
-	"	decl %[cnt] ; jnz 1b"
-	: [cnt] "+c" (lines),
+	"       decl %[cnt]\n"	
+        "       leaq 128(%[p1]),%[p1]\n" 
+        "       leaq 128(%[p2]),%[p2]\n" 
+        "       leaq 128(%[p3]),%[p3]\n" 
+        "       leaq 128(%[p4]),%[p4]\n" 
+	"       jnz  1b"	
+	: [cnt] "+r" (lines),
 	  [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
-	: [inc] "r" (256UL)
+	: 
         : "memory" );
 
 	XMMS_RESTORE;
@@ -259,7 +240,7 @@
 xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
 	  unsigned long *p3, unsigned long *p4, unsigned long *p5)
 {
-        unsigned int lines = bytes >> 8;
+        unsigned int lines = bytes >> 7;
 	xmm_store_t xmm_save[4];
 	unsigned long cr0;
 
@@ -269,82 +250,305 @@
 #undef BLOCK
 #define BLOCK(i) \
 		PF1(i)					\
-				PF1(i+2)		\
 		LD(i,0)					\
 			LD(i+1,1)			\
+		XO1(i,0)				\
+			XO1(i+1,1)			\
 				LD(i+2,2)		\
 					LD(i+3,3)	\
 		PF2(i)					\
-				PF2(i+2)		\
-		XO1(i,0)				\
-			XO1(i+1,1)			\
 				XO1(i+2,2)		\
 					XO1(i+3,3)	\
 		PF3(i)					\
-				PF3(i+2)		\
 		XO2(i,0)				\
 			XO2(i+1,1)			\
 				XO2(i+2,2)		\
 					XO2(i+3,3)	\
 		PF4(i)					\
-				PF4(i+2)		\
 		PF0(i+4)				\
-				PF0(i+6)		\
 		XO3(i,0)				\
 			XO3(i+1,1)			\
 				XO3(i+2,2)		\
 					XO3(i+3,3)	\
 		XO4(i,0)				\
 			XO4(i+1,1)			\
-				XO4(i+2,2)		\
-					XO4(i+3,3)	\
 		ST(i,0)					\
 			ST(i+1,1)			\
+				XO4(i+2,2)		\
+					XO4(i+3,3)	\
 				ST(i+2,2)		\
 					ST(i+3,3)	\
 
 
 		PF0(0)
-				PF0(2)
 
-	" .align 32			;\n"
+	" .p2align 4			;\n"
         " 1:                            ;\n"
 
 		BLOCK(0)
 		BLOCK(4)
-		BLOCK(8)
-		BLOCK(12)
 
-        "       addq %[inc], %[p1]           ;\n"
-        "       addq %[inc], %[p2]           ;\n"
-        "       addq %[inc], %[p3]           ;\n"
-        "       addq %[inc], %[p4]           ;\n"
-        "       addq %[inc], %[p5]           ;\n"
-	"	decl %[cnt] ; jnz 1b"
-	: [cnt] "+c" (lines),
+	"       decl %[cnt]\n"	
+        "       leaq 128(%[p1]),%[p1]\n" 
+        "       leaq 128(%[p2]),%[p2]\n" 
+        "       leaq 128(%[p3]),%[p3]\n" 
+        "       leaq 128(%[p4]),%[p4]\n" 
+        "       leaq 128(%[p5]),%[p5]\n" 
+	"       jnz  1b"	
+	: [cnt] "+r" (lines),
   	  [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4), 
 	  [p5] "+r" (p5)
-	: [inc] "r" (256UL)
+	: 
 	: "memory");
 
 	XMMS_RESTORE;
 }
 
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC__MINOR__ >= 3)
+#define STORE_NTI(x,mem) __builtin_ia32_movnti(&(mem), (x))
+#else
+#define STORE_NTI(x,mem)  asm("movnti %1,%0" : "=m" (mem) : "r" (x)) 
+#endif
+
+
+static void
+xor_64regs_stream_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		__builtin_prefetch(p1 + 5*64, 0, 0);
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		__builtin_prefetch(p2 + 5*64, 0, 0);
+		STORE_NTI(d0, p1[0]);
+		STORE_NTI(d1, p1[1]);
+		STORE_NTI(d2, p1[2]);
+		STORE_NTI(d3, p1[3]);
+		STORE_NTI(d4, p1[4]);
+		STORE_NTI(d5, p1[5]);
+		STORE_NTI(d6, p1[6]);
+		STORE_NTI(d7, p1[7]);
+		p1 += 8;
+		p2 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_64regs_stream_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		__builtin_prefetch(p1 + 5*64, 0, 0);
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		__builtin_prefetch(p2 + 5*64, 0, 0);
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		__builtin_prefetch(p3 + 5*64, 0, 0);
+		STORE_NTI(d0, p1[0]);
+		STORE_NTI(d1, p1[1]);
+		STORE_NTI(d2, p1[2]);
+		STORE_NTI(d3, p1[3]);
+		STORE_NTI(d4, p1[4]);
+		STORE_NTI(d5, p1[5]);
+		STORE_NTI(d6, p1[6]);
+		STORE_NTI(d7, p1[7]);
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_64regs_stream_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		__builtin_prefetch(p1 + 5*64, 0, 0);
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		__builtin_prefetch(p2 + 5*64, 0, 0);
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		__builtin_prefetch(p3 + 5*64, 0, 0);
+		d0 ^= p4[0];
+		d1 ^= p4[1];
+		d2 ^= p4[2];
+		d3 ^= p4[3];
+		d4 ^= p4[4];
+		d5 ^= p4[5];
+		d6 ^= p4[6];
+		d7 ^= p4[7];
+		__builtin_prefetch(p4 + 5*64, 0, 0);
+		STORE_NTI(d0, p1[0]);
+		STORE_NTI(d1, p1[1]);
+		STORE_NTI(d2, p1[2]);
+		STORE_NTI(d3, p1[3]);
+		STORE_NTI(d4, p1[4]);
+		STORE_NTI(d5, p1[5]);
+		STORE_NTI(d6, p1[6]);
+		STORE_NTI(d7, p1[7]);
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_64regs_stream_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		__builtin_prefetch(p1 + 5*64, 0, 0);
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		__builtin_prefetch(p2 + 5*64, 0, 0);
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		__builtin_prefetch(p3 + 5*64, 0, 0);
+		d0 ^= p4[0];
+		d1 ^= p4[1];
+		d2 ^= p4[2];
+		d3 ^= p4[3];
+		d4 ^= p4[4];
+		d5 ^= p4[5];
+		d6 ^= p4[6];
+		d7 ^= p4[7];
+		__builtin_prefetch(p4 + 5*64, 0, 0);
+		d0 ^= p5[0];
+		d1 ^= p5[1];
+		d2 ^= p5[2];
+		d3 ^= p5[3];
+		d4 ^= p5[4];
+		d5 ^= p5[5];
+		d6 ^= p5[6];
+		d7 ^= p5[7];
+		__builtin_prefetch(p5 + 5*64, 0, 0);
+		STORE_NTI(d0, p1[0]);
+		STORE_NTI(d1, p1[1]);
+		STORE_NTI(d2, p1[2]);
+		STORE_NTI(d3, p1[3]);
+		STORE_NTI(d4, p1[4]);
+		STORE_NTI(d5, p1[5]);
+		STORE_NTI(d6, p1[6]);
+		STORE_NTI(d7, p1[7]);
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+		p5 += 8;
+	} while (--lines > 0);
+}
+
+
 static struct xor_block_template xor_block_sse = {
-        name: "generic_sse",
+        name: "128byte sse streaming",
         do_2: xor_sse_2,
         do_3: xor_sse_3,
         do_4: xor_sse_4,
         do_5: xor_sse_5,
 };
 
+static struct xor_block_template xor_block_64regs_stream = {
+	name: "64byte int streaming",
+	do_2: xor_64regs_stream_2,
+	do_3: xor_64regs_stream_3,
+	do_4: xor_64regs_stream_4,
+	do_5: xor_64regs_stream_5,
+};
+
+/* AK: the speed test is useless: it only tests cache hot */
 #undef XOR_TRY_TEMPLATES
 #define XOR_TRY_TEMPLATES				\
 	do {						\
 		xor_speed(&xor_block_sse);	\
+		xor_speed(&xor_block_64regs_stream);	\
 	} while (0)
 
-/* We force the use of the SSE xor block because it can write around L2.
-   We may also be able to load into the L1 only depending on how the cpu
-   deals with a load to a line that is being prefetched.  */
-#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
+#define XOR_SELECT_TEMPLATE(FASTEST) (FASTEST)
diff -urN linux-2.4.21-pre7/include/linux/ac97_codec.h linux-2.4.21-rc1/include/linux/ac97_codec.h
--- linux-2.4.21-pre7/include/linux/ac97_codec.h	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/ac97_codec.h	2003-04-21 11:49:03.000000000 -0700
@@ -222,6 +222,8 @@
 	int dev_mixer; 
 	int type;
 
+	int modem:1;
+
 	struct ac97_ops *codec_ops;
 
 	/* controller specific lower leverl ac97 accessing routines */
@@ -237,6 +239,9 @@
 	int stereo_mixers;
 	int record_sources;
 
+	/* Property flags */
+	int flags;
+
 	int bit_resolution;
 
 	/* OSS mixer interface */
@@ -265,6 +270,8 @@
 	int (*amplifier)(struct ac97_codec *codec, int on);
 	/* Digital mode control */
 	int (*digital)(struct ac97_codec *codec, int format);
+#define AC97_DELUDED_MODEM	1	/* Audio codec reports its a modem */
+#define AC97_NO_PCM_VOLUME	2	/* Volume control is missing 	   */
 };
 
 extern int ac97_read_proc (char *page_out, char **start, off_t off,
diff -urN linux-2.4.21-pre7/include/linux/atmdev.h linux-2.4.21-rc1/include/linux/atmdev.h
--- linux-2.4.21-pre7/include/linux/atmdev.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/atmdev.h	2003-04-21 11:49:03.000000000 -0700
@@ -282,7 +282,6 @@
 
 struct atm_vcc {
 	atm_vcc_flags_t flags;		/* VCC flags (ATM_VF_*) */
-	unsigned char	family;		/* address family; 0 if unused */
 	short		vpi;		/* VPI and VCI (types must be equal */
 					/* with sockaddr) */
 	int 		vci;
@@ -291,7 +290,6 @@
 	struct atm_dev	*dev;		/* device back pointer */
 	struct atm_qos	qos;		/* QOS */
 	struct atm_sap	sap;		/* SAP */
-	atomic_t	tx_inuse,rx_inuse; /* buffer space in use */
 	void (*push)(struct atm_vcc *vcc,struct sk_buff *skb);
 	void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */
 	struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size);
@@ -302,7 +300,6 @@
 	int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
 	void		*dev_data;	/* per-device data */
 	void		*proto_data;	/* per-protocol data */
-	struct sk_buff_head recvq;	/* receive queue */
 	struct k_atm_aal_stats *stats;	/* pointer to AAL stats group */
 	wait_queue_head_t sleep;	/* if socket is busy */
 	struct sock	*sk;		/* socket backpointer */
@@ -355,7 +352,7 @@
 	struct proc_dir_entry *proc_entry; /* proc entry */
 	char *proc_name;		/* proc entry name */
 #endif
-	struct atm_dev	*prev,*next;	/* linkage */
+	struct list_head dev_list;	/* linkage */
 };
 
 
@@ -434,19 +431,19 @@
 
 static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize)
 {
-	atomic_add(truesize+ATM_PDU_OVHD,&vcc->rx_inuse);
+	atomic_add(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
 }
 
 
 static __inline__ void atm_return(struct atm_vcc *vcc,int truesize)
 {
-	atomic_sub(truesize+ATM_PDU_OVHD,&vcc->rx_inuse);
+	atomic_sub(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
 }
 
 
 static __inline__ int atm_may_send(struct atm_vcc *vcc,unsigned int size)
 {
-	return size+atomic_read(&vcc->tx_inuse)+ATM_PDU_OVHD < vcc->sk->sndbuf;
+	return size+atomic_read(&vcc->sk->wmem_alloc)+ATM_PDU_OVHD < vcc->sk->sndbuf;
 }
 
 
diff -urN linux-2.4.21-pre7/include/linux/console_struct.h linux-2.4.21-rc1/include/linux/console_struct.h
--- linux-2.4.21-pre7/include/linux/console_struct.h	2001-10-11 11:17:22.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/console_struct.h	2003-04-21 11:49:03.000000000 -0700
@@ -9,6 +9,9 @@
  * to achieve effects such as fast scrolling by changing the origin.
  */
 
+#ifndef _LINUX_CONSOLE_STRUCT_H_
+#define _LINUX_CONSOLE_STRUCT_H_
+
 #define NPAR 16
 
 struct vc_data {
@@ -107,3 +110,5 @@
 #define CUR_DEFAULT CUR_UNDERLINE
 
 #define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp)
+
+#endif /* _LINUX_CONSOLE_STRUCT_H_ */
diff -urN linux-2.4.21-pre7/include/linux/fcdevice.h linux-2.4.21-rc1/include/linux/fcdevice.h
--- linux-2.4.21-pre7/include/linux/fcdevice.h	2001-03-25 18:24:31.000000000 -0800
+++ linux-2.4.21-rc1/include/linux/fcdevice.h	2003-04-21 11:49:04.000000000 -0700
@@ -31,7 +31,7 @@
 				   unsigned short type, void *daddr,
 				   void *saddr, unsigned len);
 extern int		fc_rebuild_header(struct sk_buff *skb);
-//extern unsigned short	fc_type_trans(struct sk_buff *skb, struct net_device *dev); 
+extern unsigned short	fc_type_trans(struct sk_buff *skb, struct net_device *dev); 
 
 extern struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv);
 extern struct net_device *alloc_fcdev(int sizeof_priv);
diff -urN linux-2.4.21-pre7/include/linux/ide.h linux-2.4.21-rc1/include/linux/ide.h
--- linux-2.4.21-pre7/include/linux/ide.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/ide.h	2003-04-21 11:49:04.000000000 -0700
@@ -344,17 +344,14 @@
 #include <asm/ide.h>
 
 /* Currently only m68k, apus and m8xx need it */
-#ifdef IDE_ARCH_ACK_INTR
-extern int ide_irq_lock;
-# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
-#else
+#ifndef IDE_ARCH_ACK_INTR
 # define ide_ack_intr(hwif) (1)
 #endif
 
 /* Currently only Atari needs it */
 #ifndef IDE_ARCH_LOCK
-# define ide_release_lock(lock)			do {} while (0)
-# define ide_get_lock(lock, hdlr, data)		do {} while (0)
+# define ide_release_lock()			do {} while (0)
+# define ide_get_lock(hdlr, data)		do {} while (0)
 #endif /* IDE_ARCH_LOCK */
 
 /*
@@ -1717,6 +1714,7 @@
 extern int __ide_dma_lostirq(ide_drive_t *);
 extern int __ide_dma_timeout(ide_drive_t *);
 #else
+static inline void ide_setup_dma(ide_hwif_t *x, unsigned long y, unsigned int z) {;}
 static inline void ide_release_dma(ide_hwif_t *x) {;}
 #endif
 
diff -urN linux-2.4.21-pre7/include/linux/in6.h linux-2.4.21-rc1/include/linux/in6.h
--- linux-2.4.21-pre7/include/linux/in6.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/in6.h	2003-04-21 11:49:04.000000000 -0700
@@ -40,6 +40,15 @@
 #define s6_addr32		in6_u.u6_addr32
 };
 
+/* IPv6 Wildcard Address (::) and Loopback Address (::1) defined in RFC2553
+ * NOTE: Be aware the IN6ADDR_* constants and in6addr_* externals are defined
+ * in network byte order, not in host byte order as are the IPv4 equivalents
+ */
+extern const struct in6_addr in6addr_any;
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+extern const struct in6_addr in6addr_loopback;
+#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
+
 struct sockaddr_in6 {
 	unsigned short int	sin6_family;    /* AF_INET6 */
 	__u16			sin6_port;      /* Transport layer port # */
@@ -56,6 +65,8 @@
 	int		ipv6mr_ifindex;
 };
 
+#define ipv6mr_acaddr	ipv6mr_multiaddr
+
 struct in6_flowlabel_req
 {
 	struct in6_addr	flr_dst;
@@ -157,6 +168,8 @@
 #define IPV6_MTU		24
 #define IPV6_RECVERR		25
 #define IPV6_V6ONLY		26
+#define IPV6_JOIN_ANYCAST	27
+#define IPV6_LEAVE_ANYCAST	28
 
 /* IPV6_MTU_DISCOVER values */
 #define IPV6_PMTUDISC_DONT		0
diff -urN linux-2.4.21-pre7/include/linux/jbd.h linux-2.4.21-rc1/include/linux/jbd.h
--- linux-2.4.21-pre7/include/linux/jbd.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/jbd.h	2003-04-21 11:49:05.000000000 -0700
@@ -281,7 +281,7 @@
 	do {								     \
 		if (!(expr)) {						     \
 			printk(KERN_ERR "EXT3-fs unexpected failure: %s;\n", # expr); \
-			printk(KERN_ERR ## why);			     \
+			printk(KERN_ERR why);				     \
 		}							     \
 	} while (0)
 #define J_EXPECT(expr, why...)		__journal_expect(expr, ## why)
diff -urN linux-2.4.21-pre7/include/linux/netdevice.h linux-2.4.21-rc1/include/linux/netdevice.h
--- linux-2.4.21-pre7/include/linux/netdevice.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/include/linux/netdevice.h	2003-04-21 11:49:06.000000000 -0700
@@ -465,6 +465,10 @@
 extern void		dev_add_pack(struct packet_type *pt);
 extern void		dev_remove_pack(struct packet_type *pt);
 extern int		dev_get(const char *name);
+extern struct net_device	*dev_get_by_flags(unsigned short flags,
+					unsigned short mask);
+extern struct net_device	*__dev_get_by_flags(unsigned short flags,
+					unsigned short mask);
 extern struct net_device	*dev_get_by_name(const char *name);
 extern struct net_device	*__dev_get_by_name(const char *name);
 extern struct net_device	*dev_alloc(const char *name, int *err);
diff -urN linux-2.4.21-pre7/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.21-rc1/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.4.21-pre7/include/linux/netfilter_ipv4/ip_conntrack.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/netfilter_ipv4/ip_conntrack.h	2003-04-21 11:49:06.000000000 -0700
@@ -63,12 +63,15 @@
 };
 
 /* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+
 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
 
 /* per expectation: application helper private data */
 union ip_conntrack_expect_help {
 	/* insert conntrack helper private data (expect) here */
+	struct ip_ct_amanda_expect exp_amanda_info;
 	struct ip_ct_ftp_expect exp_ftp_info;
 	struct ip_ct_irc_expect exp_irc_info;
 
diff -urN linux-2.4.21-pre7/include/linux/netfilter_ipv4/ip_conntrack_amanda.h linux-2.4.21-rc1/include/linux/netfilter_ipv4/ip_conntrack_amanda.h
--- linux-2.4.21-pre7/include/linux/netfilter_ipv4/ip_conntrack_amanda.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/include/linux/netfilter_ipv4/ip_conntrack_amanda.h	2003-04-21 11:49:06.000000000 -0700
@@ -0,0 +1,29 @@
+#ifndef _IP_CONNTRACK_AMANDA_H
+#define _IP_CONNTRACK_AMANDA_H
+/* AMANDA tracking. */
+
+#ifdef __KERNEL__
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+/* Protects amanda part of conntracks */
+DECLARE_LOCK_EXTERN(ip_amanda_lock);
+
+#endif
+
+struct conn {
+	char* match;
+	int matchlen;
+};
+
+#define NUM_MSGS 	3
+
+
+struct ip_ct_amanda_expect
+{
+	u_int16_t port;		/* port number of this expectation */
+	u_int16_t offset;	/* offset of the port specification in ctrl packet */
+	u_int16_t len;		/* the length of the port number specification */
+};
+
+#endif /* _IP_CONNTRACK_AMANDA_H */
diff -urN linux-2.4.21-pre7/include/linux/netfilter_ipv4/ip_conntrack_tftp.h linux-2.4.21-rc1/include/linux/netfilter_ipv4/ip_conntrack_tftp.h
--- linux-2.4.21-pre7/include/linux/netfilter_ipv4/ip_conntrack_tftp.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/include/linux/netfilter_ipv4/ip_conntrack_tftp.h	2003-04-21 11:49:06.000000000 -0700
@@ -0,0 +1,13 @@
+#ifndef _IP_CT_TFTP
+#define _IP_CT_TFTP
+
+#define TFTP_PORT 69
+
+struct tftphdr {
+	u_int16_t opcode;
+};
+
+#define TFTP_OPCODE_READ	1
+#define TFTP_OPCODE_WRITE	2
+
+#endif /* _IP_CT_TFTP */
diff -urN linux-2.4.21-pre7/include/linux/netfilter_ipv6/ip6_tables.h linux-2.4.21-rc1/include/linux/netfilter_ipv6/ip6_tables.h
--- linux-2.4.21-pre7/include/linux/netfilter_ipv6/ip6_tables.h	2002-02-25 11:38:13.000000000 -0800
+++ linux-2.4.21-rc1/include/linux/netfilter_ipv6/ip6_tables.h	2003-04-21 11:49:06.000000000 -0700
@@ -449,6 +449,9 @@
 				  struct ip6t_table *table,
 				  void *userdata);
 
+/* Check for an extension */
+extern int ip6t_ext_hdr(u8 nexthdr);
+
 #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1))
 
 #endif /*__KERNEL__*/
diff -urN linux-2.4.21-pre7/include/linux/pci_ids.h linux-2.4.21-rc1/include/linux/pci_ids.h
--- linux-2.4.21-pre7/include/linux/pci_ids.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/linux/pci_ids.h	2003-04-21 11:49:06.000000000 -0700
@@ -983,6 +983,7 @@
 #define PCI_DEVICE_ID_TTI_HPT302	0x0006
 #define PCI_DEVICE_ID_TTI_HPT371	0x0007
 #define PCI_DEVICE_ID_TTI_HPT374	0x0008
+#define PCI_DEVICE_ID_TTI_HPT372N  0x0009
 
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_8363_0	0x0305
diff -urN linux-2.4.21-pre7/include/linux/rtc.h linux-2.4.21-rc1/include/linux/rtc.h
--- linux-2.4.21-pre7/include/linux/rtc.h	2001-01-29 08:11:24.000000000 -0800
+++ linux-2.4.21-rc1/include/linux/rtc.h	2003-04-21 11:49:06.000000000 -0700
@@ -39,10 +39,32 @@
 	struct rtc_time time;	/* time the alarm is set to */
 };
 
+/*
+ * Data structure to control PLL correction some better RTC feature
+ * pll_value is used to get or set current value of correction,
+ * the rest of the struct is used to query HW capabilities.
+ * This is modeled after the RTC used in Q40/Q60 computers but
+ * should be sufficiently flexible for other devices
+ *
+ * +ve pll_value means clock will run faster by
+ *   pll_value*pll_posmult/pll_clock
+ * -ve pll_value means clock will run slower by
+ *   pll_value*pll_negmult/pll_clock
+ */ 
+
+struct rtc_pll_info {
+	int pll_ctrl;       /* placeholder for fancier control */
+	int pll_value;      /* get/set correction value */
+	int pll_max;        /* max +ve (faster) adjustment value */
+	int pll_min;        /* max -ve (slower) adjustment value */
+	int pll_posmult;    /* factor for +ve correction */
+	int pll_negmult;    /* factor for -ve correction */
+	long pll_clock;     /* base PLL frequency */
+};
 
 /*
- * ioctl calls that are permitted to the /dev/rtc interface, if 
- * CONFIG_RTC/CONFIG_EFI_RTC was enabled.
+ * ioctl calls that are permitted to the /dev/rtc interface, if
+ * any of the RTC drivers are enabled.
  */
 
 #define RTC_AIE_ON	_IO('p', 0x01)	/* Alarm int. enable on		*/
@@ -66,4 +88,6 @@
 #define RTC_WKALM_SET	_IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
 #define RTC_WKALM_RD	_IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
 
+#define RTC_PLL_GET	_IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
+#define RTC_PLL_SET	_IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
 #endif /* _LINUX_RTC_H_ */
diff -urN linux-2.4.21-pre7/include/linux/socket.h linux-2.4.21-rc1/include/linux/socket.h
--- linux-2.4.21-pre7/include/linux/socket.h	2001-12-21 09:42:04.000000000 -0800
+++ linux-2.4.21-rc1/include/linux/socket.h	2003-04-21 11:49:07.000000000 -0700
@@ -25,6 +25,21 @@
 };
 
 /*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define _SS_MAXSIZE	128	/* Implementation specific max size */
+#define _SS_ALIGNSIZE	(__alignof__ (struct sockaddr *))
+				/* Implementation specific desired alignment */
+
+struct sockaddr_storage {
+	sa_family_t	ss_family;		/* address family */
+	/* Following field(s) are implementation specific */
+	char		__data[_SS_MAXSIZE - sizeof(sa_family_t)];
+				/* space to achieve desired size, */
+				/* _SS_MAXSIZE value minus size of ss_family */
+} __attribute__ ((aligned(_SS_ALIGNSIZE)));	/* force desired alignment */
+
+/*
  *	As we do 4.4BSD message passing we use a 4.4BSD message passing
  *	system, not 4.3. Thus msg_accrights(len) are now missing. They
  *	belong in an obscure libc emulation or the bin.
diff -urN linux-2.4.21-pre7/include/net/addrconf.h linux-2.4.21-rc1/include/net/addrconf.h
--- linux-2.4.21-pre7/include/net/addrconf.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/net/addrconf.h	2003-04-21 11:49:07.000000000 -0700
@@ -58,7 +58,15 @@
 extern int			ipv6_get_saddr(struct dst_entry *dst, 
 					       struct in6_addr *daddr,
 					       struct in6_addr *saddr);
+extern int			ipv6_dev_get_saddr(struct net_device *dev, 
+					       struct in6_addr *daddr,
+					       struct in6_addr *saddr,
+					       int onlink);
 extern int			ipv6_get_lladdr(struct net_device *dev, struct in6_addr *);
+extern void			addrconf_join_solict(struct net_device *dev,
+					struct in6_addr *addr);
+extern void			addrconf_leave_solict(struct net_device *dev,
+					struct in6_addr *addr);
 
 /*
  *	multicast prototypes (mcast.c)
@@ -88,6 +96,26 @@
 extern void			addrconf_prefix_rcv(struct net_device *dev,
 						    u8 *opt, int len);
 
+/*
+ *	anycast prototypes (anycast.c)
+ */
+extern int			ipv6_sock_ac_join(struct sock *sk, 
+						  int ifindex, 
+						  struct in6_addr *addr);
+extern int			ipv6_sock_ac_drop(struct sock *sk,
+						  int ifindex, 
+						  struct in6_addr *addr);
+extern void			ipv6_sock_ac_close(struct sock *sk);
+extern int			inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex);
+
+extern int			ipv6_dev_ac_inc(struct net_device *dev,
+						struct in6_addr *addr);
+extern int			ipv6_dev_ac_dec(struct net_device *dev,
+						struct in6_addr *addr);
+extern int			ipv6_chk_acast_addr(struct net_device *dev,
+						struct in6_addr *addr);
+
+
 /* Device notifier */
 extern int register_inet6addr_notifier(struct notifier_block *nb);
 extern int unregister_inet6addr_notifier(struct notifier_block *nb);
@@ -142,7 +170,7 @@
  *	Hash function taken from net_alias.c
  */
 
-static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr)
+static __inline__ u8 ipv6_addr_hash(const struct in6_addr *addr)
 {	
 	__u32 word;
 
@@ -162,7 +190,7 @@
  *	compute link-local solicited-node multicast address
  */
 
-static inline void addrconf_addr_solict_mult(struct in6_addr *addr,
+static inline void addrconf_addr_solict_mult(const struct in6_addr *addr,
 					     struct in6_addr *solicited)
 {
 	ipv6_addr_set(solicited,
@@ -186,7 +214,7 @@
 		      __constant_htonl(0x2));
 }
 
-static inline int ipv6_addr_is_multicast(struct in6_addr *addr)
+static inline int ipv6_addr_is_multicast(const struct in6_addr *addr)
 {
 	return (addr->s6_addr32[0] & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000);
 }
diff -urN linux-2.4.21-pre7/include/net/if_inet6.h linux-2.4.21-rc1/include/net/if_inet6.h
--- linux-2.4.21-pre7/include/net/if_inet6.h	2000-09-18 15:04:13.000000000 -0700
+++ linux-2.4.21-rc1/include/net/if_inet6.h	2003-04-21 11:49:07.000000000 -0700
@@ -69,6 +69,25 @@
 	spinlock_t		mca_lock;
 };
 
+/* Anycast stuff */
+
+struct ipv6_ac_socklist
+{
+	struct in6_addr		acl_addr;
+	int			acl_ifindex;
+	struct ipv6_ac_socklist *acl_next;
+};
+
+struct ifacaddr6
+{
+	struct in6_addr		aca_addr;
+	struct inet6_dev	*aca_idev;
+	struct ifacaddr6	*aca_next;
+	int			aca_users;
+	atomic_t		aca_refcnt;
+	spinlock_t		aca_lock;
+};
+
 #define	IFA_HOST	IPV6_ADDR_LOOPBACK
 #define	IFA_LINK	IPV6_ADDR_LINKLOCAL
 #define	IFA_SITE	IPV6_ADDR_SITELOCAL
@@ -96,6 +115,7 @@
 
 	struct inet6_ifaddr	*addr_list;
 	struct ifmcaddr6	*mc_list;
+	struct ifacaddr6	*ac_list;
 	rwlock_t		lock;
 	atomic_t		refcnt;
 	__u32			if_flags;
diff -urN linux-2.4.21-pre7/include/net/ip6_fib.h linux-2.4.21-rc1/include/net/ip6_fib.h
--- linux-2.4.21-pre7/include/net/ip6_fib.h	2000-12-11 13:30:48.000000000 -0800
+++ linux-2.4.21-rc1/include/net/ip6_fib.h	2003-04-21 11:49:07.000000000 -0700
@@ -80,6 +80,8 @@
 
 	struct rt6key			rt6i_dst;
 	struct rt6key			rt6i_src;
+
+	u8				rt6i_protocol;
 };
 
 struct fib6_walker_t
@@ -168,11 +170,14 @@
 extern int			fib6_walk_continue(struct fib6_walker_t *w);
 
 extern int			fib6_add(struct fib6_node *root,
-					 struct rt6_info *rt);
+					 struct rt6_info *rt,
+					 struct nlmsghdr *nlh);
 
-extern int			fib6_del(struct rt6_info *rt);
+extern int			fib6_del(struct rt6_info *rt,
+					 struct nlmsghdr *nlh);
 
-extern void			inet6_rt_notify(int event, struct rt6_info *rt);
+extern void			inet6_rt_notify(int event, struct rt6_info *rt,
+						struct nlmsghdr *nlh);
 
 extern void			fib6_run_gc(unsigned long dummy);
 
diff -urN linux-2.4.21-pre7/include/net/ip6_route.h linux-2.4.21-rc1/include/net/ip6_route.h
--- linux-2.4.21-pre7/include/net/ip6_route.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/net/ip6_route.h	2003-04-21 11:49:07.000000000 -0700
@@ -38,8 +38,10 @@
 
 extern int			ipv6_route_ioctl(unsigned int cmd, void *arg);
 
-extern int			ip6_route_add(struct in6_rtmsg *rtmsg);
-extern int			ip6_del_rt(struct rt6_info *);
+extern int			ip6_route_add(struct in6_rtmsg *rtmsg,
+					      struct nlmsghdr *);
+extern int			ip6_del_rt(struct rt6_info *,
+					   struct nlmsghdr *);
 
 extern int			ip6_rt_addr_add(struct in6_addr *addr,
 						struct net_device *dev);
diff -urN linux-2.4.21-pre7/include/net/ipv6.h linux-2.4.21-rc1/include/net/ipv6.h
--- linux-2.4.21-pre7/include/net/ipv6.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/net/ipv6.h	2003-04-21 11:49:07.000000000 -0700
@@ -221,21 +221,21 @@
 					   unsigned int, unsigned int);
 
 
-extern int		ipv6_addr_type(struct in6_addr *addr);
+extern int		ipv6_addr_type(const struct in6_addr *addr);
 
-static inline int ipv6_addr_scope(struct in6_addr *addr)
+static inline int ipv6_addr_scope(const struct in6_addr *addr)
 {
 	return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
 }
 
-static inline int ipv6_addr_cmp(struct in6_addr *a1, struct in6_addr *a2)
+static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
 {
-	return memcmp((void *) a1, (void *) a2, sizeof(struct in6_addr));
+	return memcmp((const void *) a1, (const void *) a2, sizeof(struct in6_addr));
 }
 
-static inline void ipv6_addr_copy(struct in6_addr *a1, struct in6_addr *a2)
+static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
 {
-	memcpy((void *) a1, (void *) a2, sizeof(struct in6_addr));
+	memcpy((void *) a1, (const void *) a2, sizeof(struct in6_addr));
 }
 
 #ifndef __HAVE_ARCH_ADDR_SET
@@ -250,7 +250,7 @@
 }
 #endif
 
-static inline int ipv6_addr_any(struct in6_addr *a)
+static inline int ipv6_addr_any(const struct in6_addr *a)
 {
 	return ((a->s6_addr32[0] | a->s6_addr32[1] | 
 		 a->s6_addr32[2] | a->s6_addr32[3] ) == 0); 
diff -urN linux-2.4.21-pre7/include/net/snmp.h linux-2.4.21-rc1/include/net/snmp.h
--- linux-2.4.21-pre7/include/net/snmp.h	2001-11-22 11:47:11.000000000 -0800
+++ linux-2.4.21-rc1/include/net/snmp.h	2003-04-21 11:49:07.000000000 -0700
@@ -268,5 +268,8 @@
 #define SNMP_INC_STATS(mib, field) ((mib)[2*smp_processor_id()+!in_softirq()].field++)
 #define SNMP_INC_STATS_BH(mib, field) ((mib)[2*smp_processor_id()].field++)
 #define SNMP_INC_STATS_USER(mib, field) ((mib)[2*smp_processor_id()+1].field++)
- 	
+#define SNMP_ADD_STATS_BH(mib, field, addend)	\
+	((mib)[2*smp_processor_id()].field += addend)
+#define SNMP_ADD_STATS_USER(mib, field, addend)	\
+	((mib)[2*smp_processor_id()+1].field += addend)
 #endif
diff -urN linux-2.4.21-pre7/include/net/sock.h linux-2.4.21-rc1/include/net/sock.h
--- linux-2.4.21-pre7/include/net/sock.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/net/sock.h	2003-04-21 11:49:07.000000000 -0700
@@ -175,6 +175,7 @@
 				ipv6only:1;
 
 	struct ipv6_mc_socklist	*ipv6_mc_list;
+	struct ipv6_ac_socklist	*ipv6_ac_list;
 	struct ipv6_fl_socklist *ipv6_fl_list;
 	__u32			dst_cookie;
 
diff -urN linux-2.4.21-pre7/include/net/tcp.h linux-2.4.21-rc1/include/net/tcp.h
--- linux-2.4.21-pre7/include/net/tcp.h	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/include/net/tcp.h	2003-04-21 11:49:07.000000000 -0700
@@ -30,6 +30,7 @@
 #include <linux/cache.h>
 #include <net/checksum.h>
 #include <net/sock.h>
+#include <net/snmp.h>
 
 /* This is for all connections with a full identity, no wildcards.
  * New scheme, half the table is for TIME_WAIT, the other half is
@@ -623,6 +624,8 @@
 #define TCP_INC_STATS(field)		SNMP_INC_STATS(tcp_statistics, field)
 #define TCP_INC_STATS_BH(field)		SNMP_INC_STATS_BH(tcp_statistics, field)
 #define TCP_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(tcp_statistics, field)
+#define TCP_ADD_STATS_BH(field, val)	SNMP_ADD_STATS_BH(tcp_statistics, field, val)
+#define TCP_ADD_STATS_USER(field, val)	SNMP_ADD_STATS_USER(tcp_statistics, field, val)
 
 extern void			tcp_put_port(struct sock *sk);
 extern void			__tcp_put_port(struct sock *sk);
@@ -1375,6 +1378,9 @@
 		break;
 
 	case TCP_CLOSE:
+		if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED)
+			TCP_INC_STATS(TcpEstabResets);
+
 		sk->prot->unhash(sk);
 		if (sk->prev && !(sk->userlocks&SOCK_BINDPORT_LOCK))
 			tcp_put_port(sk);
@@ -1846,4 +1852,13 @@
 		       tp->snd_una + tp->snd_wnd));
 }
 
+static inline void tcp_mib_init(void)
+{
+	/* See RFC 2012 */
+	TCP_ADD_STATS_USER(TcpRtoAlgorithm, 1);
+	TCP_ADD_STATS_USER(TcpRtoMin, TCP_RTO_MIN*1000/HZ);
+	TCP_ADD_STATS_USER(TcpRtoMax, TCP_RTO_MAX*1000/HZ);
+	TCP_ADD_STATS_USER(TcpMaxConn, -1);
+}
+
 #endif	/* _TCP_H */
diff -urN linux-2.4.21-pre7/net/802/fc.c linux-2.4.21-rc1/net/802/fc.c
--- linux-2.4.21-pre7/net/802/fc.c	1999-11-12 04:29:47.000000000 -0800
+++ linux-2.4.21-rc1/net/802/fc.c	2003-04-21 11:49:08.000000000 -0700
@@ -95,4 +95,37 @@
 	return 0;
 #endif
 }
-	
+
+unsigned short
+fc_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct fch_hdr *fch = (struct fch_hdr *)skb->data;
+	struct fcllc *fcllc;
+
+	skb->mac.raw = skb->data;
+	fcllc = (struct fcllc *)(skb->data + sizeof (struct fch_hdr) + 2);
+	skb_pull(skb, sizeof (struct fch_hdr) + 2);
+
+	if (*fch->daddr & 1) {
+		if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN))
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	} else if (dev->flags & IFF_PROMISC) {
+		if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN))
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+
+	/*
+	 * Strip the SNAP header from ARP packets since we don't pass
+	 * them through to the 802.2/SNAP layers.
+	 */
+	if (fcllc->dsap == EXTENDED_SAP &&
+	    (fcllc->ethertype == ntohs(ETH_P_IP) ||
+	     fcllc->ethertype == ntohs(ETH_P_ARP))) {
+		skb_pull(skb, sizeof (struct fcllc));
+		return fcllc->ethertype;
+	}
+
+	return ntohs(ETH_P_802_2);
+}
diff -urN linux-2.4.21-pre7/net/atm/atm_misc.c linux-2.4.21-rc1/net/atm/atm_misc.c
--- linux-2.4.21-pre7/net/atm/atm_misc.c	2000-03-21 23:38:26.000000000 -0800
+++ linux-2.4.21-rc1/net/atm/atm_misc.c	2003-04-21 11:49:08.000000000 -0700
@@ -16,7 +16,7 @@
 int atm_charge(struct atm_vcc *vcc,int truesize)
 {
 	atm_force_charge(vcc,truesize);
-	if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) return 1;
+	if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) return 1;
 	atm_return(vcc,truesize);
 	atomic_inc(&vcc->stats->rx_drop);
 	return 0;
@@ -29,11 +29,11 @@
 	int guess = atm_guess_pdu2truesize(pdu_size);
 
 	atm_force_charge(vcc,guess);
-	if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) {
+	if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) {
 		struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
 
 		if (skb) {
-			atomic_add(skb->truesize-guess,&vcc->rx_inuse);
+			atomic_add(skb->truesize-guess,&vcc->sk->rmem_alloc);
 			return skb;
 		}
 	}
diff -urN linux-2.4.21-pre7/net/atm/br2684.c linux-2.4.21-rc1/net/atm/br2684.c
--- linux-2.4.21-pre7/net/atm/br2684.c	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/br2684.c	2003-04-21 11:49:08.000000000 -0700
@@ -188,7 +188,7 @@
 		dev_kfree_skb(skb);
 		return 0;
 		}
-	atomic_add(skb->truesize, &atmvcc->tx_inuse);
+	atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0;
 	ATM_SKB(skb)->atm_options = atmvcc->atm_options;
 	brdev->stats.tx_packets++;
@@ -551,7 +551,7 @@
 	barrier();
 	atmvcc->push = br2684_push;
 	skb_queue_head_init(&copy);
-	skb_migrate(&atmvcc->recvq, &copy);
+	skb_migrate(&atmvcc->sk->receive_queue, &copy);
 	while ((skb = skb_dequeue(&copy))) {
 		BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
 		BRPRIV(skb->dev)->stats.rx_packets--;
diff -urN linux-2.4.21-pre7/net/atm/clip.c linux-2.4.21-rc1/net/atm/clip.c
--- linux-2.4.21-pre7/net/atm/clip.c	2001-06-27 17:10:55.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/clip.c	2003-04-21 11:49:08.000000000 -0700
@@ -63,7 +63,7 @@
 	ctrl->itf_num = itf;
 	ctrl->ip = ip;
 	atm_force_charge(atmarpd,skb->truesize);
-	skb_queue_tail(&atmarpd->recvq,skb);
+	skb_queue_tail(&atmarpd->sk->receive_queue,skb);
 	wake_up(&atmarpd->sleep);
 	return 0;
 }
@@ -426,7 +426,7 @@
 		memcpy(here,llc_oui,sizeof(llc_oui));
 		((u16 *) here)[3] = skb->protocol;
 	}
-	atomic_add(skb->truesize,&vcc->tx_inuse);
+	atomic_add(skb->truesize,&vcc->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0;
 	ATM_SKB(skb)->atm_options = vcc->atm_options;
 	entry->vccs->last_use = jiffies;
@@ -485,7 +485,7 @@
 	vcc->push = clip_push;
 	vcc->pop = clip_pop;
 	skb_queue_head_init(&copy);
-	skb_migrate(&vcc->recvq,&copy);
+	skb_migrate(&vcc->sk->receive_queue,&copy);
 	/* re-process everything received between connection setup and MKIP */
 	while ((skb = skb_dequeue(&copy)))
 		if (!clip_devs) {
@@ -690,10 +690,10 @@
 	barrier();
 	unregister_inetaddr_notifier(&clip_inet_notifier);
 	unregister_netdevice_notifier(&clip_dev_notifier);
-	if (skb_peek(&vcc->recvq))
+	if (skb_peek(&vcc->sk->receive_queue))
 		printk(KERN_ERR "atmarpd_close: closing with requests "
 		    "pending\n");
-	skb_queue_purge(&vcc->recvq);
+	skb_queue_purge(&vcc->sk->receive_queue);
 	DPRINTK("(done)\n");
 }
 
diff -urN linux-2.4.21-pre7/net/atm/common.c linux-2.4.21-rc1/net/atm/common.c
--- linux-2.4.21-pre7/net/atm/common.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/common.c	2003-04-21 11:49:08.000000000 -0700
@@ -92,14 +92,14 @@
 {
 	struct sk_buff *skb;
 
-	if (atomic_read(&vcc->tx_inuse) && !atm_may_send(vcc,size)) {
-		DPRINTK("Sorry: tx_inuse = %d, size = %d, sndbuf = %d\n",
-		    atomic_read(&vcc->tx_inuse),size,vcc->sk->sndbuf);
+	if (atomic_read(&vcc->sk->wmem_alloc) && !atm_may_send(vcc,size)) {
+		DPRINTK("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
+		    atomic_read(&vcc->sk->wmem_alloc),size,vcc->sk->sndbuf);
 		return NULL;
 	}
 	while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
-	DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->tx_inuse),skb->truesize);
-	atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
+	DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->sk->wmem_alloc),skb->truesize);
+	atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
 	return skb;
 }
 
@@ -115,21 +115,19 @@
 	vcc = sk->protinfo.af_atm;
 	memset(&vcc->flags,0,sizeof(vcc->flags));
 	vcc->dev = NULL;
-	vcc->family = sock->ops->family;
 	vcc->alloc_tx = alloc_tx;
 	vcc->callback = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
 	memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
 	vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
-	atomic_set(&vcc->tx_inuse,0);
-	atomic_set(&vcc->rx_inuse,0);
+	atomic_set(&vcc->sk->wmem_alloc,0);
+	atomic_set(&vcc->sk->rmem_alloc,0);
 	vcc->push = NULL;
 	vcc->pop = NULL;
 	vcc->push_oam = NULL;
 	vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
 	vcc->atm_options = vcc->aal_options = 0;
 	init_waitqueue_head(&vcc->sleep);
-	skb_queue_head_init(&vcc->recvq);
 	skb_queue_head_init(&vcc->listenq);
 	sk->sleep = &vcc->sleep;
 	sock->sk = sk;
@@ -147,7 +145,7 @@
 	if (vcc->dev) {
 		if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
 		if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
-		while ((skb = skb_dequeue(&vcc->recvq))) {
+		while ((skb = skb_dequeue(&vcc->sk->receive_queue))) {
 			atm_return(vcc,skb->truesize);
 			if (vcc->dev->ops->free_rx_skb)
 				vcc->dev->ops->free_rx_skb(vcc,skb);
@@ -155,10 +153,10 @@
 		}
 		spin_lock (&atm_dev_lock);	
 		fops_put (vcc->dev->ops);
-		if (atomic_read(&vcc->rx_inuse))
+		if (atomic_read(&vcc->sk->rmem_alloc))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
-			    "rx_inuse == %d after closing\n",
-			    atomic_read(&vcc->rx_inuse));
+			    "rmem_alloc == %d after closing\n",
+			    atomic_read(&vcc->sk->rmem_alloc));
 		bind_vcc(vcc,NULL);
 	} else
 		spin_lock (&atm_dev_lock);	
@@ -313,11 +311,15 @@
 		if (error) return error;
 	}
 	else {
-		struct atm_dev *dev;
+		struct atm_dev *dev = NULL;
+		struct list_head *p;
 
 		spin_lock (&atm_dev_lock);
-		for (dev = atm_devs; dev; dev = dev->next)
+		list_for_each(p, &atm_devs) {
+			dev = list_entry(p, struct atm_dev, dev_list);
 			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+			dev = NULL;
+		}
 		spin_unlock (&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
@@ -362,7 +364,7 @@
 	add_wait_queue(&vcc->sleep,&wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	error = 1; /* <= 0 is error */
-	while (!(skb = skb_dequeue(&vcc->recvq))) {
+	while (!(skb = skb_dequeue(&vcc->sk->receive_queue))) {
 		if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
 		    test_bit(ATM_VF_CLOSE,&vcc->flags)) {
 			error = vcc->reply;
@@ -393,7 +395,7 @@
 	if (vcc->dev->ops->feedback)
 		vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data,
 		    (unsigned long) buff,eff_len);
-	DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->rx_inuse),skb->truesize);
+	DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->sk->rmem_alloc),skb->truesize);
 	atm_return(vcc,skb->truesize);
 	if (ATM_SKB(skb)->iovcnt) { /* @@@ hack */
 		/* iovcnt set, use scatter-gather for receive */
@@ -496,14 +498,14 @@
 	vcc = ATM_SD(sock);
 	poll_wait(file,&vcc->sleep,wait);
 	mask = 0;
-	if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq))
+	if (skb_peek(&vcc->sk->receive_queue) || skb_peek(&vcc->listenq))
 		mask |= POLLIN | POLLRDNORM;
 	if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
 	    test_bit(ATM_VF_CLOSE,&vcc->flags))
 		mask |= POLLHUP;
 	if (sock->state != SS_CONNECTING) {
 		if (vcc->qos.txtp.traffic_class != ATM_NONE &&
-		    vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+
+		    vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc)+
 		    ATM_PDU_OVHD <= vcc->sk->sndbuf)
 			mask |= POLLOUT | POLLWRNORM;
 	}
@@ -554,6 +556,7 @@
 int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
 {
 	struct atm_dev *dev;
+	struct list_head *p;
 	struct atm_vcc *vcc;
 	int *tmp_buf, *tmp_p;
 	void *buf;
@@ -570,7 +573,7 @@
 				goto done;
 			}
 			ret_val =  put_user(vcc->sk->sndbuf-
-			    atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
+			    atomic_read(&vcc->sk->wmem_alloc)-ATM_PDU_OVHD,
 			    (int *) arg) ? -EFAULT : 0;
 			goto done;
 		case SIOCINQ:
@@ -581,7 +584,7 @@
 					ret_val = -EINVAL;
 					goto done;
 				}
-				skb = skb_peek(&vcc->recvq);
+				skb = skb_peek(&vcc->sk->receive_queue);
 				ret_val = put_user(skb ? skb->len : 0,(int *) arg)
 				    ? -EFAULT : 0;
 				goto done;
@@ -598,7 +601,7 @@
 				goto done;
 			}
 			size = 0;
-			for (dev = atm_devs; dev; dev = dev->next)
+			list_for_each(p, &atm_devs)
 				size += sizeof(int);
 			if (size > len) {
 				ret_val = -E2BIG;
@@ -610,8 +613,10 @@
 				goto done;
 			}
 			tmp_p = tmp_buf;
-			for (dev = atm_devs; dev; dev = dev->next)
+			list_for_each(p, &atm_devs) {
+				dev = list_entry(p, struct atm_dev, dev_list);
 				*tmp_p++ = dev->number;
+			}
 		        ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
 			    put_user(size, &((struct atm_iobuf *) arg)->length)
 			    ) ? -EFAULT : 0;
@@ -979,7 +984,7 @@
 	if (!error) error = adjust_tp(&qos->rxtp,qos->aal);
 	if (error) return error;
 	if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
-	if (vcc->family == AF_ATMPVC)
+	if (vcc->sk->family == AF_ATMPVC)
 		return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
 	return svc_change_qos(vcc,qos);
 }
diff -urN linux-2.4.21-pre7/net/atm/lec.c linux-2.4.21-rc1/net/atm/lec.c
--- linux-2.4.21-pre7/net/atm/lec.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/lec.c	2003-04-21 11:49:08.000000000 -0700
@@ -123,7 +123,7 @@
 
                 priv = (struct lec_priv *)dev->priv;
                 atm_force_charge(priv->lecd, skb2->truesize);
-                skb_queue_tail(&priv->lecd->recvq, skb2);
+                skb_queue_tail(&priv->lecd->sk->receive_queue, skb2);
                 wake_up(&priv->lecd->sleep);
         }
 
@@ -346,7 +346,7 @@
                 DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name,
                         send_vcc->vpi, send_vcc->vci);       
                 if (atm_may_send(send_vcc, skb2->len)) {
-                        atomic_add(skb2->truesize, &send_vcc->tx_inuse);
+			atomic_add(skb2->truesize, &send_vcc->sk->wmem_alloc);
                         priv->stats.tx_packets++;
                         priv->stats.tx_bytes += skb2->len;
                         send_vcc->send(send_vcc, skb2);
@@ -360,7 +360,7 @@
         ATM_SKB(skb)->iovcnt = 0;
         ATM_SKB(skb)->atm_options = send_vcc->atm_options;
         if (atm_may_send(send_vcc, skb->len)) {
-                atomic_add(skb->truesize, &send_vcc->tx_inuse);
+                atomic_add(skb->truesize, &send_vcc->sk->wmem_alloc);
                 priv->stats.tx_packets++;
                 priv->stats.tx_bytes += skb->len;
                 send_vcc->send(send_vcc, skb);
@@ -404,7 +404,7 @@
         int i;
         char *tmp; /* FIXME */
 
-	atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse);
+	atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
         mesg = (struct atmlec_msg *)skb->data;
         tmp = skb->data;
         tmp += sizeof(struct atmlec_msg);
@@ -510,7 +510,7 @@
                         skb2->len = sizeof(struct atmlec_msg);
                         memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
                         atm_force_charge(priv->lecd, skb2->truesize);
-                        skb_queue_tail(&priv->lecd->recvq, skb2);
+                        skb_queue_tail(&priv->lecd->sk->receive_queue, skb2);
                         wake_up(&priv->lecd->sleep);
                 }
                 if (f != NULL) br_fdb_put_hook(f);
@@ -539,10 +539,10 @@
         netif_stop_queue(dev);
         lec_arp_destroy(priv);
 
-        if (skb_peek(&vcc->recvq))
+        if (skb_peek(&vcc->sk->receive_queue))
 		printk("%s lec_atm_close: closing with messages pending\n",
                        dev->name);
-        while ((skb = skb_dequeue(&vcc->recvq))) {
+        while ((skb = skb_dequeue(&vcc->sk->receive_queue))) {
                 atm_return(vcc, skb->truesize);
 		dev_kfree_skb(skb);
         }
@@ -600,13 +600,13 @@
 		memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
 
         atm_force_charge(priv->lecd, skb->truesize);
-	skb_queue_tail(&priv->lecd->recvq, skb);
+	skb_queue_tail(&priv->lecd->sk->receive_queue, skb);
         wake_up(&priv->lecd->sleep);
 
         if (data != NULL) {
                 DPRINTK("lec: about to send %d bytes of data\n", data->len);
                 atm_force_charge(priv->lecd, data->truesize);
-                skb_queue_tail(&priv->lecd->recvq, data);
+                skb_queue_tail(&priv->lecd->sk->receive_queue, data);
                 wake_up(&priv->lecd->sleep);
         }
 
@@ -688,7 +688,7 @@
 #endif /* DUMP_PACKETS > 0 */
         if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/
                 DPRINTK("%s: To daemon\n",dev->name);
-                skb_queue_tail(&vcc->recvq, skb);
+                skb_queue_tail(&vcc->sk->receive_queue, skb);
                 wake_up(&vcc->sleep);
         } else { /* Data frame, queue to protocol handlers */
                 unsigned char *dst;
@@ -789,16 +789,20 @@
                 size = sizeof(struct lec_priv);
 #ifdef CONFIG_TR
                 if (is_trdev)
-                        dev_lec[i] = init_trdev(NULL, size);
+                        dev_lec[i] = alloc_trdev(size);
                 else
 #endif
-                dev_lec[i] = init_etherdev(NULL, size);
+                dev_lec[i] = alloc_etherdev(size);
                 if (!dev_lec[i])
                         return -ENOMEM;
+                snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
+                if (register_netdev(dev_lec[i])) {
+                        kfree(dev_lec[i]);
+                        return -EINVAL;
+                }
 
                 priv = dev_lec[i]->priv;
                 priv->is_trdev = is_trdev;
-                sprintf(dev_lec[i]->name, "lec%d", i);
                 lec_init(dev_lec[i]);
         } else {
                 priv = dev_lec[i]->priv;
diff -urN linux-2.4.21-pre7/net/atm/mpc.c linux-2.4.21-rc1/net/atm/mpc.c
--- linux-2.4.21-pre7/net/atm/mpc.c	2001-09-30 12:26:08.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/mpc.c	2003-04-21 11:49:08.000000000 -0700
@@ -520,7 +520,7 @@
 		memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr));
 	}
 
-	atomic_add(skb->truesize, &entry->shortcut->tx_inuse);
+	atomic_add(skb->truesize, &entry->shortcut->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */
 	ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
 	entry->shortcut->send(entry->shortcut, skb);
@@ -665,7 +665,7 @@
 	skb->dev = dev;
 	if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) {
 		dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name);
-		skb_queue_tail(&vcc->recvq, skb);           /* Pass control packets to daemon */
+		skb_queue_tail(&vcc->sk->receive_queue, skb);           /* Pass control packets to daemon */
 		wake_up(&vcc->sleep);
 		return;
 	}
@@ -849,7 +849,7 @@
 	mpc->in_ops->destroy_cache(mpc);
 	mpc->eg_ops->destroy_cache(mpc);
 
-	while ( (skb = skb_dequeue(&vcc->recvq)) ){
+	while ( (skb = skb_dequeue(&vcc->sk->receive_queue)) ){
 		atm_return(vcc, skb->truesize);
 		kfree_skb(skb);
 	}
@@ -869,7 +869,7 @@
 	
 	struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
 	struct k_message *mesg = (struct k_message*)skb->data;
-	atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse);
+	atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
 	
 	if (mpc == NULL) {
 		printk("mpoa: msg_from_mpoad: no mpc found\n");
@@ -946,7 +946,7 @@
 	skb_put(skb, sizeof(struct k_message));
 	memcpy(skb->data, mesg, sizeof(struct k_message));
 	atm_force_charge(mpc->mpoad_vcc, skb->truesize);
-	skb_queue_tail(&mpc->mpoad_vcc->recvq, skb);
+	skb_queue_tail(&mpc->mpoad_vcc->sk->receive_queue, skb);
 	wake_up(&mpc->mpoad_vcc->sleep);
 
 	return 0;
@@ -1223,7 +1223,7 @@
 		purge_msg->content.eg_info = entry->ctrl_info;
 
 	atm_force_charge(vcc, skb->truesize);
-	skb_queue_tail(&vcc->recvq, skb);
+	skb_queue_tail(&vcc->sk->receive_queue, skb);
 	wake_up(&vcc->sleep);
 	dprintk("mpoa: purge_egress_shortcut: exiting:\n");
 
diff -urN linux-2.4.21-pre7/net/atm/pppoatm.c linux-2.4.21-rc1/net/atm/pppoatm.c
--- linux-2.4.21-pre7/net/atm/pppoatm.c	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/pppoatm.c	2003-04-21 11:49:08.000000000 -0700
@@ -231,7 +231,7 @@
 		kfree_skb(skb);
 		return 1;
 	}
-	atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->tx_inuse);
+	atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->wmem_alloc);
 	ATM_SKB(skb)->iovcnt = 0;
 	ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
 	DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n",
diff -urN linux-2.4.21-pre7/net/atm/proc.c linux-2.4.21-rc1/net/atm/proc.c
--- linux-2.4.21-pre7/net/atm/proc.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/atm/proc.c	2003-04-21 11:49:08.000000000 -0700
@@ -135,7 +135,7 @@
 	unsigned char *ip;
 	int svc,off,ip_len;
 
-	svc = !clip_vcc || clip_vcc->vcc->family == AF_ATMSVC;
+	svc = !clip_vcc || clip_vcc->vcc->sk->family == AF_ATMSVC;
 	off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC",
 	    !clip_vcc || clip_vcc->encap ? "LLC" : "NULL",
 	    (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/
@@ -210,7 +210,7 @@
 	if (!vcc->dev) here += sprintf(here,"Unassigned    ");
 	else here += sprintf(here,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,
 		    vcc->vci);
-	switch (vcc->family) {
+	switch (vcc->sk->family) {
 		case AF_ATMPVC:
 			here += sprintf(here,"PVC");
 			break;
@@ -218,12 +218,12 @@
 			here += sprintf(here,"SVC");
 			break;
 		default:
-			here += sprintf(here,"%3d",vcc->family);
+			here += sprintf(here,"%3d",vcc->sk->family);
 	}
 	here += sprintf(here," %04lx  %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
 	    vcc->reply,
-	    atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
-	    atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
+	    atomic_read(&vcc->sk->wmem_alloc),vcc->sk->sndbuf,
+	    atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf);
 }
 
 
@@ -303,6 +303,7 @@
 static int atm_devices_info(loff_t pos,char *buf)
 {
 	struct atm_dev *dev;
+	struct list_head *p;
 	int left;
 
 	if (!pos) {
@@ -310,10 +311,14 @@
 		    "AAL(TX,err,RX,err,drop) ...\n");
 	}
 	left = pos-1;
-	for (dev = atm_devs; dev && left; dev = dev->next) left--;
-	if (!dev) return 0;
-	dev_info(dev,buf);
-	return strlen(buf);
+	list_for_each(p, &atm_devs) {
+		dev = list_entry(p, struct atm_dev, dev_list);
+		if (left-- == 0) {
+			dev_info(dev,buf);
+			return strlen(buf);
+		}
+	}
+	return 0;
 }
 
 /*
@@ -324,6 +329,7 @@
 static int atm_pvc_info(loff_t pos,char *buf)
 {
 	struct atm_dev *dev;
+	struct list_head *p;
 	struct atm_vcc *vcc;
 	int left;
 
@@ -332,13 +338,15 @@
 		    "TX(PCR,Class)\n");
 	}
 	left = pos-1;
-	for (dev = atm_devs; dev; dev = dev->next)
+	list_for_each(p, &atm_devs) {
+		dev = list_entry(p, struct atm_dev, dev_list);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->family == PF_ATMPVC &&
+			if (vcc->sk->family == PF_ATMPVC &&
 			    vcc->dev && !left--) {
 				pvc_info(vcc,buf);
 				return strlen(buf);
 			}
+	}
 	return 0;
 }
 
@@ -346,6 +354,7 @@
 static int atm_vc_info(loff_t pos,char *buf)
 {
 	struct atm_dev *dev;
+	struct list_head *p;
 	struct atm_vcc *vcc;
 	int left;
 
@@ -354,12 +363,14 @@
 		    "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
 		    "     Recv buffer\n");
 	left = pos-1;
-	for (dev = atm_devs; dev; dev = dev->next)
+	list_for_each(p, &atm_devs) {
+		dev = list_entry(p, struct atm_dev, dev_list);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
 			if (!left--) {
 				vc_info(vcc,buf);
 				return strlen(buf);
 			}
+	}
 	for (vcc = nodev_vccs; vcc; vcc = vcc->next)
 		if (!left--) {
 			vc_info(vcc,buf);
@@ -373,20 +384,23 @@
 static int atm_svc_info(loff_t pos,char *buf)
 {
 	struct atm_dev *dev;
+	struct list_head *p;
 	struct atm_vcc *vcc;
 	int left;
 
 	if (!pos)
 		return sprintf(buf,"Itf VPI VCI           State      Remote\n");
 	left = pos-1;
-	for (dev = atm_devs; dev; dev = dev->next)
+	list_for_each(p, &atm_devs) {
+		dev = list_entry(p, struct atm_dev, dev_list);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->family == PF_ATMSVC && !left--) {
+			if (vcc->sk->family == PF_ATMSVC && !left--) {
 				svc_info(vcc,buf);
 				return strlen(buf);
 			}
+	}
 	for (vcc = nodev_vccs; vcc; vcc = vcc->next)
-		if (vcc->family == PF_ATMSVC && !left--) {
+		if (vcc->sk->family == PF_ATMSVC && !left--) {
 			svc_info(vcc,buf);
 			return strlen(buf);
 		}
diff -urN linux-2.4.21-pre7/net/atm/raw.c linux-2.4.21-rc1/net/atm/raw.c
--- linux-2.4.21-pre7/net/atm/raw.c	2000-04-14 09:37:20.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/raw.c	2003-04-21 11:49:08.000000000 -0700
@@ -28,7 +28,7 @@
 void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	if (skb) {
-		skb_queue_tail(&vcc->recvq,skb);
+		skb_queue_tail(&vcc->sk->receive_queue,skb);
 		wake_up(&vcc->sleep);
 	}
 }
@@ -36,8 +36,8 @@
 
 static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
 {
-	DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
-	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
+	DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->sk->wmem_alloc,skb->truesize);
+	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
 	dev_kfree_skb_any(skb);
 	wake_up(&vcc->sleep);
 }
diff -urN linux-2.4.21-pre7/net/atm/resources.c linux-2.4.21-rc1/net/atm/resources.c
--- linux-2.4.21-pre7/net/atm/resources.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/atm/resources.c	2003-04-21 11:49:08.000000000 -0700
@@ -22,8 +22,7 @@
 #endif
 
 
-struct atm_dev *atm_devs = NULL;
-static struct atm_dev *last_dev = NULL;
+LIST_HEAD(atm_devs);
 struct atm_vcc *nodev_vccs = NULL;
 extern spinlock_t atm_dev_lock;
 
@@ -38,32 +37,28 @@
 	dev->type = type;
 	dev->signal = ATM_PHY_SIG_UNKNOWN;
 	dev->link_rate = ATM_OC3_PCR;
-	dev->next = NULL;
+	list_add_tail(&dev->dev_list, &atm_devs);
 
-	dev->prev = last_dev;
-
-	if (atm_devs) last_dev->next = dev;
-	else atm_devs = dev;
-	last_dev = dev;
 	return dev;
 }
 
 
 static void free_atm_dev(struct atm_dev *dev)
 {
-	if (dev->prev) dev->prev->next = dev->next;
-	else atm_devs = dev->next;
-	if (dev->next) dev->next->prev = dev->prev;
-	else last_dev = dev->prev;
+	list_del(&dev->dev_list);
 	kfree(dev);
 }
 
 struct atm_dev *atm_find_dev(int number)
 {
 	struct atm_dev *dev;
+	struct list_head *p;
 
-	for (dev = atm_devs; dev; dev = dev->next)
-		if (dev->ops && dev->number == number) return dev;
+	list_for_each(p, &atm_devs) {
+		dev = list_entry(p, struct atm_dev, dev_list);
+		if (dev->ops && dev->number == number)
+			return dev;
+	}
 	return NULL;
 }
 
diff -urN linux-2.4.21-pre7/net/atm/resources.h linux-2.4.21-rc1/net/atm/resources.h
--- linux-2.4.21-pre7/net/atm/resources.h	2000-12-11 13:33:43.000000000 -0800
+++ linux-2.4.21-rc1/net/atm/resources.h	2003-04-21 11:49:08.000000000 -0700
@@ -10,7 +10,7 @@
 #include <linux/atmdev.h>
 
 
-extern struct atm_dev *atm_devs;
+extern struct list_head atm_devs;
 extern struct atm_vcc *nodev_vccs; /* VCCs not linked to any device */
 
 
diff -urN linux-2.4.21-pre7/net/atm/signaling.c linux-2.4.21-rc1/net/atm/signaling.c
--- linux-2.4.21-pre7/net/atm/signaling.c	2001-06-27 17:10:55.000000000 -0700
+++ linux-2.4.21-rc1/net/atm/signaling.c	2003-04-21 11:49:08.000000000 -0700
@@ -61,7 +61,7 @@
 	}
 #endif
 	atm_force_charge(sigd,skb->truesize);
-	skb_queue_tail(&sigd->recvq,skb);
+	skb_queue_tail(&sigd->sk->receive_queue,skb);
 	wake_up(&sigd->sleep);
 }
 
@@ -98,7 +98,7 @@
 	struct atm_vcc *session_vcc;
 
 	msg = (struct atmsvc_msg *) skb->data;
-	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
+	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
 	DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,
 	  (unsigned long) msg->vcc);
 	vcc = *(struct atm_vcc **) &msg->vcc;
@@ -198,7 +198,7 @@
 static void purge_vccs(struct atm_vcc *vcc)
 {
 	while (vcc) {
-		if (vcc->family == PF_ATMSVC &&
+		if (vcc->sk->family == PF_ATMSVC &&
 		    !test_bit(ATM_VF_META,&vcc->flags)) {
 			set_bit(ATM_VF_RELEASED,&vcc->flags);
 			vcc->reply = -EUNATCH;
@@ -212,16 +212,20 @@
 static void sigd_close(struct atm_vcc *vcc)
 {
 	struct atm_dev *dev;
+	struct list_head *p;
 
 	DPRINTK("sigd_close\n");
 	sigd = NULL;
-	if (skb_peek(&vcc->recvq))
+	if (skb_peek(&vcc->sk->receive_queue))
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
-	skb_queue_purge(&vcc->recvq);
+	skb_queue_purge(&vcc->sk->receive_queue);
 	purge_vccs(nodev_vccs);
 
 	spin_lock (&atm_dev_lock);
-	for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+	list_for_each(p, &atm_devs) {
+		dev = list_entry(p, struct atm_dev, dev_list);
+		purge_vccs(dev->vccs);
+	}
 	spin_unlock (&atm_dev_lock);
 }
 
diff -urN linux-2.4.21-pre7/net/core/dev.c linux-2.4.21-rc1/net/core/dev.c
--- linux-2.4.21-pre7/net/core/dev.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/core/dev.c	2003-04-21 11:49:08.000000000 -0700
@@ -547,6 +547,50 @@
 }
 
 /**
+ *	dev_get_by_flags - find any device with given flags
+ *	@if_flags: IFF_* values
+ *	@mask: bitmask of bits in if_flags to check
+ *
+ *	Search for any interface with the given flags. Returns NULL if a device
+ *	is not found or a pointer to the device. The device returned has 
+ *	had a reference added and the pointer is safe until the user calls
+ *	dev_put to indicate they have finished with it.
+ */
+
+struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask)
+{
+	struct net_device *dev;
+
+	read_lock(&dev_base_lock);
+	dev = __dev_get_by_flags(if_flags, mask);
+	if (dev)
+		dev_hold(dev);
+	read_unlock(&dev_base_lock);
+	return dev;
+}
+
+/**
+ *	__dev_get_by_flags - find any device with given flags
+ *	@if_flags: IFF_* values
+ *	@mask: bitmask of bits in if_flags to check
+ *
+ *	Search for any interface with the given flags. Returns NULL if a device
+ *	is not found or a pointer to the device. The caller must hold either
+ *	the RTNL semaphore or @dev_base_lock.
+ */
+
+struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short mask)
+{
+	struct net_device *dev;
+
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		if (((dev->flags ^ if_flags) & mask) == 0)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
  *	dev_alloc_name - allocate a name for a device
  *	@dev: device 
  *	@name: name format string
diff -urN linux-2.4.21-pre7/net/ipv4/igmp.c linux-2.4.21-rc1/net/ipv4/igmp.c
--- linux-2.4.21-pre7/net/ipv4/igmp.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/igmp.c	2003-04-21 11:49:08.000000000 -0700
@@ -258,30 +258,22 @@
 {
 	struct ip_mc_list *im=(struct ip_mc_list *)data;
 	struct in_device *in_dev = im->interface;
-	int err;
 
 	spin_lock(&im->lock);
 	im->tm_running=0;
 
-	if (IGMP_V1_SEEN(in_dev))
-		err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
-	else
-		err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
-
-	/* Failed. Retry later. */
-	if (err) {
-		if (!in_dev->dead)
-			igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
-		goto out;
-	}
-
 	if (im->unsolicit_count) {
 		im->unsolicit_count--;
 		igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
 	}
 	im->reporter = 1;
-out:
 	spin_unlock(&im->lock);
+
+	if (IGMP_V1_SEEN(in_dev))
+		igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
+	else
+		igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
+
 	ip_ma_put(im);
 }
 
diff -urN linux-2.4.21-pre7/net/ipv4/ipip.c linux-2.4.21-rc1/net/ipv4/ipip.c
--- linux-2.4.21-pre7/net/ipv4/ipip.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/ipip.c	2003-04-21 11:49:08.000000000 -0700
@@ -464,11 +464,13 @@
 #endif
 }
 
-static inline void ipip_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
+static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb)
 {
-	if (INET_ECN_is_ce(iph->tos) &&
-	    INET_ECN_is_not_ce(skb->nh.iph->tos))
-		IP_ECN_set_ce(iph);
+	struct iphdr *inner_iph = skb->nh.iph;
+
+	if (INET_ECN_is_ce(outer_iph->tos) &&
+	    INET_ECN_is_not_ce(inner_iph->tos))
+		IP_ECN_set_ce(inner_iph);
 }
 
 int ipip_rcv(struct sk_buff *skb)
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/Config.in linux-2.4.21-rc1/net/ipv4/netfilter/Config.in
--- linux-2.4.21-pre7/net/ipv4/netfilter/Config.in	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/Config.in	2003-04-21 11:49:08.000000000 -0700
@@ -7,6 +7,8 @@
 tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK
 if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
   dep_tristate '  FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
+  dep_tristate '  Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
+  dep_tristate '  TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
   dep_tristate '  IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
 fi
 
@@ -56,6 +58,13 @@
       define_bool CONFIG_IP_NF_NAT_NEEDED y
       dep_tristate '    MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
       dep_tristate '    REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
+      if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then
+        define_tristate CONFIG_IP_NF_NAT_AMANDA m
+      else
+        if [ "$CONFIG_IP_NF_AMANDA" = "y" ]; then
+          define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT
+        fi
+      fi
       bool '    NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         dep_tristate '    Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
@@ -76,6 +85,13 @@
           define_tristate CONFIG_IP_NF_NAT_FTP $CONFIG_IP_NF_NAT
         fi
       fi
+      if [ "$CONFIG_IP_NF_TFTP" = "m" ]; then
+	define_tristate CONFIG_IP_NF_NAT_TFTP m
+      else
+        if [ "$CONFIG_IP_NF_TFTP" = "y" ]; then
+          define_tristate CONFIG_IP_NF_NAT_TFTP $CONFIG_IP_NF_NAT
+        fi
+      fi
     fi
   fi
 
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/Makefile linux-2.4.21-rc1/net/ipv4/netfilter/Makefile
--- linux-2.4.21-pre7/net/ipv4/netfilter/Makefile	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/Makefile	2003-04-21 11:49:08.000000000 -0700
@@ -31,7 +31,16 @@
 # connection tracking
 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
 
+# Amanda protocol support
+obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
+obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
+ifdef CONFIG_IP_NF_NAT_AMANDA
+	export-objs += ip_conntrack_amanda.o
+endif
+
+
 # connection tracking helpers
+obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
 ifdef CONFIG_IP_NF_NAT_FTP
 	export-objs += ip_conntrack_ftp.o
@@ -43,6 +52,7 @@
 endif
 
 # NAT helpers 
+obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
 obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
 
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ip_conntrack_amanda.c linux-2.4.21-rc1/net/ipv4/netfilter/ip_conntrack_amanda.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ip_conntrack_amanda.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ip_conntrack_amanda.c	2003-04-21 11:49:08.000000000 -0700
@@ -0,0 +1,233 @@
+/* Amanda extension for IP connection tracking, Version 0.2
+ * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
+ * based on HW's ip_conntrack_irc.c as well as other modules
+ *
+ *      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.
+ *
+ *	Module load syntax:
+ * 	insmod ip_conntrack_amanda.o [master_timeout=n]
+ *	
+ *	Where master_timeout is the timeout (in seconds) of the master
+ *	connection (port 10080).  This defaults to 5 minutes but if
+ *	your clients take longer than 5 minutes to do their work
+ *	before getting back to the Amanda server, you can increase
+ *	this value.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/udp.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+
+static unsigned int master_timeout = 300;
+
+MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
+MODULE_DESCRIPTION("Amanda connection tracking module");
+MODULE_LICENSE("GPL");
+MODULE_PARM(master_timeout, "i");
+MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
+
+DECLARE_LOCK(ip_amanda_lock);
+struct module *ip_conntrack_amanda = THIS_MODULE;
+
+#define MAXMATCHLEN	6
+struct conn conns[NUM_MSGS] = {
+	{"DATA ", 5},
+	{"MESG ", 5},
+	{"INDEX ", 6},
+};
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+/* FIXME: This should be in userspace.  Later. */
+static int help(const struct iphdr *iph, size_t len,
+		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+{
+	struct udphdr *udph = (void *)iph + iph->ihl * 4;
+	u_int32_t udplen = len - iph->ihl * 4;
+	u_int32_t datalen = udplen - sizeof(struct udphdr);
+	char *data = (char *)udph + sizeof(struct udphdr);
+	char *datap = data;
+	char *data_limit = (char *) data + datalen;
+	int dir = CTINFO2DIR(ctinfo);
+	struct ip_ct_amanda *info =
+				(struct ip_ct_amanda *)&ct->help.ct_ftp_info;
+
+	/* Can't track connections formed before we registered */
+	if (!info)
+		return NF_ACCEPT;
+
+	/* increase the UDP timeout of the master connection as replies from
+	 * Amanda clients to the server can be quite delayed */
+	ip_ct_refresh(ct, master_timeout * HZ);
+
+	/* If packet is coming from Amanda server */
+	if (dir == IP_CT_DIR_ORIGINAL)
+		return NF_ACCEPT;
+
+	/* Not whole UDP header? */
+	if (udplen < sizeof(struct udphdr)) {
+		printk("ip_conntrack_amanda_help: udplen = %u\n",
+		       (unsigned)udplen);
+		return NF_ACCEPT;
+	}
+
+	/* Checksum invalid?  Ignore. */
+	if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
+			      csum_partial((char *)udph, udplen, 0))) {
+		DEBUGP("ip_ct_talk_help: bad csum: %p %u %u.%u.%u.%u "
+		       "%u.%u.%u.%u\n",
+		       udph, udplen, NIPQUAD(iph->saddr),
+		       NIPQUAD(iph->daddr));
+		return NF_ACCEPT;
+	}
+	
+	/* Search for the CONNECT string */
+	while (data < data_limit) {
+		if (!memcmp(data, "CONNECT ", 8)) {
+			break;
+		}
+		data++;
+	}
+	if (memcmp(data, "CONNECT ", 8))
+		return NF_ACCEPT;
+
+	DEBUGP("ip_conntrack_amanda_help: CONNECT found in connection "
+		   "%u.%u.%u.%u:%u %u.%u.%u.%u:%u\n",
+		   NIPQUAD(iph->saddr), htons(udph->source),
+		   NIPQUAD(iph->daddr), htons(udph->dest));
+	data += 8;
+	while (*data != 0x0a && data < data_limit) {
+
+		int i;
+
+		for (i = 0; i < NUM_MSGS; i++) {
+			if (!memcmp(data, conns[i].match,
+				   conns[i].matchlen)) {
+
+				char *portchr;
+				struct ip_conntrack_expect expect;
+				struct ip_ct_amanda_expect
+				    *exp_amanda_info =
+					&expect.help.exp_amanda_info;
+
+				memset(&expect, 0, sizeof(expect));
+
+				data += conns[i].matchlen;
+				/* this is not really tcp, but let's steal an
+				 * idea from a tcp stream helper :-)
+				 */
+				// XXX expect.seq = data - datap;
+				exp_amanda_info->offset = data - datap;
+// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, datap, expect.seq);
+DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, datap, exp_amanda_info->offset);
+				portchr = data;
+				exp_amanda_info->port =
+				    simple_strtoul(data, &data, 10);
+				exp_amanda_info->len = data - portchr;
+
+				/* eat whitespace */
+				while (*data == ' ')
+					data++;
+				DEBUGP ("ip_conntrack_amanda_help: "
+					"CONNECT %s request with port "
+					"%u found\n", conns[i].match,
+					exp_amanda_info->port);
+
+				LOCK_BH(&ip_amanda_lock);
+
+				expect.tuple = ((struct ip_conntrack_tuple)
+						{ { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
+						  { 0 } },
+				  		{ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
+						  { htons(exp_amanda_info->port) },
+				    	  IPPROTO_TCP }});
+				expect.mask = ((struct ip_conntrack_tuple)
+							   { { 0, { 0 } },
+				  				 { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+				expect.expectfn = NULL;
+
+				DEBUGP ("ip_conntrack_amanda_help: "
+					"expect_related: %u.%u.%u.%u:%u - "
+					"%u.%u.%u.%u:%u\n",
+					NIPQUAD(expect.tuple.src.ip),
+					ntohs(expect.tuple.src.u.tcp.port),
+					NIPQUAD(expect.tuple.dst.ip),
+					ntohs(expect.tuple.dst.u.tcp.port));
+				if (ip_conntrack_expect_related(ct, &expect) ==
+				    -EEXIST) {
+					;
+					/* this must be a packet being resent */
+					/* XXX - how do I get the
+					 *       ip_conntrack_expect that
+					 *       already exists so that I can
+					 *       update the .seq so that the
+					 *       nat module rewrites the port
+					 *       numbers?
+					 *       Perhaps I should use the
+					 *       exp_amanda_info instead of
+					 *       .seq.
+					 */
+				}
+				UNLOCK_BH(&ip_amanda_lock);
+			} /* if memcmp(conns) */
+		} /* for .. NUM_MSGS */
+		data++;
+	} /* while (*data != 0x0a && data < data_limit) */
+
+	return NF_ACCEPT;
+}
+
+static struct ip_conntrack_helper amanda_helper;
+
+static void fini(void)
+{
+	DEBUGP("ip_ct_amanda: unregistering helper for port 10080\n");
+	ip_conntrack_helper_unregister(&amanda_helper);
+}
+
+static int __init init(void)
+{
+	int ret;
+
+	memset(&amanda_helper, 0, sizeof(struct ip_conntrack_helper));
+	amanda_helper.tuple.src.u.udp.port = htons(10080);
+	amanda_helper.tuple.dst.protonum = IPPROTO_UDP;
+	amanda_helper.mask.src.u.udp.port = 0xFFFF;
+	amanda_helper.mask.dst.protonum = 0xFFFF;
+	amanda_helper.max_expected = NUM_MSGS;
+	amanda_helper.timeout = 180;
+	amanda_helper.flags = IP_CT_HELPER_F_REUSE_EXPECT;
+	amanda_helper.me = ip_conntrack_amanda;
+	amanda_helper.help = help;
+	amanda_helper.name = "amanda";
+
+	DEBUGP("ip_ct_amanda: registering helper for port 10080\n");
+
+	ret = ip_conntrack_helper_register(&amanda_helper);
+
+	if (ret) {
+		printk("ip_ct_amanda: ERROR registering helper\n");
+		fini();
+		return -EBUSY;
+	}
+	return 0;
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.21-rc1/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ip_conntrack_core.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ip_conntrack_core.c	2003-04-21 11:49:08.000000000 -0700
@@ -273,6 +273,8 @@
 		 * the un-established ones only */
 		if (exp->sibling) {
 			DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
+			/* Indicate that this expectations parent is dead */
+			exp->expectant = NULL;
 			continue;
 		}
 
@@ -324,6 +326,9 @@
 		ip_conntrack_destroyed(ct);
 
 	WRITE_LOCK(&ip_conntrack_lock);
+	/* Delete us from our own list to prevent corruption later */
+	list_del(&ct->sibling_list);
+
 	/* Delete our master expectation */
 	if (ct->master) {
 		/* can't call __unexpect_related here,
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.4.21-rc1/net/ipv4/netfilter/ip_conntrack_tftp.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ip_conntrack_tftp.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ip_conntrack_tftp.c	2003-04-21 11:49:08.000000000 -0700
@@ -0,0 +1,131 @@
+/*
+ * Licensed under GNU GPL version 2 Copyright Magnus Boden <mb@ozaba.mine.nu>
+ * Version: 0.0.7
+ *
+ * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- port to newnat API
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
+
+MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
+MODULE_DESCRIPTION("Netfilter connection tracking module for tftp");
+MODULE_LICENSE("GPL");
+
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_c = 0;
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+MODULE_PARM_DESC(ports, "port numbers of tftp servers");
+#endif
+
+#if 0
+#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ": " \
+				       format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static int tftp_help(const struct iphdr *iph, size_t len,
+	struct ip_conntrack *ct,
+	enum ip_conntrack_info ctinfo)
+{
+	struct udphdr *udph = (void *)iph + iph->ihl * 4;
+	struct tftphdr *tftph = (void *)udph + 8;
+	struct ip_conntrack_expect exp;
+	
+	switch (ntohs(tftph->opcode)) {
+	/* RRQ and WRQ works the same way */
+	case TFTP_OPCODE_READ:
+	case TFTP_OPCODE_WRITE:
+		DEBUGP("");
+		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+		memset(&exp, 0, sizeof(exp));
+
+		exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+		exp.mask.src.ip = 0xffffffff;
+		exp.mask.dst.ip = 0xffffffff;
+		exp.mask.dst.u.udp.port = 0xffff;
+		exp.mask.dst.protonum = 0xffff;
+		exp.expectfn = NULL;
+
+		DEBUGP("expect: ");
+		DUMP_TUPLE(&exp.tuple);
+		DUMP_TUPLE(&exp.mask);
+		ip_conntrack_expect_related(ct, &exp);
+		break;
+	default:
+		DEBUGP("Unknown opcode\n");
+	}
+	return NF_ACCEPT;
+}
+
+static struct ip_conntrack_helper tftp[MAX_PORTS];
+static char tftp_names[MAX_PORTS][10];
+
+static void fini(void)
+{
+	int i;
+
+	for (i = 0 ; i < ports_c; i++) {
+		DEBUGP("unregistering helper for port %d\n",
+			ports[i]);
+		ip_conntrack_helper_unregister(&tftp[i]);
+	} 
+}
+
+static int __init init(void)
+{
+	int i, ret;
+	char *tmpname;
+
+	if (!ports[0])
+		ports[0]=TFTP_PORT;
+
+	for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
+		/* Create helper structure */
+		memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
+
+		tftp[i].tuple.dst.protonum = IPPROTO_UDP;
+		tftp[i].tuple.src.u.udp.port = htons(ports[i]);
+		tftp[i].mask.dst.protonum = 0xFFFF;
+		tftp[i].mask.src.u.udp.port = 0xFFFF;
+		tftp[i].max_expected = 1;
+		tftp[i].timeout = 0;
+		tftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		tftp[i].me = THIS_MODULE;
+		tftp[i].help = tftp_help;
+
+		tmpname = &tftp_names[i][0];
+		if (ports[i] == TFTP_PORT)
+			sprintf(tmpname, "tftp");
+		else
+			sprintf(tmpname, "tftp-%d", i);
+		tftp[i].name = tmpname;
+
+		DEBUGP("port #%d: %d\n", i, ports[i]);
+
+		ret=ip_conntrack_helper_register(&tftp[i]);
+		if (ret) {
+			printk("ERROR registering helper for port %d\n",
+				ports[i]);
+			fini();
+			return(ret);
+		}
+		ports_c++;
+	}
+	return(0);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_amanda.c linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_amanda.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_amanda.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_amanda.c	2003-04-21 11:49:08.000000000 -0700
@@ -0,0 +1,226 @@
+/* Amanda extension for TCP NAT alteration.
+ * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
+ * based on a copy of HW's ip_nat_irc.c as well as other modules
+ *
+ *      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.
+ *
+ *	Module load syntax:
+ * 	insmod ip_nat_amanda.o
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/kernel.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+
+
+#if 0
+#define DEBUGP printk
+#define DUMP_OFFSET(x)	printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
+#else
+#define DEBUGP(format, args...)
+#define DUMP_OFFSET(x)
+#endif
+
+MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
+MODULE_DESCRIPTION("Amanda network address translation module");
+MODULE_LICENSE("GPL");
+
+/* protects amanda part of conntracks */
+DECLARE_LOCK_EXTERN(ip_amanda_lock);
+
+static unsigned int
+amanda_nat_expected(struct sk_buff **pskb,
+		 unsigned int hooknum,
+		 struct ip_conntrack *ct,
+		 struct ip_nat_info *info)
+{
+	struct ip_nat_multi_range mr;
+	u_int32_t newdstip, newsrcip, newip;
+	u_int16_t port;
+	struct ip_ct_amanda_expect *exp_info;
+	struct ip_conntrack *master = master_ct(ct);
+
+	IP_NF_ASSERT(info);
+	IP_NF_ASSERT(master);
+
+	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+
+	DEBUGP("nat_expected: We have a connection!\n");
+	exp_info = &ct->master->help.exp_amanda_info;
+
+	newdstip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+	newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+	DEBUGP("nat_expected: %u.%u.%u.%u->%u.%u.%u.%u\n",
+	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
+
+	port = exp_info->port;
+
+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
+		newip = newsrcip;
+	else
+		newip = newdstip;
+
+	DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
+
+	mr.rangesize = 1;
+	/* We don't want to manip the per-protocol, just the IPs. */
+	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
+	mr.range[0].min_ip = mr.range[0].max_ip = newip;
+
+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
+		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+		mr.range[0].min = mr.range[0].max
+			= ((union ip_conntrack_manip_proto)
+				{ htons(port) });
+	}
+
+	return ip_nat_setup_info(ct, &mr, hooknum);
+}
+
+static int amanda_data_fixup(struct ip_conntrack *ct,
+			  struct sk_buff **pskb,
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
+{
+	u_int32_t newip;
+	/* DATA 99999 MESG 99999 INDEX 99999 */
+	char buffer[6];
+	struct ip_conntrack_expect *exp = expect;
+	struct ip_ct_amanda_expect *ct_amanda_info = &exp->help.exp_amanda_info;
+	struct ip_conntrack_tuple t = exp->tuple;
+	int port;
+
+	MUST_BE_LOCKED(&ip_amanda_lock);
+
+	newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+	DEBUGP ("ip_nat_amanda_help: newip = %u.%u.%u.%u\n", NIPQUAD(newip));
+
+	/* Alter conntrack's expectations. */
+
+	/* We can read expect here without conntrack lock, since it's
+	   only set in ip_conntrack_amanda, with ip_amanda_lock held
+	   writable */
+
+	t.dst.ip = newip;
+	for (port = ct_amanda_info->port + 10; port != 0; port++) {
+		t.dst.u.tcp.port = htons(port);
+		if (ip_conntrack_change_expect(exp, &t) == 0)
+			break;
+	}
+
+	if (port == 0)
+		return 0;
+
+	sprintf(buffer, "%u", port);
+
+	return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, /* XXX exp->seq */ ct_amanda_info->offset, 
+					ct_amanda_info->len, buffer, strlen(buffer));
+}
+
+static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
+			 struct ip_nat_info *info,
+			 enum ip_conntrack_info ctinfo,
+			 unsigned int hooknum,
+			 struct sk_buff **pskb)
+{
+	int dir;
+
+	if (!exp)
+		DEBUGP("ip_nat_amanda: no exp!!");
+		
+	/* Only mangle things once: original direction in POST_ROUTING
+	   and reply direction on PRE_ROUTING. */
+	dir = CTINFO2DIR(ctinfo);
+	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
+	      || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
+		DEBUGP("ip_nat_amanda_help: Not touching dir %s at hook %s\n",
+		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
+		       : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
+		return NF_ACCEPT;
+	}
+	DEBUGP("ip_nat_amanda_help: got beyond not touching: dir %s at hook %s for expect: ",
+		   dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+		   hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+		   : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+		     : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
+		       : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
+	DUMP_TUPLE(&exp->tuple);
+
+	LOCK_BH(&ip_amanda_lock);
+// XXX	if (exp->seq != 0)
+	if (exp->help.exp_amanda_info.offset != 0)
+		/*  if this packet has a "seq" it needs to have it's content mangled */
+		if (!amanda_data_fixup(ct, pskb, ctinfo, exp)) {
+			UNLOCK_BH(&ip_amanda_lock);
+			DEBUGP("ip_nat_amanda: NF_DROP\n");
+			return NF_DROP;
+		}
+	exp->help.exp_amanda_info.offset = 0;
+	UNLOCK_BH(&ip_amanda_lock);
+
+	DEBUGP("ip_nat_amanda: NF_ACCEPT\n");
+	return NF_ACCEPT;
+}
+
+static struct ip_nat_helper ip_nat_amanda_helper;
+
+/* This function is intentionally _NOT_ defined as  __exit, because
+ * it is needed by init() */
+static void fini(void)
+{
+	DEBUGP("ip_nat_amanda: unregistering nat helper\n");
+	ip_nat_helper_unregister(&ip_nat_amanda_helper);
+}
+
+static int __init init(void)
+{
+	int ret = 0;
+	struct ip_nat_helper *hlpr;
+
+	hlpr = &ip_nat_amanda_helper;
+	memset(hlpr, 0, sizeof(struct ip_nat_helper));
+
+	hlpr->tuple.dst.protonum = IPPROTO_UDP;
+	hlpr->tuple.src.u.udp.port = htons(10080);
+	hlpr->mask.src.u.udp.port = 0xFFFF;
+	hlpr->mask.dst.protonum = 0xFFFF;
+	hlpr->help = help;
+	hlpr->flags = 0;
+	hlpr->me = THIS_MODULE;
+	hlpr->expect = amanda_nat_expected;
+
+	hlpr->name = "amanda";
+
+	DEBUGP
+	    ("ip_nat_amanda: Trying to register nat helper\n");
+	ret = ip_nat_helper_register(hlpr);
+
+	if (ret) {
+		printk
+		    ("ip_nat_amanda: error registering nat helper\n");
+		fini();
+		return 1;
+	}
+	return ret;
+}
+
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_helper.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_helper.c	2003-04-21 11:49:08.000000000 -0700
@@ -366,54 +366,49 @@
 }
 			
 
-/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
-static inline int
+/* TCP SACK sequence number adjustment. */
+static inline void
 ip_nat_sack_adjust(struct sk_buff *skb,
-			struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo)
+		   struct ip_conntrack *ct,
+		   enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph;
 	struct tcphdr *tcph;
-	unsigned char *ptr;
-	int length, dir, sack_adjusted = 0;
+	unsigned char *ptr, *optend;
+	unsigned int dir;
 
-	iph = skb->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
-	length = (tcph->doff*4)-sizeof(struct tcphdr);
+	tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4;
+	optend = (unsigned char *)tcph + tcph->doff*4;
 	ptr = (unsigned char *)(tcph+1);
 
 	dir = CTINFO2DIR(ctinfo);
 
-	while (length > 0) {
-		int opcode = *ptr++;
+	while (ptr < optend) {
+		int opcode = ptr[0];
 		int opsize;
 
 		switch (opcode) {
 		case TCPOPT_EOL:
-			return !sack_adjusted;
+			return;
 		case TCPOPT_NOP:
-			length--;
+			ptr++;
 			continue;
 		default:
-			opsize = *ptr++;
-			if (opsize > length) /* no partial opts */
-				return !sack_adjusted;
+			opsize = ptr[1];
+			 /* no partial opts */
+			if (ptr + opsize > optend || opsize < 2)
+				return;
 			if (opcode == TCPOPT_SACK) {
 				/* found SACK */
 				if((opsize >= (TCPOLEN_SACK_BASE
 					       +TCPOLEN_SACK_PERBLOCK)) &&
 				   !((opsize - TCPOLEN_SACK_BASE)
 				     % TCPOLEN_SACK_PERBLOCK))
-					sack_adjust(tcph, ptr-2,
+					sack_adjust(tcph, ptr,
 						    &ct->nat.info.seq[!dir]);
-				
-				sack_adjusted = 1;
 			}
-			ptr += opsize-2;
-			length -= opsize;
+			ptr += opsize;
 		}
 	}
-	return !sack_adjusted;
 }
 
 /* TCP sequence number adjustment */
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_standalone.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_standalone.c	2003-04-21 11:49:08.000000000 -0700
@@ -109,12 +109,6 @@
 		}
 		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
 	case IP_CT_NEW:
-#ifdef CONFIG_IP_NF_NAT_LOCAL
-		/* LOCAL_IN hook doesn't have a chain and thus doesn't care
-		 * about new packets -HW */
-		if (hooknum == NF_IP_LOCAL_IN)
-			return NF_ACCEPT;
-#endif
 		info = &ct->nat.info;
 
 		WRITE_LOCK(&ip_nat_lock);
@@ -130,6 +124,12 @@
 				ret = call_expect(master_ct(ct), pskb, 
 						  hooknum, ct, info);
 			} else {
+#ifdef CONFIG_IP_NF_NAT_LOCAL
+				/* LOCAL_IN hook doesn't have a chain!  */
+				if (hooknum == NF_IP_LOCAL_IN) {
+					ret = NF_ACCEPT;
+				} else
+#endif
 				ret = ip_nat_rule_find(pskb, hooknum, in, out,
 						       ct, info);
 			}
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_tftp.c linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_tftp.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ip_nat_tftp.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ip_nat_tftp.c	2003-04-21 11:49:08.000000000 -0700
@@ -0,0 +1,197 @@
+/*
+ * Licensed under GNU GPL version 2 Copyright Magnus Boden <mb@ozaba.mine.nu>
+ * Version: 0.0.7
+ *
+ * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- Port to newnat API
+ *
+ * This module currently supports DNAT:
+ * iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y
+ *
+ * and SNAT:
+ * iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x }
+ *
+ * It has not been tested with
+ * -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip
+ * If you do test this please let me know if it works or not.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
+MODULE_DESCRIPTION("Netfilter NAT helper for tftp");
+MODULE_LICENSE("GPL");
+
+#define MAX_PORTS 8
+
+static int ports[MAX_PORTS];
+static int ports_c = 0;
+#ifdef MODULE_PARM
+MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i");
+MODULE_PARM_DESC(ports, "port numbers of tftp servers");
+#endif
+
+#if 0
+#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ": " \
+				       format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+static unsigned int 
+tftp_nat_help(struct ip_conntrack *ct,
+	      struct ip_conntrack_expect *exp,
+	      struct ip_nat_info *info,
+	      enum ip_conntrack_info ctinfo,
+	      unsigned int hooknum,
+	      struct sk_buff **pskb)
+{
+	int dir = CTINFO2DIR(ctinfo);
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct udphdr *udph = (void *)iph + iph->ihl * 4;
+	struct tftphdr *tftph = (void *)udph + 8;
+	struct ip_conntrack_tuple repl;
+
+	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
+	      || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) 
+		return NF_ACCEPT;
+
+	if (!exp) {
+		DEBUGP("no conntrack expectation to modify\n");
+		return NF_ACCEPT;
+	}
+
+	switch (ntohs(tftph->opcode)) {
+	/* RRQ and WRQ works the same way */
+	case TFTP_OPCODE_READ:
+	case TFTP_OPCODE_WRITE:
+		repl = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+		DEBUGP("");
+		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+		DEBUGP("expecting: ");
+		DUMP_TUPLE(&repl);
+		DUMP_TUPLE(&exp->mask);
+		ip_conntrack_change_expect(exp, &repl);
+		break;
+	default:
+		DEBUGP("Unknown opcode\n");
+	}               
+
+	return NF_ACCEPT;
+}
+
+static unsigned int 
+tftp_nat_expected(struct sk_buff **pskb,
+		  unsigned int hooknum,
+		  struct ip_conntrack *ct, 
+		  struct ip_nat_info *info) 
+{
+	const struct ip_conntrack *master = ct->master->expectant;
+	const struct ip_conntrack_tuple *orig = 
+			&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+	struct ip_nat_multi_range mr;
+#if 0
+	const struct ip_conntrack_tuple *repl =
+			&master->tuplehash[IP_CT_DIR_REPLY].tuple;
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct udphdr *udph = (void *)iph + iph->ihl*4;
+#endif
+
+	IP_NF_ASSERT(info);
+	IP_NF_ASSERT(master);
+	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+
+	mr.rangesize = 1;
+	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
+
+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
+		mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip; 
+		DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
+			"newsrc: %u.%u.%u.%u\n",
+                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
+			NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
+			NIPQUAD(orig->dst.ip));
+	} else {
+		mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip;
+		mr.range[0].min.udp.port = mr.range[0].max.udp.port = 
+							orig->src.u.udp.port;
+		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+		DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
+			"newdst: %u.%u.%u.%u:%u\n",
+                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
+                        NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
+                        NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port));
+	}
+
+	return ip_nat_setup_info(ct,&mr,hooknum);
+}
+
+static struct ip_nat_helper tftp[MAX_PORTS];
+static char tftp_names[MAX_PORTS][10];
+
+static void fini(void)
+{
+	int i;
+
+	for (i = 0 ; i < ports_c; i++) {
+		DEBUGP("unregistering helper for port %d\n", ports[i]);
+		ip_nat_helper_unregister(&tftp[i]);
+	}
+}
+
+static int __init init(void)
+{
+	int i, ret;
+	char *tmpname;
+
+	if (!ports[0])
+		ports[0] = TFTP_PORT;
+
+	for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
+		memset(&tftp[i], 0, sizeof(struct ip_nat_helper));
+
+		tftp[i].tuple.dst.protonum = IPPROTO_UDP;
+		tftp[i].tuple.src.u.udp.port = htons(ports[i]);
+		tftp[i].mask.dst.protonum = 0xFFFF;
+		tftp[i].mask.src.u.udp.port = 0xFFFF;
+		tftp[i].help = tftp_nat_help;
+		tftp[i].flags = 0;
+		tftp[i].me = THIS_MODULE;
+		tftp[i].expect = tftp_nat_expected;
+
+		tmpname = &tftp_names[i][0];
+		if (ports[i] == TFTP_PORT)
+			sprintf(tmpname, "tftp");
+		else
+			sprintf(tmpname, "tftp-%d", i);
+		tftp[i].name = tmpname;
+		
+		DEBUGP("ip_nat_tftp: registering for port %d: name %s\n",
+			ports[i], tftp[i].name);
+		ret = ip_nat_helper_register(&tftp[i]);
+
+		if (ret) {
+			printk("ip_nat_tftp: unable to register for port %d\n",
+				ports[i]);
+			fini();
+			return ret;
+		}
+		ports_c++;
+	}
+	return ret;
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ipchains_core.c linux-2.4.21-rc1/net/ipv4/netfilter/ipchains_core.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ipchains_core.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ipchains_core.c	2003-04-21 11:49:08.000000000 -0700
@@ -1566,16 +1566,8 @@
 
 /* File offset is actually in records, not bytes. */
 static int ip_chain_procinfo(char *buffer, char **start,
-			     off_t offset, int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			     , int reset
-#endif
-	)
+			     off_t offset, int length)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
 	struct ip_chain *i;
 	struct ip_fwkernel *j = ip_fw_chains->chain;
 	unsigned long flags;
@@ -1612,9 +1604,6 @@
 				len = last_len;
 				goto outside;
 			}
-			else if (reset)
-				memset(j->counters, 0,
-				       sizeof(struct ip_counters)*NUM_SLOTS);
 		}
 	}
 outside:
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ipfwadm_core.c linux-2.4.21-rc1/net/ipv4/netfilter/ipfwadm_core.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ipfwadm_core.c	2002-02-25 11:38:14.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ipfwadm_core.c	2003-04-21 11:49:08.000000000 -0700
@@ -1104,9 +1104,8 @@
 #endif /* CONFIG_IP_FIREWALL */
 
 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
-
 static int ip_chain_procinfo(int stage, char *buffer, char **start,
-			     off_t offset, int length, int reset)
+			     off_t offset, int length)
 {
 	off_t pos=0, begin=0;
 	struct ip_fw *i;
@@ -1177,12 +1176,6 @@
 			len = last_len;
 			break;
 		}
-		else if(reset)
-		{
-			/* This needs to be done at this specific place! */
-			i->fw_pcnt=0L;
-			i->fw_bcnt=0L;
-		}
 		last_len = len;
 		i=i->fw_next;
 	}
@@ -1196,69 +1189,30 @@
 #endif
 
 #ifdef CONFIG_IP_ACCT
-
 static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
-			    int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			    , int reset
-#endif
-	)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length,
-				 reset);
+			    int length)
+{
+	return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length);
 }
-
 #endif
 
 #ifdef CONFIG_IP_FIREWALL
-
 static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset,
-			      int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			     , int reset
-#endif
-	)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length,
-				 reset);
+			      int length)
+{
+	return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length);
 }
 
 static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset,
-			      int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			    , int reset
-#endif
-	)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length,
-				 reset);
+			      int length)
+{
+	return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length);
 }
 
 static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
-			      int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			    , int reset
-#endif
-	)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length,
-				 reset);
+			      int length)
+{
+	return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length);
 }
 #endif
 
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.21-rc1/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/ipt_REJECT.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv4/netfilter/ipt_REJECT.c	2003-04-21 11:49:08.000000000 -0700
@@ -44,6 +44,7 @@
 	u_int16_t tmp_port;
 	u_int32_t tmp_addr;
 	int needs_ack;
+	int hh_len;
 
 	/* IP header checks: fragment, too short. */
 	if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
@@ -63,13 +64,28 @@
 			 csum_partial((char *)otcph, otcplen, 0)) != 0)
 		return;
 
+	/* Routing: if not headed for us, route won't like source */
+	if (ip_route_output(&rt, oldskb->nh.iph->daddr,
+			    local ? oldskb->nh.iph->saddr : 0,
+			    RT_TOS(oldskb->nh.iph->tos) | RTO_CONN,
+			    0) != 0)
+		return;
+
+	hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
+
+
 	/* Copy skb (even if skb is about to be dropped, we can't just
            clone it because there may be other things, such as tcpdump,
-           interested in it) */
-	nskb = skb_copy(oldskb, GFP_ATOMIC);
+           interested in it). We also need to expand headroom in case
+	   hh_len of incoming interface < hh_len of outgoing interface */
+	nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
+			       GFP_ATOMIC);
 	if (!nskb)
 		return;
 
+	dst_release(nskb->dst);
+	nskb->dst = &rt->u.dst;
+
 	/* This packet will not be the same as the other: clear nf fields */
 	nf_conntrack_put(nskb->nfct);
 	nskb->nfct = NULL;
@@ -132,16 +148,6 @@
 	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
 					   nskb->nh.iph->ihl);
 
-	/* Routing: if not headed for us, route won't like source */
-	if (ip_route_output(&rt, nskb->nh.iph->daddr,
-			    local ? nskb->nh.iph->saddr : 0,
-			    RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
-			    0) != 0)
-		goto free_nskb;
-
-	dst_release(nskb->dst);
-	nskb->dst = &rt->u.dst;
-
 	/* "Never happens" */
 	if (nskb->len > nskb->dst->pmtu)
 		goto free_nskb;
diff -urN linux-2.4.21-pre7/net/ipv4/netfilter/iptable_mangle.c linux-2.4.21-rc1/net/ipv4/netfilter/iptable_mangle.c
--- linux-2.4.21-pre7/net/ipv4/netfilter/iptable_mangle.c	2002-02-25 11:38:14.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/netfilter/iptable_mangle.c	2003-04-21 11:49:08.000000000 -0700
@@ -170,7 +170,7 @@
 static struct nf_hook_ops ipt_ops[]
 = { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, 
 	NF_IP_PRI_MANGLE },
-    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN,
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_LOCAL_IN,
 	NF_IP_PRI_MANGLE },
     { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
 	NF_IP_PRI_MANGLE },
diff -urN linux-2.4.21-pre7/net/ipv4/proc.c linux-2.4.21-rc1/net/ipv4/proc.c
--- linux-2.4.21-pre7/net/ipv4/proc.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/proc.c	2003-04-21 11:49:08.000000000 -0700
@@ -134,9 +134,17 @@
 	len += sprintf (buffer + len,
 		"\nTcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
 		  "Tcp:");
-	for (i=0; i<offsetof(struct tcp_mib, __pad)/sizeof(unsigned long); i++)
-		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)tcp_statistics, sizeof(struct tcp_mib), i));
-
+	for (i=0; i<offsetof(struct tcp_mib, __pad)/sizeof(unsigned long); i++) {
+		if (i == (offsetof(struct tcp_mib, TcpMaxConn) / sizeof(unsigned long)))
+			/* MaxConn field is negative, RFC 2012 */
+			len += sprintf(buffer+len, " %ld",
+				       fold_field((unsigned long*)tcp_statistics,
+					          sizeof(struct tcp_mib), i));
+		else
+			len += sprintf(buffer+len, " %lu",
+				       fold_field((unsigned long*)tcp_statistics,
+					          sizeof(struct tcp_mib), i));
+	}
 	len += sprintf (buffer + len,
 		"\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n"
 		  "Udp:");
diff -urN linux-2.4.21-pre7/net/ipv4/route.c linux-2.4.21-rc1/net/ipv4/route.c
--- linux-2.4.21-pre7/net/ipv4/route.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv4/route.c	2003-04-21 11:49:08.000000000 -0700
@@ -825,7 +825,7 @@
 				    rth->u.dst.dev != dev)
 					break;
 
-				dst_clone(&rth->u.dst);
+				dst_hold(&rth->u.dst);
 				read_unlock(&rt_hash_table[hash].lock);
 
 				rt = dst_alloc(&ipv4_dst_ops);
diff -urN linux-2.4.21-pre7/net/ipv4/tcp.c linux-2.4.21-rc1/net/ipv4/tcp.c
--- linux-2.4.21-pre7/net/ipv4/tcp.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv4/tcp.c	2003-04-21 11:49:09.000000000 -0700
@@ -2641,5 +2641,6 @@
 	printk(KERN_INFO "TCP: Hash tables configured (established %d bind %d)\n",
 	       tcp_ehash_size<<1, tcp_bhash_size);
 
+	(void) tcp_mib_init();
 	tcpdiag_init();
 }
diff -urN linux-2.4.21-pre7/net/ipv4/tcp_input.c linux-2.4.21-rc1/net/ipv4/tcp_input.c
--- linux-2.4.21-pre7/net/ipv4/tcp_input.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv4/tcp_input.c	2003-04-21 11:49:09.000000000 -0700
@@ -3338,7 +3338,7 @@
 
 	/*
 	 *	Header prediction.
-	 *	The code losely follows the one in the famous 
+	 *	The code loosely follows the one in the famous 
 	 *	"30 instruction TCP receive" Van Jacobson mail.
 	 *	
 	 *	Van's trick is to deposit buffers into socket queue 
diff -urN linux-2.4.21-pre7/net/ipv6/Makefile linux-2.4.21-rc1/net/ipv6/Makefile
--- linux-2.4.21-pre7/net/ipv6/Makefile	2000-12-29 14:07:24.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv6/Makefile	2003-04-21 11:49:09.000000000 -0700
@@ -9,7 +9,7 @@
 
 O_TARGET := ipv6.o
 
-obj-y :=	af_inet6.o ip6_output.o ip6_input.o addrconf.o sit.o \
+obj-y :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
 		route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
 		protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
diff -urN linux-2.4.21-pre7/net/ipv6/addrconf.c linux-2.4.21-rc1/net/ipv6/addrconf.c
--- linux-2.4.21-pre7/net/ipv6/addrconf.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/addrconf.c	2003-04-21 11:49:09.000000000 -0700
@@ -28,6 +28,8 @@
  *						packets.
  *	YOSHIFUJI Hideaki @USAGI	:	improved accuracy of
  *						address validation timer.
+ *	Yuji SEKIYA @USAGI		:	Don't assign a same IPv6
+ *						address on a same interface.
  */
 
 #include <linux/config.h>
@@ -105,6 +107,8 @@
 static void addrconf_rs_timer(unsigned long data);
 static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
 
+static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev);
+
 static struct notifier_block *inet6addr_chain;
 
 struct ipv6_devconf ipv6_devconf =
@@ -135,21 +139,19 @@
 	MAX_RTR_SOLICITATION_DELAY,	/* rtr solicit delay	*/
 };
 
-int ipv6_addr_type(struct in6_addr *addr)
+/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+
+int ipv6_addr_type(const struct in6_addr *addr)
 {
+	int type;
 	u32 st;
 
 	st = addr->s6_addr32[0];
 
-	/* Consider all addresses with the first three bits different of
-	   000 and 111 as unicasts.
-	 */
-	if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
-	    (st & htonl(0xE0000000)) != htonl(0xE0000000))
-		return IPV6_ADDR_UNICAST;
-
 	if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
-		int type = IPV6_ADDR_MULTICAST;
+		type = IPV6_ADDR_MULTICAST;
 
 		switch((st & htonl(0x00FF0000))) {
 			case __constant_htonl(0x00010000):
@@ -166,29 +168,53 @@
 		};
 		return type;
 	}
+	/* check for reserved anycast addresses */
+	
+	if ((st & htonl(0xE0000000)) &&
+	    ((addr->s6_addr32[2] == htonl(0xFDFFFFFF) &&
+	    (addr->s6_addr32[3] | htonl(0x7F)) == (u32)~0) ||
+	    (addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0)))
+		type = IPV6_ADDR_ANYCAST;
+	else
+		type = IPV6_ADDR_UNICAST;
+
+	/* Consider all addresses with the first three bits different of
+	   000 and 111 as finished.
+	 */
+	if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
+	    (st & htonl(0xE0000000)) != htonl(0xE0000000))
+		return type;
 	
 	if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
-		return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST);
+		return (IPV6_ADDR_LINKLOCAL | type);
 
 	if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
-		return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST);
+		return (IPV6_ADDR_SITELOCAL | type);
 
 	if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
 		if (addr->s6_addr32[2] == 0) {
-			if (addr->s6_addr32[3] == 0)
+			if (addr->in6_u.u6_addr32[3] == 0)
 				return IPV6_ADDR_ANY;
 
 			if (addr->s6_addr32[3] == htonl(0x00000001))
-				return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST);
+				return (IPV6_ADDR_LOOPBACK | type);
 
-			return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST);
+			return (IPV6_ADDR_COMPATv4 | type);
 		}
 
 		if (addr->s6_addr32[2] == htonl(0x0000ffff))
 			return IPV6_ADDR_MAPPED;
 	}
 
-	return IPV6_ADDR_RESERVED;
+	st &= htonl(0xFF000000);
+	if (st == 0)
+		return IPV6_ADDR_RESERVED;
+	st &= htonl(0xFE000000);
+	if (st == htonl(0x02000000))
+		return IPV6_ADDR_RESERVED;	/* for NSAP */
+	if (st == htonl(0x04000000))
+		return IPV6_ADDR_RESERVED;	/* for IPX */
+	return type;
 }
 
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -224,7 +250,6 @@
 	add_timer(&ifp->timer);
 }
 
-
 /* Nobody refers to this device, we may destroy it. */
 
 void in6_dev_finish_destroy(struct inet6_dev *idev)
@@ -303,24 +328,90 @@
 	return idev;
 }
 
+void ipv6_addr_prefix(struct in6_addr *prefix,
+	struct in6_addr *addr, int prefix_len)
+{
+	unsigned long mask;
+	int ncopy, nbits;
+
+	memset(prefix, 0, sizeof(*prefix));
+
+	if (prefix_len <= 0)
+		return;
+	if (prefix_len > 128)
+		prefix_len = 128;
+
+	ncopy = prefix_len / 32;
+	switch (ncopy) {
+	case 4:	prefix->s6_addr32[3] = addr->s6_addr32[3];
+	case 3:	prefix->s6_addr32[2] = addr->s6_addr32[2];
+	case 2:	prefix->s6_addr32[1] = addr->s6_addr32[1];
+	case 1:	prefix->s6_addr32[0] = addr->s6_addr32[0];
+	case 0:	break;
+	}
+	nbits = prefix_len % 32;
+	if (nbits == 0)
+		return;
+
+	mask = ~((1 << (32 - nbits)) - 1);
+	mask = htonl(mask);
+
+	prefix->s6_addr32[ncopy] = addr->s6_addr32[ncopy] & mask;
+}
+
+
+static void dev_forward_change(struct inet6_dev *idev)
+{
+	struct net_device *dev;
+	struct inet6_ifaddr *ifa;
+	struct in6_addr addr;
+
+	if (!idev)
+		return;
+	dev = idev->dev;
+	if (dev && (dev->flags & IFF_MULTICAST)) {
+		ipv6_addr_all_routers(&addr);
+	
+		if (idev->cnf.forwarding)
+			ipv6_dev_mc_inc(dev, &addr);
+		else
+			ipv6_dev_mc_dec(dev, &addr);
+	}
+	for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+		ipv6_addr_prefix(&addr, &ifa->addr, ifa->prefix_len);
+		if (ipv6_addr_any(&addr))
+			continue;
+		if (idev->cnf.forwarding)
+			ipv6_dev_ac_inc(idev->dev, &addr);
+		else
+			ipv6_dev_ac_dec(idev->dev, &addr);
+	}
+}
+
+
 static void addrconf_forward_change(struct inet6_dev *idev)
 {
 	struct net_device *dev;
 
-	if (idev)
+	if (idev) {
+		dev_forward_change(idev);
 		return;
+	}
 
 	read_lock(&dev_base_lock);
 	for (dev=dev_base; dev; dev=dev->next) {
 		read_lock(&addrconf_lock);
 		idev = __in6_dev_get(dev);
-		if (idev)
+		if (idev) {
 			idev->cnf.forwarding = ipv6_devconf.forwarding;
+			dev_forward_change(idev);
+		}
 		read_unlock(&addrconf_lock);
 	}
 	read_unlock(&dev_base_lock);
 }
 
+
 /* Nobody refers to this ifaddr, destroy it */
 
 void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
@@ -347,17 +438,28 @@
 /* On success it returns ifp with increased reference count */
 
 static struct inet6_ifaddr *
-ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen,
+ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 	      int scope, unsigned flags)
 {
 	struct inet6_ifaddr *ifa;
 	int hash;
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+	spin_lock_bh(&lock);
+
+	/* Ignore adding duplicate addresses on an interface */
+	if (ipv6_chk_same_addr(addr, idev->dev)) {
+		spin_unlock_bh(&lock);
+		ADBG(("ipv6_add_addr: already assigned\n"));
+		return ERR_PTR(-EEXIST);
+	}
 
 	ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
 
 	if (ifa == NULL) {
+		spin_unlock_bh(&lock);
 		ADBG(("ipv6_add_addr: malloc failed\n"));
-		return NULL;
+		return ERR_PTR(-ENOBUFS);
 	}
 
 	memset(ifa, 0, sizeof(struct inet6_ifaddr));
@@ -373,8 +475,9 @@
 	read_lock(&addrconf_lock);
 	if (idev->dead) {
 		read_unlock(&addrconf_lock);
+		spin_unlock_bh(&lock);
 		kfree(ifa);
-		return NULL;
+		return ERR_PTR(-ENODEV);	/*XXX*/
 	}
 
 	inet6_ifa_count++;
@@ -399,6 +502,7 @@
 	in6_ifa_hold(ifa);
 	write_unlock_bh(&idev->lock);
 	read_unlock(&addrconf_lock);
+	spin_unlock_bh(&lock);
 
 	notifier_call_chain(&inet6addr_chain,NETDEV_UP,ifa);
 
@@ -458,29 +562,20 @@
  *		an address of the attached interface 
  *	iii)	don't use deprecated addresses
  */
-int ipv6_get_saddr(struct dst_entry *dst,
-		   struct in6_addr *daddr, struct in6_addr *saddr)
+int ipv6_dev_get_saddr(struct net_device *dev,
+		   struct in6_addr *daddr, struct in6_addr *saddr, int onlink)
 {
-	int scope;
 	struct inet6_ifaddr *ifp = NULL;
 	struct inet6_ifaddr *match = NULL;
-	struct net_device *dev = NULL;
 	struct inet6_dev *idev;
-	struct rt6_info *rt;
+	int scope;
 	int err;
 
-	rt = (struct rt6_info *) dst;
-	if (rt)
-		dev = rt->rt6i_dev;
 
-	scope = ipv6_addr_scope(daddr);
-	if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
-		/*
-		 *	route for the "all destinations on link" rule
-		 *	when no routers are present
-		 */
+	if (!onlink)
+		scope = ipv6_addr_scope(daddr);
+	else
 		scope = IFA_LINK;
-	}
 
 	/*
 	 *	known dev
@@ -568,6 +663,24 @@
 	return err;
 }
 
+
+int ipv6_get_saddr(struct dst_entry *dst,
+		   struct in6_addr *daddr, struct in6_addr *saddr)
+{
+	struct rt6_info *rt;
+	struct net_device *dev = NULL;
+	int onlink;
+
+	rt = (struct rt6_info *) dst;
+	if (rt)
+		dev = rt->rt6i_dev;
+
+	onlink = (rt && (rt->rt6i_flags & RTF_ALLONLINK));
+
+	return ipv6_dev_get_saddr(dev, daddr, saddr, onlink);
+}
+
+
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
 {
 	struct inet6_dev *idev;
@@ -621,6 +734,23 @@
 	return ifp != NULL;
 }
 
+static
+int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev)
+{
+	struct inet6_ifaddr * ifp;
+	u8 hash = ipv6_addr_hash(addr);
+
+	read_lock_bh(&addrconf_hash_lock);
+	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+		if (ipv6_addr_cmp(&ifp->addr, addr) == 0) {
+			if (dev == NULL || ifp->idev->dev == dev)
+				break;
+		}
+	}
+	read_unlock_bh(&addrconf_hash_lock);
+	return ifp != NULL;
+}
+
 struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev)
 {
 	struct inet6_ifaddr * ifp;
@@ -660,7 +790,7 @@
 
 /* Join to solicited addr multicast group. */
 
-static void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
+void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr)
 {
 	struct in6_addr maddr;
 
@@ -671,7 +801,7 @@
 	ipv6_dev_mc_inc(dev, &maddr);
 }
 
-static void addrconf_leave_solict(struct net_device *dev, struct in6_addr *addr)
+void addrconf_leave_solict(struct net_device *dev, struct in6_addr *addr)
 {
 	struct in6_addr maddr;
 
@@ -744,7 +874,7 @@
 	if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
 		rtmsg.rtmsg_flags |= RTF_NONEXTHOP;
 
-	ip6_route_add(&rtmsg);
+	ip6_route_add(&rtmsg, NULL);
 }
 
 /* Create "default" multicast route to the interface */
@@ -761,7 +891,7 @@
 	rtmsg.rtmsg_ifindex = dev->ifindex;
 	rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF;
 	rtmsg.rtmsg_type = RTMSG_NEWROUTE;
-	ip6_route_add(&rtmsg);
+	ip6_route_add(&rtmsg, NULL);
 }
 
 static void sit_route_add(struct net_device *dev)
@@ -778,7 +908,7 @@
 	rtmsg.rtmsg_flags	= RTF_UP|RTF_NONEXTHOP;
 	rtmsg.rtmsg_ifindex	= dev->ifindex;
 
-	ip6_route_add(&rtmsg);
+	ip6_route_add(&rtmsg, NULL);
 }
 
 static void addrconf_add_lroute(struct net_device *dev)
@@ -870,7 +1000,7 @@
 	if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
 		if (rt->rt6i_flags&RTF_EXPIRES) {
 			if (pinfo->onlink == 0 || valid_lft == 0) {
-				ip6_del_rt(rt);
+				ip6_del_rt(rt, NULL);
 				rt = NULL;
 			} else {
 				rt->rt6i_expires = rt_expires;
@@ -919,7 +1049,7 @@
 				ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
 						    addr_type&IPV6_ADDR_SCOPE_MASK, 0);
 
-			if (ifp == NULL) {
+			if (IS_ERR(ifp)) {
 				in6_dev_put(in6_dev);
 				return;
 			}
@@ -1034,13 +1164,14 @@
 
 	scope = ipv6_addr_scope(pfx);
 
-	if ((ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT)) != NULL) {
+	ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
+	if (!IS_ERR(ifp)) {
 		addrconf_dad_start(ifp);
 		in6_ifa_put(ifp);
 		return 0;
 	}
 
-	return -ENOBUFS;
+	return PTR_ERR(ifp);
 }
 
 static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen)
@@ -1132,7 +1263,7 @@
 
 	if (addr.s6_addr32[3]) {
 		ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT);
-		if (ifp) {
+		if (!IS_ERR(ifp)) {
 			spin_lock_bh(&ifp->lock);
 			ifp->flags &= ~IFA_F_TENTATIVE;
 			spin_unlock_bh(&ifp->lock);
@@ -1168,7 +1299,7 @@
 
 				ifp = ipv6_add_addr(idev, &addr, plen, flag,
 						    IFA_F_PERMANENT);
-				if (ifp) {
+				if (!IS_ERR(ifp)) {
 					spin_lock_bh(&ifp->lock);
 					ifp->flags &= ~IFA_F_TENTATIVE;
 					spin_unlock_bh(&ifp->lock);
@@ -1182,7 +1313,6 @@
 
 static void init_loopback(struct net_device *dev)
 {
-	struct in6_addr addr;
 	struct inet6_dev  *idev;
 	struct inet6_ifaddr * ifp;
 
@@ -1190,16 +1320,13 @@
 
 	ASSERT_RTNL();
 
-	memset(&addr, 0, sizeof(struct in6_addr));
-	addr.s6_addr32[3] = htonl(0x00000001);
-
 	if ((idev = ipv6_find_idev(dev)) == NULL) {
 		printk(KERN_DEBUG "init loopback: add_dev failed\n");
 		return;
 	}
 
-	ifp = ipv6_add_addr(idev, &addr, 128, IFA_HOST, IFA_F_PERMANENT);
-	if (ifp) {
+	ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT);
+	if (!IS_ERR(ifp)) {
 		spin_lock_bh(&ifp->lock);
 		ifp->flags &= ~IFA_F_TENTATIVE;
 		spin_unlock_bh(&ifp->lock);
@@ -1213,7 +1340,7 @@
 	struct inet6_ifaddr * ifp;
 
 	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
-	if (ifp) {
+	if (!IS_ERR(ifp)) {
 		addrconf_dad_start(ifp);
 		in6_ifa_put(ifp);
 	}
@@ -1456,7 +1583,7 @@
 
 		rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
 
-		ip6_route_add(&rtmsg);
+		ip6_route_add(&rtmsg, NULL);
 	}
 
 out:
@@ -1565,6 +1692,14 @@
 		addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval);
 		spin_unlock_bh(&ifp->lock);
 	}
+
+	if (ifp->idev->cnf.forwarding) {
+		struct in6_addr addr;
+
+		ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
+		if (!ipv6_addr_any(&addr))
+			ipv6_dev_ac_inc(ifp->idev->dev, &addr);
+	}
 }
 
 #ifdef CONFIG_PROC_FS
@@ -1864,6 +1999,13 @@
 		break;
 	case RTM_DELADDR:
 		addrconf_leave_solict(ifp->idev->dev, &ifp->addr);
+		if (ifp->idev->cnf.forwarding) {
+			struct in6_addr addr;
+
+			ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
+			if (!ipv6_addr_any(&addr))
+				ipv6_dev_ac_dec(ifp->idev->dev, &addr);
+		}
 		if (!ipv6_chk_addr(&ifp->addr, NULL))
 			ip6_rt_addr_del(&ifp->addr, ifp->idev->dev);
 		break;
@@ -1886,11 +2028,7 @@
 		struct inet6_dev *idev = NULL;
 
 		if (valp != &ipv6_devconf.forwarding) {
-			struct net_device *dev = dev_get_by_index(ctl->ctl_name);
-			if (dev) {
-				idev = in6_dev_get(dev);
-				dev_put(dev);
-			}
+			idev = (struct inet6_dev *)ctl->extra1;
 			if (idev == NULL)
 				return ret;
 		} else
@@ -1900,8 +2038,6 @@
 
 		if (*valp)
 			rt6_purge_dflt_routers(0);
-		if (idev)
-			in6_dev_put(idev);
 	}
 
         return ret;
@@ -1978,6 +2114,7 @@
 	for (i=0; i<sizeof(t->addrconf_vars)/sizeof(t->addrconf_vars[0])-1; i++) {
 		t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
 		t->addrconf_vars[i].de = NULL;
+		t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
 	}
 	if (dev) {
 		t->addrconf_dev[0].procname = dev->name;
diff -urN linux-2.4.21-pre7/net/ipv6/af_inet6.c linux-2.4.21-rc1/net/ipv6/af_inet6.c
--- linux-2.4.21-pre7/net/ipv6/af_inet6.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/af_inet6.c	2003-04-21 11:49:09.000000000 -0700
@@ -76,6 +76,7 @@
 /* IPv6 procfs goodies... */
 
 #ifdef CONFIG_PROC_FS
+extern int anycast6_get_info(char *, char **, off_t, int);
 extern int raw6_get_info(char *, char **, off_t, int);
 extern int tcp6_get_info(char *, char **, off_t, int);
 extern int udp6_get_info(char *, char **, off_t, int);
@@ -338,6 +339,9 @@
 	/* Free mc lists */
 	ipv6_sock_mc_close(sk);
 
+	/* Free ac lists */
+	ipv6_sock_ac_close(sk);
+
 	return inet_release(sock);
 }
 
@@ -658,6 +662,8 @@
 		goto proc_sockstat6_fail;
 	if (!proc_net_create("snmp6", 0, afinet6_get_snmp))
 		goto proc_snmp6_fail;
+	if (!proc_net_create("anycast6", 0, anycast6_get_info))
+		goto proc_anycast6_fail;
 #endif
 	ipv6_netdev_notif_init();
 	ipv6_packet_init();
@@ -676,6 +682,8 @@
 	return 0;
 
 #ifdef CONFIG_PROC_FS
+proc_anycast6_fail:
+	proc_net_remove("anycast6");
 proc_snmp6_fail:
 	proc_net_remove("sockstat6");
 proc_sockstat6_fail:
@@ -711,6 +719,7 @@
 	proc_net_remove("udp6");
 	proc_net_remove("sockstat6");
 	proc_net_remove("snmp6");
+	proc_net_remove("anycast6");
 #endif
 	/* Cleanup code parts. */
 	sit_cleanup();
diff -urN linux-2.4.21-pre7/net/ipv6/anycast.c linux-2.4.21-rc1/net/ipv6/anycast.c
--- linux-2.4.21-pre7/net/ipv6/anycast.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv6/anycast.c	2003-04-21 11:49:09.000000000 -0700
@@ -0,0 +1,489 @@
+/*
+ *	Anycast support for IPv6
+ *	Linux INET6 implementation 
+ *
+ *	Authors:
+ *	David L Stevens (dlstevens@us.ibm.com)
+ *
+ *	based heavily on net/ipv6/mcast.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/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/route.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/if_inet6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+
+#include <net/checksum.h>
+
+/* Big ac list lock for all the sockets */
+static rwlock_t ipv6_sk_ac_lock = RW_LOCK_UNLOCKED;
+
+/* XXX ip6_addr_match() and ip6_onlink() really belong in net/core.c */
+
+static int
+ip6_addr_match(struct in6_addr *addr1, struct in6_addr *addr2, int prefix)
+{
+	__u32	mask;
+	int	i;
+
+	if (prefix > 128 || prefix < 0)
+		return 0;
+	if (prefix == 0)
+		return 1;
+	for (i=0; i<4; ++i) {
+		if (prefix >= 32)
+			mask = ~0;
+		else
+			mask = htonl(~0 << (32 - prefix));
+		if ((addr1->s6_addr32[i] ^ addr2->s6_addr32[i]) & mask)
+			return 0;
+		prefix -= 32;
+		if (prefix <= 0)
+			break;
+	}
+	return 1;
+}
+
+static int
+ip6_onlink(struct in6_addr *addr, struct net_device *dev)
+{
+	struct inet6_dev	*idev;
+	struct inet6_ifaddr	*ifa;
+	int	onlink;
+
+	onlink = 0;
+	read_lock(&addrconf_lock);
+	idev = __in6_dev_get(dev);
+	if (idev) {
+		read_lock_bh(&idev->lock);
+		for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+			onlink = ip6_addr_match(addr, &ifa->addr,
+					ifa->prefix_len);
+			if (onlink)
+				break;
+		}
+		read_unlock_bh(&idev->lock);
+	}
+	read_unlock(&addrconf_lock);
+	return onlink;
+}
+
+
+/*
+ *	socket join an anycast group
+ */
+
+int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
+{
+	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+	struct net_device *dev = NULL;
+	struct inet6_dev *idev;
+	struct ipv6_ac_socklist *pac;
+	int	ishost = !ipv6_devconf.forwarding;
+	int	err = 0;
+
+	if (ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST)
+		return -EINVAL;
+
+	pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL);
+	if (pac == NULL)
+		return -ENOMEM;
+	pac->acl_next = NULL;
+	ipv6_addr_copy(&pac->acl_addr, addr);
+
+	if (ifindex == 0) {
+		struct rt6_info *rt;
+
+		rt = rt6_lookup(addr, NULL, 0, 0);
+		if (rt) {
+			dev = rt->rt6i_dev;
+			dev_hold(dev);
+			dst_release(&rt->u.dst);
+		} else if (ishost) {
+			sock_kfree_s(sk, pac, sizeof(*pac));
+			return -EADDRNOTAVAIL;
+		} else {
+			/* router, no matching interface: just pick one */
+
+			dev = dev_get_by_flags(IFF_UP, IFF_UP|IFF_LOOPBACK);
+		}
+	} else
+		dev = dev_get_by_index(ifindex);
+
+	if (dev == NULL) {
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		return -ENODEV;
+	}
+
+	idev = in6_dev_get(dev);
+	if (!idev) {
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		dev_put(dev);
+		if (ifindex)
+			return -ENODEV;
+		else
+			return -EADDRNOTAVAIL;
+	}
+	/* reset ishost, now that we have a specific device */
+	ishost = !idev->cnf.forwarding;
+	in6_dev_put(idev);
+
+	pac->acl_ifindex = dev->ifindex;
+
+	/* XXX
+	 * For hosts, allow link-local or matching prefix anycasts.
+	 * This obviates the need for propagating anycast routes while
+	 * still allowing some non-router anycast participation.
+	 *
+	 * allow anyone to join anycasts that don't require a special route
+	 * and can't be spoofs of unicast addresses (reserved anycast only)
+	 */
+	if (!ip6_onlink(addr, dev)) {
+		if (ishost)
+			err = -EADDRNOTAVAIL;
+		else if (!capable(CAP_NET_ADMIN))
+			err = -EPERM;
+		if (err) {
+			sock_kfree_s(sk, pac, sizeof(*pac));
+			dev_put(dev);
+			return err;
+		}
+	} else if (!(ipv6_addr_type(addr) & IPV6_ADDR_ANYCAST) &&
+		   !capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	err = ipv6_dev_ac_inc(dev, addr);
+	if (err) {
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		dev_put(dev);
+		return err;
+	}
+
+	write_lock_bh(&ipv6_sk_ac_lock);
+	pac->acl_next = np->ipv6_ac_list;
+	np->ipv6_ac_list = pac;
+	write_unlock_bh(&ipv6_sk_ac_lock);
+
+	dev_put(dev);
+
+	return 0;
+}
+
+/*
+ *	socket leave an anycast group
+ */
+int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
+{
+	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+	struct net_device *dev;
+	struct ipv6_ac_socklist *pac, *prev_pac;
+
+	write_lock_bh(&ipv6_sk_ac_lock);
+	prev_pac = 0;
+	for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) {
+		if ((ifindex == 0 || pac->acl_ifindex == ifindex) &&
+		     ipv6_addr_cmp(&pac->acl_addr, addr) == 0)
+			break;
+		prev_pac = pac;
+	}
+	if (!pac) {
+		write_unlock_bh(&ipv6_sk_ac_lock);
+		return -ENOENT;
+	}
+	if (prev_pac)
+		prev_pac->acl_next = pac->acl_next;
+	else
+		np->ipv6_ac_list = pac->acl_next;
+
+	write_unlock_bh(&ipv6_sk_ac_lock);
+
+	dev = dev_get_by_index(pac->acl_ifindex);
+	if (dev) {
+		ipv6_dev_ac_dec(dev, &pac->acl_addr);
+		dev_put(dev);
+	}
+	sock_kfree_s(sk, pac, sizeof(*pac));
+	return 0;
+}
+
+void ipv6_sock_ac_close(struct sock *sk)
+{
+	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+	struct net_device *dev = 0;
+	struct ipv6_ac_socklist *pac;
+	int	prev_index;
+
+	write_lock_bh(&ipv6_sk_ac_lock);
+	pac = np->ipv6_ac_list;
+	np->ipv6_ac_list = 0;
+	write_unlock_bh(&ipv6_sk_ac_lock);
+
+	prev_index = 0;
+	while (pac) {
+		struct ipv6_ac_socklist *next = pac->acl_next;
+
+		if (pac->acl_ifindex != prev_index) {
+			if (dev)
+				dev_put(dev);
+			dev = dev_get_by_index(pac->acl_ifindex);
+			prev_index = pac->acl_ifindex;
+		}
+		if (dev)
+			ipv6_dev_ac_dec(dev, &pac->acl_addr);
+		sock_kfree_s(sk, pac, sizeof(*pac));
+		pac = next;
+	}
+	if (dev)
+		dev_put(dev);
+}
+
+int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex)
+{
+	struct ipv6_ac_socklist *pac;
+	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+	int	found;
+
+	found = 0;
+	read_lock(&ipv6_sk_ac_lock);
+	for (pac=np->ipv6_ac_list; pac; pac=pac->acl_next) {
+		if (ifindex && pac->acl_ifindex != ifindex)
+			continue;
+		found = ipv6_addr_cmp(&pac->acl_addr, addr) == 0;
+		if (found)
+			break;
+	}
+	read_unlock(&ipv6_sk_ac_lock);
+
+	return found;
+}
+
+static void aca_put(struct ifacaddr6 *ac)
+{
+	if (atomic_dec_and_test(&ac->aca_refcnt)) {
+		in6_dev_put(ac->aca_idev);
+		kfree(ac);
+	}
+}
+
+/*
+ *	device anycast group inc (add if not found)
+ */
+int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
+{
+	struct ifacaddr6 *aca;
+	struct inet6_dev *idev;
+
+	idev = in6_dev_get(dev);
+
+	if (idev == NULL)
+		return -EINVAL;
+
+	write_lock_bh(&idev->lock);
+	if (idev->dead) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return -ENODEV;
+	}
+
+	for (aca = idev->ac_list; aca; aca = aca->aca_next) {
+		if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0) {
+			aca->aca_users++;
+			write_unlock_bh(&idev->lock);
+			in6_dev_put(idev);
+			return 0;
+		}
+	}
+
+	/*
+	 *	not found: create a new one.
+	 */
+
+	aca = kmalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
+
+	if (aca == NULL) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return -ENOMEM;
+	}
+
+	memset(aca, 0, sizeof(struct ifacaddr6));
+
+	ipv6_addr_copy(&aca->aca_addr, addr);
+	aca->aca_idev = idev;
+	aca->aca_users = 1;
+	atomic_set(&aca->aca_refcnt, 2);
+	aca->aca_lock = SPIN_LOCK_UNLOCKED;
+
+	aca->aca_next = idev->ac_list;
+	idev->ac_list = aca;
+	write_unlock_bh(&idev->lock);
+
+	ip6_rt_addr_add(&aca->aca_addr, dev);
+
+	addrconf_join_solict(dev, &aca->aca_addr);
+
+	aca_put(aca);
+	return 0;
+}
+
+/*
+ *	device anycast group decrement
+ */
+int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
+{
+	struct inet6_dev *idev;
+	struct ifacaddr6 *aca, *prev_aca;
+
+	idev = in6_dev_get(dev);
+	if (idev == NULL)
+		return -ENODEV;
+
+	write_lock_bh(&idev->lock);
+	prev_aca = 0;
+	for (aca = idev->ac_list; aca; aca = aca->aca_next) {
+		if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0)
+			break;
+		prev_aca = aca;
+	}
+	if (!aca) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return -ENOENT;
+	}
+	if (--aca->aca_users > 0) {
+		write_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return 0;
+	}
+	if (prev_aca)
+		prev_aca->aca_next = aca->aca_next;
+	else
+		idev->ac_list = aca->aca_next;
+	write_unlock_bh(&idev->lock);
+	addrconf_leave_solict(dev, &aca->aca_addr);
+
+	ip6_rt_addr_del(&aca->aca_addr, dev);
+
+	aca_put(aca);
+	in6_dev_put(idev);
+	return 0;
+}
+
+/*
+ *	check if the interface has this anycast address
+ */
+static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
+{
+	struct inet6_dev *idev;
+	struct ifacaddr6 *aca;
+
+	idev = in6_dev_get(dev);
+	if (idev) {
+		read_lock_bh(&idev->lock);
+		for (aca = idev->ac_list; aca; aca = aca->aca_next)
+			if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0)
+				break;
+		read_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+		return aca != 0;
+	}
+	return 0;
+}
+
+/*
+ *	check if given interface (or any, if dev==0) has this anycast address
+ */
+int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
+{
+	if (dev)
+		return ipv6_chk_acast_dev(dev, addr);
+	read_lock(&dev_base_lock);
+	for (dev=dev_base; dev; dev=dev->next)
+		if (ipv6_chk_acast_dev(dev, addr))
+			break;
+	read_unlock(&dev_base_lock);
+	return dev != 0;
+}
+
+
+#ifdef CONFIG_PROC_FS
+int anycast6_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos=0, begin=0;
+	struct ifacaddr6 *im;
+	int len=0;
+	struct net_device *dev;
+	
+	read_lock(&dev_base_lock);
+	for (dev = dev_base; dev; dev = dev->next) {
+		struct inet6_dev *idev;
+
+		if ((idev = in6_dev_get(dev)) == NULL)
+			continue;
+
+		read_lock_bh(&idev->lock);
+		for (im = idev->ac_list; im; im = im->aca_next) {
+			int i;
+
+			len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
+
+			for (i=0; i<16; i++)
+				len += sprintf(buffer+len, "%02x", im->aca_addr.s6_addr[i]);
+
+			len += sprintf(buffer+len, " %5d\n", im->aca_users);
+
+			pos=begin+len;
+			if (pos < offset) {
+				len=0;
+				begin=pos;
+			}
+			if (pos > offset+length) {
+				read_unlock_bh(&idev->lock);
+				in6_dev_put(idev);
+				goto done;
+			}
+		}
+		read_unlock_bh(&idev->lock);
+		in6_dev_put(idev);
+	}
+
+done:
+	read_unlock(&dev_base_lock);
+
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if(len>length)
+		len=length;
+	if (len<0)
+		len=0;
+	return len;
+}
+
+#endif
diff -urN linux-2.4.21-pre7/net/ipv6/icmp.c linux-2.4.21-rc1/net/ipv6/icmp.c
--- linux-2.4.21-pre7/net/ipv6/icmp.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/icmp.c	2003-04-21 11:49:09.000000000 -0700
@@ -375,7 +375,8 @@
 
 	saddr = &skb->nh.ipv6h->daddr;
 
-	if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST)
+	if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST ||
+	    ipv6_chk_acast_addr(0, saddr)) 
 		saddr = NULL;
 
 	msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
diff -urN linux-2.4.21-pre7/net/ipv6/ip6_fib.c linux-2.4.21-rc1/net/ipv6/ip6_fib.c
--- linux-2.4.21-pre7/net/ipv6/ip6_fib.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.21-rc1/net/ipv6/ip6_fib.c	2003-04-21 11:49:09.000000000 -0700
@@ -423,7 +423,8 @@
  *	Insert routing information in a node.
  */
 
-static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
+static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
+    struct nlmsghdr *nlh)
 {
 	struct rt6_info *iter = NULL;
 	struct rt6_info **ins;
@@ -481,7 +482,7 @@
 	*ins = rt;
 	rt->rt6i_node = fn;
 	atomic_inc(&rt->rt6i_ref);
-	inet6_rt_notify(RTM_NEWROUTE, rt);
+	inet6_rt_notify(RTM_NEWROUTE, rt, nlh);
 	rt6_stats.fib_rt_entries++;
 
 	if ((fn->fn_flags & RTN_RTINFO) == 0) {
@@ -505,7 +506,7 @@
  *	with source addr info in sub-trees
  */
 
-int fib6_add(struct fib6_node *root, struct rt6_info *rt)
+int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh)
 {
 	struct fib6_node *fn;
 	int err = -ENOMEM;
@@ -578,7 +579,7 @@
 	}
 #endif
 
-	err = fib6_add_rt2node(fn, rt);
+	err = fib6_add_rt2node(fn, rt, nlh);
 
 	if (err == 0) {
 		fib6_start_gc(rt);
@@ -886,7 +887,8 @@
 	}
 }
 
-static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp)
+static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
+    struct nlmsghdr *nlh)
 {
 	struct fib6_walker_t *w;
 	struct rt6_info *rt = *rtp;
@@ -941,11 +943,11 @@
 		if (atomic_read(&rt->rt6i_ref) != 1) BUG();
 	}
 
-	inet6_rt_notify(RTM_DELROUTE, rt);
+	inet6_rt_notify(RTM_DELROUTE, rt, nlh);
 	rt6_release(rt);
 }
 
-int fib6_del(struct rt6_info *rt)
+int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh)
 {
 	struct fib6_node *fn = rt->rt6i_node;
 	struct rt6_info **rtp;
@@ -970,7 +972,7 @@
 
 	for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) {
 		if (*rtp == rt) {
-			fib6_del_route(fn, rtp);
+			fib6_del_route(fn, rtp, nlh);
 			return 0;
 		}
 	}
@@ -1099,7 +1101,7 @@
 		res = c->func(rt, c->arg);
 		if (res < 0) {
 			w->leaf = rt;
-			res = fib6_del(rt);
+			res = fib6_del(rt, NULL);
 			if (res) {
 #if RT6_DEBUG >= 2
 				printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
diff -urN linux-2.4.21-pre7/net/ipv6/ip6_output.c linux-2.4.21-rc1/net/ipv6/ip6_output.c
--- linux-2.4.21-pre7/net/ipv6/ip6_output.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/ip6_output.c	2003-04-21 11:49:09.000000000 -0700
@@ -151,6 +151,7 @@
 	if (dst->error) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
+		dst_release(dst);
 		return -EINVAL;
 	}
 
@@ -545,7 +546,7 @@
 		    || (fl->oif && fl->oif != dst->dev->ifindex)) {
 			dst = NULL;
 		} else
-			dst_clone(dst);
+			dst_hold(dst);
 	}
 
 	if (dst == NULL)
diff -urN linux-2.4.21-pre7/net/ipv6/ipv6_sockglue.c linux-2.4.21-rc1/net/ipv6/ipv6_sockglue.c
--- linux-2.4.21-pre7/net/ipv6/ipv6_sockglue.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/ipv6_sockglue.c	2003-04-21 11:49:09.000000000 -0700
@@ -358,6 +358,24 @@
 			retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
 		break;
 	}
+	case IPV6_JOIN_ANYCAST:
+	case IPV6_LEAVE_ANYCAST:
+	{
+		struct ipv6_mreq mreq;
+
+		if (optlen != sizeof(struct ipv6_mreq))
+			goto e_inval;
+
+		retv = -EFAULT;
+		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
+			break;
+
+		if (optname == IPV6_JOIN_ANYCAST)
+			retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
+		else
+			retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
+		break;
+	}
 	case IPV6_ROUTER_ALERT:
 		retv = ip6_ra_control(sk, val, NULL);
 		break;
diff -urN linux-2.4.21-pre7/net/ipv6/ndisc.c linux-2.4.21-rc1/net/ipv6/ndisc.c
--- linux-2.4.21-pre7/net/ipv6/ndisc.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/ndisc.c	2003-04-21 11:49:09.000000000 -0700
@@ -372,7 +372,10 @@
 		   struct in6_addr *daddr, struct in6_addr *solicited_addr,
 		   int router, int solicited, int override, int inc_opt) 
 {
+	static struct in6_addr tmpaddr;
+	struct inet6_ifaddr *ifp;
         struct sock *sk = ndisc_socket->sk;
+	struct in6_addr *src_addr;
         struct nd_msg *msg;
         int len;
         struct sk_buff *skb;
@@ -388,19 +391,29 @@
 	}
 
 	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, &err);
+				  1, &err);
 
 	if (skb == NULL) {
 		ND_PRINTK1("send_na: alloc skb failed\n");
 		return;
 	}
+	/* for anycast or proxy, solicited_addr != src_addr */
+	ifp = ipv6_get_ifaddr(solicited_addr, dev);
+	if (ifp) {
+		src_addr = solicited_addr;
+		in6_ifa_put(ifp);
+	} else {
+		if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0))
+			return;
+		src_addr = &tmpaddr;
+	}
 
 	if (ndisc_build_ll_hdr(skb, dev, daddr, neigh, len) == 0) {
 		kfree_skb(skb);
 		return;
 	}
 
-	ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len);
+	ip6_nd_hdr(sk, skb, dev, src_addr, daddr, IPPROTO_ICMPV6, len);
 
 	msg = (struct nd_msg *) skb_put(skb, len);
 
@@ -420,7 +433,7 @@
 		ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
 
 	/* checksum */
-	msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len, 
+	msg->icmph.icmp6_cksum = csum_ipv6_magic(src_addr, daddr, len, 
 						 IPPROTO_ICMPV6,
 						 csum_partial((__u8 *) msg, 
 							      len, 0));
@@ -455,7 +468,7 @@
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
 	skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, &err);
+				  1, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
 		return;
@@ -508,7 +521,7 @@
 		len += NDISC_OPT_SPACE(dev->addr_len);
 
         skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				  0, &err);
+				  1, &err);
 	if (skb == NULL) {
 		ND_PRINTK1("send_ns: alloc skb failed\n");
 		return;
@@ -701,6 +714,50 @@
 			}
 		}
 		in6_ifa_put(ifp);
+	} else if (ipv6_chk_acast_addr(dev, &msg->target)) {
+		struct inet6_dev *idev = in6_dev_get(dev);
+		int addr_type = ipv6_addr_type(saddr);
+
+		/* anycast */
+
+		if (!idev) {
+			/* XXX: count this drop? */
+			return;
+		}
+
+		if (addr_type == IPV6_ADDR_ANY) {
+			struct in6_addr maddr;
+
+			ipv6_addr_all_nodes(&maddr);
+			ndisc_send_na(dev, NULL, &maddr, &msg->target,
+				      idev->cnf.forwarding, 0, 0, 1);
+			in6_dev_put(idev);
+			return;
+		}
+
+		if (addr_type & IPV6_ADDR_UNICAST) {
+			int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+			if (inc)  
+				nd_tbl.stats.rcv_probes_mcast++;
+ 			else
+				nd_tbl.stats.rcv_probes_ucast++;
+
+			/*
+			 *   update / create cache entry
+			 *   for the source adddress
+			 */
+
+			neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
+
+			if (neigh || !dev->hard_header) {
+				ndisc_send_na(dev, neigh, saddr,
+					&msg->target, 
+				        idev->cnf.forwarding, 1, 0, inc);
+				if (neigh)
+					neigh_release(neigh);
+			}
+		}
+		in6_dev_put(idev);
 	} else {
 		struct inet6_dev *in6_dev = in6_dev_get(dev);
 		int addr_type = ipv6_addr_type(saddr);
@@ -814,7 +871,7 @@
 					/* It is safe only because
 					   we aer in BH */
 					dst_release(&rt->u.dst);
-					ip6_del_rt(rt);
+					ip6_del_rt(rt, NULL);
 				}
 			}
 		} else {
@@ -889,7 +946,7 @@
 	rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
 	if (rt && lifetime == 0) {
-		ip6_del_rt(rt);
+		ip6_del_rt(rt, NULL);
 		rt = NULL;
 	}
 
@@ -1169,7 +1226,7 @@
  	}
 
 	buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
-				   0, &err);
+				   1, &err);
 	if (buff == NULL) {
 		ND_PRINTK1("ndisc_send_redirect: alloc_skb failed\n");
 		return;
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/Makefile linux-2.4.21-rc1/net/ipv6/netfilter/Makefile
--- linux-2.4.21-pre7/net/ipv6/netfilter/Makefile	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/Makefile	2003-04-21 11:49:09.000000000 -0700
@@ -30,6 +30,6 @@
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
-obj-$(CONFIG_IP_NF_MATCH_HL) += ip6t_hl.o
+obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_ah.c linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_ah.c
--- linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_ah.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_ah.c	2003-04-21 11:49:09.000000000 -0700
@@ -27,17 +27,6 @@
        __u32   spi;
 };
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -80,7 +69,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_ah header iteration \n");
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_dst.c linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_dst.c
--- linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_dst.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_dst.c	2003-04-21 11:49:09.000000000 -0700
@@ -30,17 +30,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /*
  * (Type & 0xC0) >> 6
  * 	0	-> ignorable
@@ -85,7 +74,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_opts header iteration \n");
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_esp.c linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_esp.c
--- linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_esp.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_esp.c	2003-04-21 11:49:09.000000000 -0700
@@ -24,17 +24,6 @@
 	__u32   spi;
 };
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -75,7 +64,7 @@
 	len = skb->len - ptr;
 	temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
         	struct ipv6_opt_hdr *hdr;
         	int hdrlen;
 
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_frag.c linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_frag.c
--- linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_frag.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_frag.c	2003-04-21 11:49:09.000000000 -0700
@@ -45,17 +45,6 @@
        __u32   id;
 };
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the id is matched by the range, 0 otherwise */
 static inline int
 id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
@@ -94,7 +83,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_frag header iteration \n");
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_hbh.c linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_hbh.c
--- linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_hbh.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_hbh.c	2003-04-21 11:49:09.000000000 -0700
@@ -30,17 +30,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /*
  * (Type & 0xC0) >> 6
  * 	0	-> ignorable
@@ -85,7 +74,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_opts header iteration \n");
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_ipv6header.c
--- linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_ipv6header.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_ipv6header.c	2003-04-21 11:49:09.000000000 -0700
@@ -25,17 +25,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 static int
 ipv6header_match(const struct sk_buff *skb,
 		 const struct net_device *in,
@@ -96,7 +85,7 @@
 
 	temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
         	struct ipv6_opt_hdr *hdr;
         	int hdrlen;
 
diff -urN linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_rt.c linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_rt.c
--- linux-2.4.21-pre7/net/ipv6/netfilter/ip6t_rt.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/netfilter/ip6t_rt.c	2003-04-21 11:49:09.000000000 -0700
@@ -22,17 +22,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-int ipv6_ext_hdr(u8 nexthdr)
-{
-        return ( (nexthdr == NEXTHDR_HOP)       ||
-                 (nexthdr == NEXTHDR_ROUTING)   ||
-                 (nexthdr == NEXTHDR_FRAGMENT)  ||
-                 (nexthdr == NEXTHDR_AUTH)      ||
-                 (nexthdr == NEXTHDR_ESP)       ||
-                 (nexthdr == NEXTHDR_NONE)      ||
-                 (nexthdr == NEXTHDR_DEST) );
-}
-
 /* Returns 1 if the id is matched by the range, 0 otherwise */
 static inline int
 segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
@@ -72,7 +61,7 @@
        len = skb->len - ptr;
        temp = 0;
 
-        while (ipv6_ext_hdr(nexthdr)) {
+        while (ip6t_ext_hdr(nexthdr)) {
                struct ipv6_opt_hdr *hdr;
 
               DEBUGP("ipv6_rt header iteration \n");
diff -urN linux-2.4.21-pre7/net/ipv6/route.c linux-2.4.21-rc1/net/ipv6/route.c
--- linux-2.4.21-pre7/net/ipv6/route.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/route.c	2003-04-21 11:49:09.000000000 -0700
@@ -261,12 +261,12 @@
    be destroyed.
  */
 
-static int rt6_ins(struct rt6_info *rt)
+static int rt6_ins(struct rt6_info *rt, struct nlmsghdr *nlh)
 {
 	int err;
 
 	write_lock_bh(&rt6_lock);
-	err = fib6_add(&ip6_routing_table, rt);
+	err = fib6_add(&ip6_routing_table, rt, nlh);
 	write_unlock_bh(&rt6_lock);
 
 	return err;
@@ -307,9 +307,9 @@
 
 		rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
 
-		dst_clone(&rt->u.dst);
+		dst_hold(&rt->u.dst);
 
-		err = rt6_ins(rt);
+		err = rt6_ins(rt, NULL);
 		if (err == 0)
 			return rt;
 
@@ -317,7 +317,7 @@
 
 		return rt;
 	}
-	dst_clone(&ip6_null_entry.u.dst);
+	dst_hold(&ip6_null_entry.u.dst);
 	return &ip6_null_entry;
 }
 
@@ -357,7 +357,7 @@
 if (rt == &ip6_null_entry && strict) { \
        while ((fn = fn->parent) != NULL) { \
 		if (fn->fn_flags & RTN_ROOT) { \
-			dst_clone(&rt->u.dst); \
+			dst_hold(&rt->u.dst); \
 			goto out; \
 		} \
 		if (fn->fn_flags & RTN_RTINFO) \
@@ -388,7 +388,7 @@
 		if (ip6_rt_policy == 0) {
 			rt = rt6_device_match(rt, skb->dev->ifindex, strict);
 			BACKTRACK();
-			dst_clone(&rt->u.dst);
+			dst_hold(&rt->u.dst);
 			goto out;
 		}
 
@@ -399,7 +399,7 @@
 			for (sprt = rt; sprt; sprt = sprt->u.next) {
 				if (rt6_flow_match_in(sprt, skb)) {
 					rt = sprt;
-					dst_clone(&rt->u.dst);
+					dst_hold(&rt->u.dst);
 					goto out;
 				}
 			}
@@ -424,7 +424,7 @@
 			 */
 			goto relookup;
 		}
-		dst_clone(&rt->u.dst);
+		dst_hold(&rt->u.dst);
 	} else {
 #ifdef CONFIG_RT6_POLICY
 		rt = rt6_flow_lookup_in(rt, skb);
@@ -463,7 +463,7 @@
 		if (ip6_rt_policy == 0) {
 			rt = rt6_device_match(rt, fl->oif, strict);
 			BACKTRACK();
-			dst_clone(&rt->u.dst);
+			dst_hold(&rt->u.dst);
 			goto out;
 		}
 
@@ -474,7 +474,7 @@
 			for (sprt = rt; sprt; sprt = sprt->u.next) {
 				if (rt6_flow_match_out(sprt, sk)) {
 					rt = sprt;
-					dst_clone(&rt->u.dst);
+					dst_hold(&rt->u.dst);
 					goto out;
 				}
 			}
@@ -504,7 +504,7 @@
 			 */
 			goto relookup;
 		}
-		dst_clone(&rt->u.dst);
+		dst_hold(&rt->u.dst);
 	} else {
 #ifdef CONFIG_RT6_POLICY
 		rt = rt6_flow_lookup_out(rt, sk, fl);
@@ -555,7 +555,7 @@
 
 	if (rt) {
 		if (rt->rt6i_flags & RTF_CACHE)
-			ip6_del_rt(rt);
+			ip6_del_rt(rt, NULL);
 		else
 			dst_release(dst);
 	}
@@ -648,9 +648,10 @@
  *
  */
 
-int ip6_route_add(struct in6_rtmsg *rtmsg)
+int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh)
 {
 	int err;
+	struct rtmsg *r;
 	struct rt6_info *rt;
 	struct net_device *dev = NULL;
 	int addr_type;
@@ -671,6 +672,11 @@
 
 	rt->u.dst.obsolete = -1;
 	rt->rt6i_expires = rtmsg->rtmsg_info;
+	if (nlh && (r = NLMSG_DATA(nlh))) {
+		rt->rt6i_protocol = r->rtm_protocol;
+	} else {
+		rt->rt6i_protocol = RTPROT_BOOT;
+	}
 
 	addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst);
 
@@ -795,7 +801,7 @@
 	if (rt->u.dst.advmss > 65535-20)
 		rt->u.dst.advmss = 65535;
 	rt->u.dst.dev = dev;
-	return rt6_ins(rt);
+	return rt6_ins(rt, nlh);
 
 out:
 	if (dev)
@@ -804,7 +810,7 @@
 	return err;
 }
 
-int ip6_del_rt(struct rt6_info *rt)
+int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh)
 {
 	int err;
 
@@ -816,13 +822,13 @@
 
 	dst_release(&rt->u.dst);
 
-	err = fib6_del(rt);
+	err = fib6_del(rt, nlh);
 	write_unlock_bh(&rt6_lock);
 
 	return err;
 }
 
-int ip6_route_del(struct in6_rtmsg *rtmsg)
+int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh)
 {
 	struct fib6_node *fn;
 	struct rt6_info *rt;
@@ -846,10 +852,10 @@
 			if (rtmsg->rtmsg_metric &&
 			    rtmsg->rtmsg_metric != rt->rt6i_metric)
 				continue;
-			dst_clone(&rt->u.dst);
+			dst_hold(&rt->u.dst);
 			read_unlock_bh(&rt6_lock);
 
-			return ip6_del_rt(rt);
+			return ip6_del_rt(rt, nlh);
 		}
 	}
 	read_unlock_bh(&rt6_lock);
@@ -909,7 +915,7 @@
 			read_lock(&rt6_lock);
 			for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) {
 				if (!ipv6_addr_cmp(saddr, &rt1->rt6i_gateway)) {
-					dst_clone(&rt1->u.dst);
+					dst_hold(&rt1->u.dst);
 					dst_release(&rt->u.dst);
 					read_unlock(&rt6_lock);
 					rt = rt1;
@@ -951,11 +957,11 @@
 		rt->u.dst.advmss = 65535;
 	nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev);
 
-	if (rt6_ins(nrt))
+	if (rt6_ins(nrt, NULL))
 		goto out;
 
 	if (rt->rt6i_flags&RTF_CACHE) {
-		ip6_del_rt(rt);
+		ip6_del_rt(rt, NULL);
 		return;
 	}
 
@@ -1041,7 +1047,7 @@
 		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
 		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
 		nrt->u.dst.pmtu = pmtu;
-		rt6_ins(nrt);
+		rt6_ins(nrt, NULL);
 	}
 
 out:
@@ -1096,7 +1102,7 @@
 			break;
 	}
 	if (rt)
-		dst_clone(&rt->u.dst);
+		dst_hold(&rt->u.dst);
 	write_unlock_bh(&rt6_lock);
 	return rt;
 }
@@ -1114,7 +1120,7 @@
 
 	rtmsg.rtmsg_ifindex = dev->ifindex;
 
-	ip6_route_add(&rtmsg);
+	ip6_route_add(&rtmsg, NULL);
 	return rt6_get_dflt_router(gwaddr, dev);
 }
 
@@ -1140,7 +1146,7 @@
 
 			read_unlock_bh(&rt6_lock);
 
-			ip6_del_rt(rt);
+			ip6_del_rt(rt, NULL);
 
 			goto restart;
 		}
@@ -1166,10 +1172,10 @@
 		rtnl_lock();
 		switch (cmd) {
 		case SIOCADDRT:
-			err = ip6_route_add(&rtmsg);
+			err = ip6_route_add(&rtmsg, NULL);
 			break;
 		case SIOCDELRT:
-			err = ip6_route_del(&rtmsg);
+			err = ip6_route_del(&rtmsg, NULL);
 			break;
 		default:
 			err = -EINVAL;
@@ -1226,7 +1232,7 @@
 
 	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
 	rt->rt6i_dst.plen = 128;
-	rt6_ins(rt);
+	rt6_ins(rt, NULL);
 
 	return 0;
 }
@@ -1243,7 +1249,7 @@
 	rt = rt6_lookup(addr, NULL, loopback_dev.ifindex, 1);
 	if (rt) {
 		if (rt->rt6i_dst.plen == 128)
-			err = ip6_del_rt(rt);
+			err = ip6_del_rt(rt, NULL);
 		else
 			dst_release(&rt->u.dst);
 	}
@@ -1350,7 +1356,7 @@
 	}
 
 error:
-	dst_clone(&ip6_null_entry.u.dst);
+	dst_hold(&ip6_null_entry.u.dst);
 	return &ip6_null_entry;
 
 found:
@@ -1358,8 +1364,8 @@
 		goto error;
 
 	nrt->rt6i_flags |= RTF_CACHE;
-	dst_clone(&nrt->u.dst);
-	err = rt6_ins(nrt);
+	dst_hold(&nrt->u.dst);
+	err = rt6_ins(nrt, NULL);
 	if (err)
 		nrt->u.dst.error = err;
 	return nrt;
@@ -1486,7 +1492,7 @@
 
 	if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
 		return -EINVAL;
-	return ip6_route_del(&rtmsg);
+	return ip6_route_del(&rtmsg, nlh);
 }
 
 int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
@@ -1496,7 +1502,7 @@
 
 	if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
 		return -EINVAL;
-	return ip6_route_add(&rtmsg);
+	return ip6_route_add(&rtmsg, nlh);
 }
 
 struct rt6_rtnl_dump_arg
@@ -1509,13 +1515,18 @@
 			 struct in6_addr *dst,
 			 struct in6_addr *src,
 			 int iif,
-			 int type, u32 pid, u32 seq)
+			 int type, u32 pid, u32 seq,
+			 struct nlmsghdr *in_nlh)
 {
 	struct rtmsg *rtm;
 	struct nlmsghdr  *nlh;
 	unsigned char	 *b = skb->tail;
 	struct rta_cacheinfo ci;
 
+	if (!pid && in_nlh) {
+		pid = in_nlh->nlmsg_pid;
+	}
+
 	nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*rtm));
 	rtm = NLMSG_DATA(nlh);
 	rtm->rtm_family = AF_INET6;
@@ -1531,7 +1542,7 @@
 		rtm->rtm_type = RTN_UNICAST;
 	rtm->rtm_flags = 0;
 	rtm->rtm_scope = RT_SCOPE_UNIVERSE;
-	rtm->rtm_protocol = RTPROT_BOOT;
+	rtm->rtm_protocol = rt->rt6i_protocol;
 	if (rt->rt6i_flags&RTF_DYNAMIC)
 		rtm->rtm_protocol = RTPROT_REDIRECT;
 	else if (rt->rt6i_flags&(RTF_ADDRCONF|RTF_ALLONLINK))
@@ -1594,7 +1605,8 @@
 	struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
 
 	return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
-			     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq);
+		     NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
+		     NULL);
 }
 
 static int fib6_dump_node(struct fib6_walker_t *w)
@@ -1744,7 +1756,8 @@
 			    fl.nl_u.ip6_u.daddr,
 			    fl.nl_u.ip6_u.saddr,
 			    iif,
-			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq);
+			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
+			    nlh->nlmsg_seq, nlh);
 	if (err < 0) {
 		err = -EMSGSIZE;
 		goto out_free;
@@ -1760,7 +1773,7 @@
 	goto out;	
 }
 
-void inet6_rt_notify(int event, struct rt6_info *rt)
+void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh)
 {
 	struct sk_buff *skb;
 	int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
@@ -1770,7 +1783,7 @@
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
 		return;
 	}
-	if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0) < 0) {
+	if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh) < 0) {
 		kfree_skb(skb);
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
 		return;
diff -urN linux-2.4.21-pre7/net/ipv6/tcp_ipv6.c linux-2.4.21-rc1/net/ipv6/tcp_ipv6.c
--- linux-2.4.21-pre7/net/ipv6/tcp_ipv6.c	2003-04-21 11:48:36.000000000 -0700
+++ linux-2.4.21-rc1/net/ipv6/tcp_ipv6.c	2003-04-21 11:49:09.000000000 -0700
@@ -775,7 +775,7 @@
 
 			dst = ip6_route_output(sk, &fl);
 		} else
-			dst_clone(dst);
+			dst_hold(dst);
 
 		if (dst->error) {
 			sk->err_soft = -dst->error;
@@ -936,7 +936,7 @@
 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
 
 	if (skb->ip_summed == CHECKSUM_HW) {
-		th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,  0);
+		th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,  0);
 		skb->csum = offsetof(struct tcphdr, check);
 	} else {
 		th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 
diff -urN linux-2.4.21-pre7/net/netsyms.c linux-2.4.21-rc1/net/netsyms.c
--- linux-2.4.21-pre7/net/netsyms.c	2003-04-21 11:48:37.000000000 -0700
+++ linux-2.4.21-rc1/net/netsyms.c	2003-04-21 11:49:09.000000000 -0700
@@ -480,6 +480,8 @@
 EXPORT_SYMBOL(unregister_netdevice);
 EXPORT_SYMBOL(netdev_state_change);
 EXPORT_SYMBOL(dev_new_index);
+EXPORT_SYMBOL(dev_get_by_flags);
+EXPORT_SYMBOL(__dev_get_by_flags);
 EXPORT_SYMBOL(dev_get_by_index);
 EXPORT_SYMBOL(__dev_get_by_index);
 EXPORT_SYMBOL(dev_get_by_name);
diff -urN linux-2.4.21-pre7/net/sched/cls_rsvp.h linux-2.4.21-rc1/net/sched/cls_rsvp.h
--- linux-2.4.21-pre7/net/sched/cls_rsvp.h	2001-12-21 09:42:06.000000000 -0800
+++ linux-2.4.21-rc1/net/sched/cls_rsvp.h	2003-04-21 11:49:09.000000000 -0700
@@ -149,11 +149,6 @@
 	struct iphdr *nhptr = skb->nh.iph;
 #endif
 
-#if !defined( __i386__) && !defined(__mc68000__)
-	if ((unsigned long)nhptr & 3)
-		return -1;
-#endif
-
 restart:
 
 #if RSVP_DST_LEN == 4
diff -urN linux-2.4.21-pre7/net/sched/cls_u32.c linux-2.4.21-rc1/net/sched/cls_u32.c
--- linux-2.4.21-pre7/net/sched/cls_u32.c	2001-12-21 09:42:06.000000000 -0800
+++ linux-2.4.21-rc1/net/sched/cls_u32.c	2003-04-21 11:49:10.000000000 -0700
@@ -112,11 +112,6 @@
 	int sel = 0;
 	int i;
 
-#if !defined(__i386__) && !defined(__mc68000__)
-	if ((unsigned long)ptr & 3)
-		return -1;
-#endif
-
 next_ht:
 	n = ht->ht[sel];
 
diff -urN linux-2.4.21-pre7/net/sched/sch_atm.c linux-2.4.21-rc1/net/sched/sch_atm.c
--- linux-2.4.21-pre7/net/sched/sch_atm.c	2001-12-21 09:42:06.000000000 -0800
+++ linux-2.4.21-rc1/net/sched/sch_atm.c	2003-04-21 11:49:10.000000000 -0700
@@ -511,7 +511,7 @@
 			ATM_SKB(skb)->vcc = flow->vcc;
 			memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
 			    flow->hdr_len);
-			atomic_add(skb->truesize,&flow->vcc->tx_inuse);
+			atomic_add(skb->truesize,&flow->vcc->sk->wmem_alloc);
 			ATM_SKB(skb)->iovcnt = 0;
 			/* atm.atm_options are already set by atm_tc_enqueue */
 			(void) flow->vcc->send(flow->vcc,skb);
diff -urN linux-2.4.21-pre7/net/sched/sch_csz.c linux-2.4.21-rc1/net/sched/sch_csz.c
--- linux-2.4.21-pre7/net/sched/sch_csz.c	2001-12-21 09:42:06.000000000 -0800
+++ linux-2.4.21-rc1/net/sched/sch_csz.c	2003-04-21 11:49:10.000000000 -0700
@@ -56,7 +56,7 @@
 	CSZ presents a more precise but less flexible and less efficient
 	approach. As I understand it, the main idea is to create
 	WFQ flows for each guaranteed service and to allocate
-	the rest of bandwith to dummy flow-0. Flow-0 comprises
+	the rest of bandwidth to dummy flow-0. Flow-0 comprises
 	the predictive services and the best effort traffic;
 	it is handled by a priority scheduler with the highest
 	priority band allocated	for predictive services, and the rest ---
@@ -749,6 +749,14 @@
 static void
 csz_destroy(struct Qdisc* sch)
 {
+	struct csz_sched_data *q = (struct csz_sched_data *)sch->data;
+	struct tcf_proto *tp;
+
+	while ((tp = q->filter_list) != NULL) {
+		q->filter_list = tp->next;
+		tp->ops->destroy(tp);
+	}
+
 	MOD_DEC_USE_COUNT;
 }
 
diff -urN linux-2.4.21-pre7/net/sched/sch_htb.c linux-2.4.21-rc1/net/sched/sch_htb.c
--- linux-2.4.21-pre7/net/sched/sch_htb.c	2003-04-21 11:48:37.000000000 -0700
+++ linux-2.4.21-rc1/net/sched/sch_htb.c	2003-04-21 11:49:10.000000000 -0700
@@ -102,7 +102,9 @@
 #define HTB_PASSQ q,
 #define HTB_ARGQ struct htb_sched *q,
 #define static
+#undef __inline__
 #define __inline__
+#undef inline
 #define inline
 #define HTB_CMAGIC 0xFEFAFEF1
 #define htb_safe_rb_erase(N,R) do { BUG_TRAP((N)->rb_color != -1); \
diff -urN linux-2.4.21-pre7/net/sched/sch_prio.c linux-2.4.21-rc1/net/sched/sch_prio.c
--- linux-2.4.21-pre7/net/sched/sch_prio.c	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.21-rc1/net/sched/sch_prio.c	2003-04-21 11:49:10.000000000 -0700
@@ -158,6 +158,12 @@
 {
 	int prio;
 	struct prio_sched_data *q = (struct prio_sched_data *)sch->data;
+	struct tcf_proto *tp;
+
+	while ((tp = q->filter_list) != NULL) {
+		q->filter_list = tp->next;
+		tp->ops->destroy(tp);
+	}
 
 	for (prio=0; prio<q->bands; prio++) {
 		qdisc_destroy(q->queues[prio]);
diff -urN linux-2.4.21-pre7/net/sched/sch_sfq.c linux-2.4.21-rc1/net/sched/sch_sfq.c
--- linux-2.4.21-pre7/net/sched/sch_sfq.c	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.21-rc1/net/sched/sch_sfq.c	2003-04-21 11:49:10.000000000 -0700
@@ -131,10 +131,6 @@
 	return h & 0x3FF;
 }
 
-#ifndef IPPROTO_ESP
-#define IPPROTO_ESP 50
-#endif
-
 static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
 {
 	u32 h, h2;
diff -urN linux-2.4.21-pre7/net/socket.c linux-2.4.21-rc1/net/socket.c
--- linux-2.4.21-pre7/net/socket.c	2003-04-21 11:48:37.000000000 -0700
+++ linux-2.4.21-rc1/net/socket.c	2003-04-21 11:49:10.000000000 -0700
@@ -311,17 +311,17 @@
 /*
  *	Obtains the first available file descriptor and sets it up for use.
  *
- *	This functions creates file structure and maps it to fd space
+ *	This function creates file structure and maps it to fd space
  *	of current process. On success it returns file descriptor
  *	and file struct implicitly stored in sock->file.
  *	Note that another thread may close file descriptor before we return
  *	from this function. We use the fact that now we do not refer
  *	to socket after mapping. If one day we will need it, this
- *	function will inincrement ref. count on file by 1.
+ *	function will increment ref. count on file by 1.
  *
  *	In any case returned fd MAY BE not valid!
- *	This race condition is inavoidable
- *	with shared fd spaces, we cannot solve is inside kernel,
+ *	This race condition is unavoidable
+ *	with shared fd spaces, we cannot solve it inside kernel,
  *	but we take care of internal coherence yet.
  */
 
