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

diff -urN linux-2.4.22-pre9/Documentation/Configure.help linux-2.4.22-pre10/Documentation/Configure.help
--- linux-2.4.22-pre9/Documentation/Configure.help	2003-08-01 09:15:54.000000000 -0700
+++ linux-2.4.22-pre10/Documentation/Configure.help	2003-08-01 09:16:06.000000000 -0700
@@ -11615,6 +11615,18 @@
   module, say M here and read <file:Documentation/modules.txt> as well
   as <file:Documentation/networking/net-modules.txt>.
 
+Broadcom 4400 ethernet support (EXPERIMENTAL)
+CONFIG_B44
+  If you have a network (Ethernet) controller of this type, say Y and
+  read the Ethernet-HOWTO, available from
+  <http://www.tldp.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt> as well as
+  <file:Documentation/networking/net-modules.txt>.  The module will be
+  called b44.
+
 CS89x0 support (Daynaport CS and LC cards)
 CONFIG_CS89x0
   Support for CS89x0 chipset based Ethernet cards. If you have a
@@ -17512,6 +17524,13 @@
 
   If unsure, say N.
 
+Support for serial port described by EFI HCDP table
+CONFIG_SERIAL_HCDP
+  If you wish to make the serial console port described by the EFI
+  HCDP table available for use as serial console or general
+  purpose port, say Y here. See
+  <http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf>.
+
 Support for PowerMac serial ports
 CONFIG_MAC_SERIAL
   If you have Macintosh style serial ports (8 pin mini-DIN), say Y
diff -urN linux-2.4.22-pre9/Documentation/networking/ifenslave.c linux-2.4.22-pre10/Documentation/networking/ifenslave.c
--- linux-2.4.22-pre9/Documentation/networking/ifenslave.c	2003-08-01 09:15:54.000000000 -0700
+++ linux-2.4.22-pre10/Documentation/networking/ifenslave.c	2003-08-01 09:16:06.000000000 -0700
@@ -27,7 +27,7 @@
  *    - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> :
  *       - Master is now brought down before setting the MAC address.  In
  *         the 2.4 kernel you can't change the MAC address while the device is
- *         up because you get EBUSY.  
+ *         up because you get EBUSY.
  *
  *    - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com>
  *       - Added the ability to change the active interface on a mode 1 bond
@@ -44,10 +44,10 @@
  *
  *    - 2002/10/31 Tony Cureington <tony.cureington * hp_com> :
  *       - If the master does not have a hardware address when the first slave
- *         is enslaved, the master is assigned the hardware address of that 
- *         slave - there is a comment in bonding.c stating "ifenslave takes 
- *         care of this now." This corrects the problem of slaves having 
- *         different hardware addresses in active-backup mode when 
+ *         is enslaved, the master is assigned the hardware address of that
+ *         slave - there is a comment in bonding.c stating "ifenslave takes
+ *         care of this now." This corrects the problem of slaves having
+ *         different hardware addresses in active-backup mode when
  *         multiple interfaces are specified on a single ifenslave command
  *         (ifenslave bond0 eth0 eth1).
  *
@@ -82,16 +82,18 @@
  *	   processing.
  *
  *    - 2003/05/27 - Amir Noam <amir.noam at intel dot com>
- *	 - Fix backward compatibility issue:
+ *	 - Fix backward compatibility issues:
  *	   For drivers not using ABI versions, slave was set down while
  *	   it should be left up before enslaving.
+ *	   Also, master was not set down and the default set_mac_address()
+ *	   would fail and generate an error message in the system log.
  * 	 - For opt_c: slave should not be set to the master's setting
- *	   while it is runnig. It was already set during enslave. To
+ *	   while it is running. It was already set during enslave. To
  *	   simplify things, it is now handeled separately.
  */
 
-#define APP_VERSION	"1.0.11"
-#define APP_RELDATE	"May 29, 2003"
+#define APP_VERSION	"1.0.12"
+#define APP_RELDATE	"June 30, 2003"
 #define APP_NAME	"ifenslave"
 
 static char *version =
@@ -138,8 +140,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
-#include <linux/if.h>
-#include <linux/if_arp.h>
+#include <net/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_bonding.h>
 #include <linux/sockios.h>
@@ -360,7 +361,7 @@
 					}
 				}
 			}
-		} else if (opt_c) {
+		} else if (opt_c) { /* change primary slave */
 			strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ);
 			strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ);
 			if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) &&
@@ -386,11 +387,11 @@
 
 			/* if hwaddr_notset, assign the slave hw address to the master */
 			if (hwaddr_notset) {
-				/* assign the slave hw address to the 
-				 * master since it currently does not 
+				/* assign the slave hw address to the
+				 * master since it currently does not
 				 * have one; otherwise, slaves may
-				 * have different hw addresses in 
-				 * active-backup mode as seen when enslaving 
+				 * have different hw addresses in
+				 * active-backup mode as seen when enslaving
 				 * using "ifenslave bond0 eth0 eth1" because
 				 * hwaddr_notset is set outside this loop.
 				 * TODO: put this and the "else" portion in
@@ -403,7 +404,7 @@
 				if (-1 == rv) {
 					fprintf(stderr, "Could not get MAC "
 						"address of %s: %s\n",
-						slave_ifname, 
+						slave_ifname,
 						strerror(errno));
 					strncpy(if_hwaddr.ifr_name,
 						master_ifname, IFNAMSIZ);
@@ -411,19 +412,53 @@
 				}
 
 				if (!goterr) {
-					strncpy(if_hwaddr.ifr_name, 
+					if (abi_ver < 1) {
+						/* In ABI versions older than 1, the
+						 * master's set_mac routine couldn't
+						 * work if it was up, because it
+						 * used the default ethernet set_mac
+						 * function.
+						 */
+						/* bring master down */
+						if_flags.ifr_flags &= ~IFF_UP;
+						if (ioctl(skfd, SIOCSIFFLAGS,
+								&if_flags) < 0) {
+							goterr = 1;
+							fprintf(stderr,
+								"Shutting down "
+								"interface %s failed: "
+								"%s\n",
+								master_ifname,
+								strerror(errno));
+						}
+					}
+
+					strncpy(if_hwaddr.ifr_name,
 						master_ifname, IFNAMSIZ);
-					if (ioctl(skfd, SIOCSIFHWADDR, 
+					if (ioctl(skfd, SIOCSIFHWADDR,
 							&if_hwaddr) < 0) {
-						fprintf(stderr, 
+						fprintf(stderr,
 							"Could not set MAC "
 							"address of %s: %s\n",
-							master_ifname, 
+							master_ifname,
 							strerror(errno));
 						goterr=1;
 					} else {
 						hwaddr_notset = 0;
 					}
+
+					if (abi_ver < 1) {
+						/* bring master back up */
+						if_flags.ifr_flags |= IFF_UP;
+						if (ioctl(skfd, SIOCSIFFLAGS,
+							  &if_flags) < 0) {
+							fprintf(stderr,
+								"Bringing up interface "
+								"%s failed: %s\n",
+								master_ifname,
+								strerror(errno));
+						}
+					}
 				}
 			} else if (abi_ver < 1) { /* if (hwaddr_notset) */
 
@@ -479,7 +514,7 @@
 				}
 				spp++;
 			}
-	
+
 			if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0
 				|| ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) {
 				fprintf(stderr,
@@ -492,16 +527,16 @@
 						   slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
 				}
 			}
-	
+
 			if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0
-				|| ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { 
+				|| ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) {
 				fprintf(stderr, "Something broke setting the slave MTU: %s.\n",
 						strerror(errno));
 			} else {
 				if (verbose)
 					printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu);
 			}
-	
+
 			if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0
 				|| ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) {
 				fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n",
@@ -513,7 +548,7 @@
 						   slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
 				}
 			}
-	
+
 			if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0
 				|| ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) {
 				fprintf(stderr,
@@ -526,7 +561,7 @@
 						   slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
 				}
 			}
-			
+
 			if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0
 				|| ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) {
 				fprintf(stderr,
@@ -539,7 +574,7 @@
 						   slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
 				}
 			}
-			
+
 			if (abi_ver < 1) {
 
 			      	/* The driver is using an old ABI, so we'll set the interface
@@ -721,7 +756,7 @@
 }
 
 
-
+
 /*
  * Local variables:
  *  version-control: t
diff -urN linux-2.4.22-pre9/Documentation/nmi_watchdog.txt linux-2.4.22-pre10/Documentation/nmi_watchdog.txt
--- linux-2.4.22-pre9/Documentation/nmi_watchdog.txt	2003-08-01 09:15:54.000000000 -0700
+++ linux-2.4.22-pre10/Documentation/nmi_watchdog.txt	2003-08-01 09:16:06.000000000 -0700
@@ -1,9 +1,11 @@
 
-Is your ix86 system locking up unpredictably? No keyboard activity, just
+[NMI watchdog is available for x86 and x86-64 architectures]
+
+Is your system locking up unpredictably? No keyboard activity, just
 a frustrating complete hard lockup? Do you want to help us debugging
 such lockups? If all yes then this document is definitely for you.
 
-On Intel and similar ix86 type hardware there is a feature that enables
+On many x86/x86-64 type hardware there is a feature that enables
 us to generate 'watchdog NMI interrupts'.  (NMI: Non Maskable Interrupt
 which get executed even if the system is otherwise locked up hard).
 This can be used to debug hard kernel lockups.  By executing periodic
@@ -20,6 +22,15 @@
 kernel debugging options, such as Kernel Stack Meter or Kernel Tracer,
 may implicitly disable the NMI watchdog.]
 
+For x86-64, the needed APIC is always compiled in, and the NMI watchdog is
+always enabled with I/O-APIC mode (nmi_watchdog=1). Currently, local APIC
+mode (nmi_watchdog=2) does not work on x86-64.
+
+Using local APIC (nmi_watchdog=2) needs the first performance register, so
+you can't use it for other purposes (such as high precision performance
+profiling.) However, at least oprofile and the perfctr driver disable the
+local APIC NMI watchdog automatically.
+
 To actually enable the NMI watchdog, use the 'nmi_watchdog=N' boot
 parameter.  Eg. the relevant lilo.conf entry:
 
diff -urN linux-2.4.22-pre9/Makefile linux-2.4.22-pre10/Makefile
--- linux-2.4.22-pre9/Makefile	2003-08-01 09:15:55.000000000 -0700
+++ linux-2.4.22-pre10/Makefile	2003-08-01 09:16:06.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 22
-EXTRAVERSION = -pre9
+EXTRAVERSION = -pre10
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.22-pre9/arch/i386/kernel/i387.c linux-2.4.22-pre10/arch/i386/kernel/i387.c
--- linux-2.4.22-pre9/arch/i386/kernel/i387.c	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.22-pre10/arch/i386/kernel/i387.c	2003-08-01 09:16:06.000000000 -0700
@@ -373,14 +373,14 @@
 
 static inline int restore_i387_fxsave( struct _fpstate *buf )
 {
+	int err;
 	struct task_struct *tsk = current;
 	clear_fpu( tsk );
-	if ( __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0],
-			       sizeof(struct i387_fxsave_struct) ) )
-		return 1;
+	err = __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0],
+				sizeof(struct i387_fxsave_struct) );
 	/* mxcsr bit 6 and 31-16 must be zero for security reasons */
 	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
-	return convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf );
+	return err ? 1 : convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf );
 }
 
 int restore_i387( struct _fpstate *buf )
diff -urN linux-2.4.22-pre9/arch/i386/kernel/io_apic.c linux-2.4.22-pre10/arch/i386/kernel/io_apic.c
--- linux-2.4.22-pre9/arch/i386/kernel/io_apic.c	2003-08-01 09:15:55.000000000 -0700
+++ linux-2.4.22-pre10/arch/i386/kernel/io_apic.c	2003-08-01 09:16:06.000000000 -0700
@@ -1343,6 +1343,25 @@
 
 static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
 
+#ifndef CONFIG_SMP
+
+void send_IPI_self(int vector)
+{
+	unsigned int cfg;
+
+	/*
+	 * Wait for idle.
+	 */
+	apic_wait_icr_idle();
+	cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL;
+	/*
+	 * Send the IPI. The write to APIC_ICR fires this off.
+	 */
+	apic_write_around(APIC_ICR, cfg);
+}
+
+#endif /* CONFIG_SMP */
+
 static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
 {
 	unsigned long flags;
diff -urN linux-2.4.22-pre9/arch/ppc/kernel/ppc_ksyms.c linux-2.4.22-pre10/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.22-pre9/arch/ppc/kernel/ppc_ksyms.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.22-pre10/arch/ppc/kernel/ppc_ksyms.c	2003-08-01 09:16:07.000000000 -0700
@@ -353,6 +353,10 @@
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
 EXPORT_SYMBOL(handle_mm_fault); /* For MOL */
+#ifdef CONFIG_SMP
+extern int *hash_table_lock;
+EXPORT_SYMBOL_NOVERS(hash_table_lock); /* For MOL */
+#endif
 EXPORT_SYMBOL_NOVERS(disarm_decr);
 #ifdef CONFIG_PPC_STD_MMU
 EXPORT_SYMBOL(flush_hash_page); /* For MOL */
diff -urN linux-2.4.22-pre9/drivers/acpi/system.c linux-2.4.22-pre10/drivers/acpi/system.c
--- linux-2.4.22-pre9/drivers/acpi/system.c	2003-08-01 09:15:57.000000000 -0700
+++ linux-2.4.22-pre10/drivers/acpi/system.c	2003-08-01 09:16:07.000000000 -0700
@@ -90,9 +90,7 @@
 static void
 acpi_power_off (void)
 {
-	acpi_enter_sleep_state_prep(ACPI_STATE_S5);
-	ACPI_DISABLE_IRQS();
-	acpi_enter_sleep_state(ACPI_STATE_S5);
+	acpi_suspend(ACPI_STATE_S5);
 }
 
 #endif /*CONFIG_PM*/
@@ -180,7 +178,7 @@
 			return AE_ERROR;
 	}
 
-	if (state < ACPI_STATE_S5) {
+	if (state <= ACPI_STATE_S5) {
 		/* Tell devices to stop I/O and actually save their state.
 		 * It is theoretically possible that something could fail,
 		 * so handle that gracefully..
diff -urN linux-2.4.22-pre9/drivers/block/cciss.c linux-2.4.22-pre10/drivers/block/cciss.c
--- linux-2.4.22-pre9/drivers/block/cciss.c	2003-08-01 09:15:57.000000000 -0700
+++ linux-2.4.22-pre10/drivers/block/cciss.c	2003-08-01 09:16:08.000000000 -0700
@@ -48,7 +48,7 @@
 #define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,47)
 
 /* Embedded module documentation macros - see modules.h */
-MODULE_AUTHOR("Charles M. White III - Hewlett-Packard Company");
+MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.47");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"); 
 MODULE_LICENSE("GPL");
@@ -2341,7 +2341,7 @@
 
 
 	/* Is this interrupt for us? */
-	if (h->access.intr_pending(h) == 0)
+	if ((h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0))
 		return;
 
 	/*
diff -urN linux-2.4.22-pre9/drivers/block/cciss.h linux-2.4.22-pre10/drivers/block/cciss.h
--- linux-2.4.22-pre9/drivers/block/cciss.h	2003-08-01 09:15:57.000000000 -0700
+++ linux-2.4.22-pre10/drivers/block/cciss.h	2003-08-01 09:16:08.000000000 -0700
@@ -51,7 +51,7 @@
 	unsigned long io_mem_length;
 	CfgTable_struct *cfgtable;
 	int	intr;
-
+	int	interrupts_enabled;
 	int 	max_commands;
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
@@ -139,9 +139,11 @@
 {
 	if (val) 
 	{ /* Turn interrupts on */
+		h->interrupts_enabled = 1;
 		writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
 	} else /* Turn them off */
 	{
+		h->interrupts_enabled = 0;
         	writel( SA5_INTR_OFF, 
 			h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
 	}
@@ -155,9 +157,11 @@
 {
         if (val)
         { /* Turn interrupts on */
+		h->interrupts_enabled = 1;
                 writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         } else /* Turn them off */
         {
+		h->interrupts_enabled = 0;
                 writel( SA5B_INTR_OFF,
                         h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         }
diff -urN linux-2.4.22-pre9/drivers/char/Config.in linux-2.4.22-pre10/drivers/char/Config.in
--- linux-2.4.22-pre9/drivers/char/Config.in	2003-08-01 09:15:58.000000000 -0700
+++ linux-2.4.22-pre10/drivers/char/Config.in	2003-08-01 09:16:08.000000000 -0700
@@ -18,7 +18,7 @@
       bool '   serial port on GSC support' CONFIG_SERIAL_GSC
    fi
    if [ "$CONFIG_IA64" = "y" ]; then
-      bool 'Support for serial console port described by EFI HCDP table' CONFIG_SERIAL_HCDP
+      bool '  Support for serial port described by EFI HCDP table' CONFIG_SERIAL_HCDP
    fi
    if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
       tristate '   Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
diff -urN linux-2.4.22-pre9/drivers/char/agp/agpgart_be.c linux-2.4.22-pre10/drivers/char/agp/agpgart_be.c
--- linux-2.4.22-pre9/drivers/char/agp/agpgart_be.c	2003-08-01 09:15:58.000000000 -0700
+++ linux-2.4.22-pre10/drivers/char/agp/agpgart_be.c	2003-08-01 09:16:08.000000000 -0700
@@ -5580,7 +5580,11 @@
 {
 	long memory, index, result;
 
-	memory = (num_physpages << PAGE_SHIFT) >> 20;
+#if PAGE_SHIFT < 20
+	memory = num_physpages >> (20 - PAGE_SHIFT);
+#else
+	memory = num_physpages << (PAGE_SHIFT - 20);
+#endif
 	index = 1;
 
 	while ((memory > maxes_table[index].mem) &&
diff -urN linux-2.4.22-pre9/drivers/char/ipmi/ipmi_kcs_intf.c linux-2.4.22-pre10/drivers/char/ipmi/ipmi_kcs_intf.c
--- linux-2.4.22-pre9/drivers/char/ipmi/ipmi_kcs_intf.c	2003-08-01 09:15:58.000000000 -0700
+++ linux-2.4.22-pre10/drivers/char/ipmi/ipmi_kcs_intf.c	2003-08-01 09:16:08.000000000 -0700
@@ -1025,7 +1025,7 @@
 	return rv;
 }
 
-#ifdef CONFIG_ACPI
+#ifdef CONFIG_ACPI_INTERPRETER
 
 /* Retrieve the base physical address from ACPI tables.  Originally
    from Hewlett-Packard simple bmc.c, a GPL KCS driver. */
@@ -1085,7 +1085,7 @@
 	int		rv = 0;
 	int		pos = 0;
 	int		i = 0;
-#ifdef CONFIG_ACPI
+#ifdef CONFIG_ACPI_INTERPRETER
 	unsigned long	physaddr = 0;
 #endif
 
@@ -1115,7 +1115,7 @@
 	   (because they weren't already specified above). */
 
 	if (kcs_trydefaults) {
-#ifdef CONFIG_ACPI
+#ifdef CONFIG_ACPI_INTERPRETER
 		if ((physaddr = acpi_find_bmc())) {
 			if (!check_mem_region(physaddr, 2)) {
 				rv = init_one_kcs(0, 
diff -urN linux-2.4.22-pre9/drivers/net/Config.in linux-2.4.22-pre10/drivers/net/Config.in
--- linux-2.4.22-pre9/drivers/net/Config.in	2003-08-01 09:15:58.000000000 -0700
+++ linux-2.4.22-pre10/drivers/net/Config.in	2003-08-01 09:16:08.000000000 -0700
@@ -172,6 +172,7 @@
       fi
 
       dep_tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA
+      dep_tristate '    Broadcom 4400 ethernet support (EXPERIMENTAL)' CONFIG_B44 $CONFIG_PCI $CONFIG_EXPERIMENTAL
       dep_tristate '    CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
       dep_tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
       if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then
diff -urN linux-2.4.22-pre9/drivers/net/Makefile linux-2.4.22-pre10/drivers/net/Makefile
--- linux-2.4.22-pre9/drivers/net/Makefile	2003-08-01 09:15:58.000000000 -0700
+++ linux-2.4.22-pre10/drivers/net/Makefile	2003-08-01 09:16:08.000000000 -0700
@@ -151,6 +151,7 @@
 obj-$(CONFIG_LNE390) += lne390.o 8390.o
 obj-$(CONFIG_NE3210) += ne3210.o 8390.o
 obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
+obj-$(CONFIG_B44) += b44.o
 
 obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
 obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
diff -urN linux-2.4.22-pre9/drivers/net/b44.c linux-2.4.22-pre10/drivers/net/b44.c
--- linux-2.4.22-pre9/drivers/net/b44.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-pre10/drivers/net/b44.c	2003-08-01 09:16:08.000000000 -0700
@@ -0,0 +1,1881 @@
+/* b44.c: Broadcom 4400 device driver.
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "b44.h"
+
+#define DRV_MODULE_NAME		"b44"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_MODULE_VERSION	"0.9"
+#define DRV_MODULE_RELDATE	"Jul 14, 2003"
+
+#define B44_DEF_MSG_ENABLE	  \
+	(NETIF_MSG_DRV		| \
+	 NETIF_MSG_PROBE	| \
+	 NETIF_MSG_LINK		| \
+	 NETIF_MSG_TIMER	| \
+	 NETIF_MSG_IFDOWN	| \
+	 NETIF_MSG_IFUP		| \
+	 NETIF_MSG_RX_ERR	| \
+	 NETIF_MSG_TX_ERR)
+
+/* length of time before we decide the hardware is borked,
+ * and dev->tx_timeout() should be called to fix the problem
+ */
+#define B44_TX_TIMEOUT			(5 * HZ)
+
+/* hardware minimum and maximum for a single frame's data payload */
+#define B44_MIN_MTU			60
+#define B44_MAX_MTU			1500
+
+#define B44_RX_RING_SIZE		512
+#define B44_DEF_RX_RING_PENDING		200
+#define B44_RX_RING_BYTES	(sizeof(struct dma_desc) * \
+				 B44_RX_RING_SIZE)
+#define B44_TX_RING_SIZE		512
+#define B44_DEF_TX_RING_PENDING		(B44_TX_RING_SIZE - 1)
+#define B44_TX_RING_BYTES	(sizeof(struct dma_desc) * \
+				 B44_TX_RING_SIZE)
+
+#define TX_RING_GAP(BP)	\
+	(B44_TX_RING_SIZE - (BP)->tx_pending)
+#define TX_BUFFS_AVAIL(BP)						\
+	(((BP)->tx_cons <= (BP)->tx_prod) ?				\
+	  (BP)->tx_cons + (BP)->tx_pending - (BP)->tx_prod :		\
+	  (BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
+#define NEXT_TX(N)		(((N) + 1) & (B44_TX_RING_SIZE - 1))
+
+#define RX_PKT_BUF_SZ		(1536 + bp->rx_offset + 64)
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define B44_TX_WAKEUP_THRESH		(B44_TX_RING_SIZE / 4)
+
+static char version[] __devinitdata =
+	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(b44_debug, "i");
+MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
+
+static int b44_debug = -1;	/* -1 == use B44_DEF_MSG_ENABLE as value */
+
+#ifndef PCI_DEVICE_ID_BCM4401
+#define PCI_DEVICE_ID_BCM4401      0x4401
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define IRQ_RETVAL(x) 
+#define irqreturn_t void
+#endif
+
+static struct pci_device_id b44_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ }	/* terminate list with empty entry */
+};
+
+MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
+
+static void b44_halt(struct b44 *);
+static void b44_init_rings(struct b44 *);
+static int b44_init_hw(struct b44 *);
+
+static int b44_wait_bit(struct b44 *bp, unsigned long reg,
+			u32 bit, unsigned long timeout, const int clear)
+{
+	unsigned long i;
+
+	for (i = 0; i < timeout; i++) {
+		u32 val = br32(reg);
+
+		if (clear && !(val & bit))
+			break;
+		if (!clear && (val & bit))
+			break;
+		udelay(10);
+	}
+	if (i == timeout) {
+		printk(KERN_ERR PFX "%s: BUG!  Timeout waiting for bit %08x of register "
+		       "%lx to %s.\n",
+		       bp->dev->name,
+		       bit, reg,
+		       (clear ? "clear" : "set"));
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* Sonics SiliconBackplane support routines.  ROFL, you should see all the
+ * buzz words used on this company's website :-)
+ *
+ * All of these routines must be invoked with bp->lock held and
+ * interrupts disabled.
+ */
+
+#define SBID_SDRAM		0
+#define SBID_PCI_MEM		1
+#define SBID_PCI_CFG		2
+#define SBID_PCI_DMA		3
+#define	SBID_SDRAM_SWAPPED	4
+#define SBID_ENUM		5
+#define SBID_REG_SDRAM		6
+#define SBID_REG_ILINE20	7
+#define SBID_REG_EMAC		8
+#define SBID_REG_CODEC		9
+#define SBID_REG_USB		10
+#define SBID_REG_PCI		11
+#define SBID_REG_MIPS		12
+#define SBID_REG_EXTIF		13
+#define	SBID_EXTIF		14
+#define	SBID_EJTAG		15
+#define	SBID_MAX		16
+
+static u32 ssb_get_addr(struct b44 *bp, u32 id, u32 instance)
+{
+	switch (id) {
+	case SBID_PCI_DMA:
+		return 0x40000000;
+	case SBID_ENUM:
+		return 0x18000000;
+	case SBID_REG_EMAC:
+		return 0x18000000;
+	case SBID_REG_CODEC:
+		return 0x18001000;
+	case SBID_REG_PCI:
+		return 0x18002000;
+	default:
+		return 0;
+	};
+}
+
+static u32 ssb_get_core_rev(struct b44 *bp)
+{
+	return (br32(B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
+}
+
+static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
+{
+	u32 bar_orig, pci_rev, val;
+
+	pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
+	pci_write_config_dword(bp->pdev, SSB_BAR0_WIN,
+			       ssb_get_addr(bp, SBID_REG_PCI, 0));
+	pci_rev = ssb_get_core_rev(bp);
+
+	val = br32(B44_SBINTVEC);
+	val |= cores;
+	bw32(B44_SBINTVEC, val);
+
+	val = br32(SSB_PCI_TRANS_2);
+	val |= SSB_PCI_PREF | SSB_PCI_BURST;
+	bw32(SSB_PCI_TRANS_2, val);
+
+	pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
+
+	return pci_rev;
+}
+
+static void ssb_core_disable(struct b44 *bp)
+{
+	if (br32(B44_SBTMSLOW) & SBTMSLOW_RESET)
+		return;
+
+	bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
+	b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
+	b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
+	bw32(B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
+			    SBTMSLOW_REJECT | SBTMSLOW_RESET));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+	bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+}
+
+static void ssb_core_reset(struct b44 *bp)
+{
+	u32 val;
+
+	ssb_core_disable(bp);
+	bw32(B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+
+	/* Clear SERR if set, this is a hw bug workaround.  */
+	if (br32(B44_SBTMSHIGH) & SBTMSHIGH_SERR)
+		bw32(B44_SBTMSHIGH, 0);
+
+	val = br32(B44_SBIMSTATE);
+	if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
+		bw32(B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
+
+	bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+
+	bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+}
+
+static int ssb_core_unit(struct b44 *bp)
+{
+#if 0
+	u32 val = br32(B44_SBADMATCH0);
+	u32 base;
+
+	type = val & SBADMATCH0_TYPE_MASK;
+	switch (type) {
+	case 0:
+		base = val & SBADMATCH0_BS0_MASK;
+		break;
+
+	case 1:
+		base = val & SBADMATCH0_BS1_MASK;
+		break;
+
+	case 2:
+	default:
+		base = val & SBADMATCH0_BS2_MASK;
+		break;
+	};
+#endif
+	return 0;
+}
+
+static int ssb_is_core_up(struct b44 *bp)
+{
+	return ((br32(B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
+		== SBTMSLOW_CLOCK);
+}
+
+static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
+{
+	u32 val;
+
+	val  = ((u32) data[2]) << 24;
+	val |= ((u32) data[3]) << 16;
+	val |= ((u32) data[4]) <<  8;
+	val |= ((u32) data[5]) <<  0;
+	bw32(B44_CAM_DATA_LO, val);
+	val = (CAM_DATA_HI_VALID | 
+	       (((u32) data[0]) << 8) |
+	       (((u32) data[1]) << 0));
+	bw32(B44_CAM_DATA_HI, val);
+	bw32(B44_CAM_CTRL, (CAM_CTRL_WRITE |
+			    (index << CAM_CTRL_INDEX_SHIFT)));
+	b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);	
+}
+
+static inline void __b44_disable_ints(struct b44 *bp)
+{
+	bw32(B44_IMASK, 0);
+}
+
+static void b44_disable_ints(struct b44 *bp)
+{
+	__b44_disable_ints(bp);
+
+	/* Flush posted writes. */
+	br32(B44_IMASK);
+}
+
+static void b44_enable_ints(struct b44 *bp)
+{
+	bw32(B44_IMASK, bp->imask);
+}
+
+static int b44_readphy(struct b44 *bp, int reg, u32 *val)
+{
+	int err;
+
+	bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
+	bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
+			     (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
+			     (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+			     (reg << MDIO_DATA_RA_SHIFT) |
+			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
+	err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+	*val = br32(B44_MDIO_DATA) & MDIO_DATA_DATA;
+
+	return err;
+}
+
+static int b44_writephy(struct b44 *bp, int reg, u32 val)
+{
+	bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
+	bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
+			     (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
+			     (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+			     (reg << MDIO_DATA_RA_SHIFT) |
+			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
+			     (val & MDIO_DATA_DATA)));
+	return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+}
+
+static int b44_phy_reset(struct b44 *bp)
+{
+	u32 val;
+	int err;
+
+	err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
+	if (err)
+		return err;
+	udelay(100);
+	err = b44_readphy(bp, MII_BMCR, &val);
+	if (!err) {
+		if (val & BMCR_RESET) {
+			printk(KERN_ERR PFX "%s: PHY Reset would not complete.\n",
+			       bp->dev->name);
+			err = -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags)
+{
+	u32 val;
+
+	bp->flags &= ~(B44_FLAG_TX_PAUSE | B44_FLAG_RX_PAUSE);
+	bp->flags |= pause_flags;
+
+	val = br32(B44_RXCONFIG);
+	if (pause_flags & B44_FLAG_RX_PAUSE)
+		val |= RXCONFIG_FLOW;
+	else
+		val &= ~RXCONFIG_FLOW;
+	bw32(B44_RXCONFIG, val);
+
+	val = br32(B44_MAC_FLOW);
+	if (pause_flags & B44_FLAG_TX_PAUSE)
+		val |= (MAC_FLOW_PAUSE_ENAB |
+			(0xc0 & MAC_FLOW_RX_HI_WATER));
+	else
+		val &= ~MAC_FLOW_PAUSE_ENAB;
+	bw32(B44_MAC_FLOW, val);
+}
+
+static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
+{
+	u32 pause_enab = bp->flags & (B44_FLAG_TX_PAUSE |
+				      B44_FLAG_RX_PAUSE);
+
+	if (local & ADVERTISE_PAUSE_CAP) {
+		if (local & ADVERTISE_PAUSE_ASYM) {
+			if (remote & LPA_PAUSE_CAP)
+				pause_enab |= (B44_FLAG_TX_PAUSE |
+					       B44_FLAG_RX_PAUSE);
+			else if (remote & LPA_PAUSE_ASYM)
+				pause_enab |= B44_FLAG_RX_PAUSE;
+		} else {
+			if (remote & LPA_PAUSE_CAP)
+				pause_enab |= (B44_FLAG_TX_PAUSE |
+					       B44_FLAG_RX_PAUSE);
+		}
+	} else if (local & ADVERTISE_PAUSE_ASYM) {
+		if ((remote & LPA_PAUSE_CAP) &&
+		    (remote & LPA_PAUSE_ASYM))
+			pause_enab |= B44_FLAG_TX_PAUSE;
+	}
+
+	__b44_set_flow_ctrl(bp, pause_enab);
+}
+
+static int b44_setup_phy(struct b44 *bp)
+{
+	u32 val;
+	int err;
+
+	if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
+		goto out;
+	if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
+				val & MII_ALEDCTRL_ALLMSK)) != 0)
+		goto out;
+	if ((err = b44_readphy(bp, B44_MII_TLEDCTRL, &val)) != 0)
+		goto out;
+	if ((err = b44_writephy(bp, B44_MII_TLEDCTRL,
+				val | MII_TLEDCTRL_ENABLE)) != 0)
+		goto out;
+
+	if (!(bp->flags & B44_FLAG_FORCE_LINK)) {
+		u32 adv = ADVERTISE_CSMA;
+
+		if (bp->flags & B44_FLAG_ADV_10HALF)
+			adv |= ADVERTISE_10HALF;
+		if (bp->flags & B44_FLAG_ADV_10FULL)
+			adv |= ADVERTISE_10FULL;
+		if (bp->flags & B44_FLAG_ADV_100HALF)
+			adv |= ADVERTISE_100HALF;
+		if (bp->flags & B44_FLAG_ADV_100FULL)
+			adv |= ADVERTISE_100FULL;
+
+		if (bp->flags & B44_FLAG_PAUSE_AUTO)
+			adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+		if ((err = b44_writephy(bp, MII_ADVERTISE, adv)) != 0)
+			goto out;
+		if ((err = b44_writephy(bp, MII_BMCR, (BMCR_ANENABLE |
+						       BMCR_ANRESTART))) != 0)
+			goto out;
+	} else {
+		u32 bmcr;
+
+		if ((err = b44_readphy(bp, MII_BMCR, &bmcr)) != 0)
+			goto out;
+		bmcr &= ~(BMCR_FULLDPLX | BMCR_ANENABLE | BMCR_SPEED100);
+		if (bp->flags & B44_FLAG_100_BASE_T)
+			bmcr |= BMCR_SPEED100;
+		if (bp->flags & B44_FLAG_FULL_DUPLEX)
+			bmcr |= BMCR_FULLDPLX;
+		if ((err = b44_writephy(bp, MII_BMCR, bmcr)) != 0)
+			goto out;
+
+		/* Since we will not be negotiating there is no safe way
+		 * to determine if the link partner supports flow control
+		 * or not.  So just disable it completely in this case.
+		 */
+		b44_set_flow_ctrl(bp, 0, 0);
+	}
+
+out:
+	return err;
+}
+
+static void b44_stats_update(struct b44 *bp)
+{
+	unsigned long reg;
+	u32 *val;
+
+	val = &bp->hw_stats.tx_good_octets;
+	for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) {
+		*val++ += br32(reg);
+	}
+	val = &bp->hw_stats.rx_good_octets;
+	for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) {
+		*val++ += br32(reg);
+	}
+}
+
+static void b44_link_report(struct b44 *bp)
+{
+	if (!netif_carrier_ok(bp->dev)) {
+		printk(KERN_INFO PFX "%s: Link is down.\n", bp->dev->name);
+	} else {
+		printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
+		       bp->dev->name,
+		       (bp->flags & B44_FLAG_100_BASE_T) ? 100 : 10,
+		       (bp->flags & B44_FLAG_FULL_DUPLEX) ? "full" : "half");
+
+		printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
+		       "%s for RX.\n",
+		       bp->dev->name,
+		       (bp->flags & B44_FLAG_TX_PAUSE) ? "on" : "off",
+		       (bp->flags & B44_FLAG_RX_PAUSE) ? "on" : "off");
+	}
+}
+
+static void b44_check_phy(struct b44 *bp)
+{
+	u32 bmsr, aux;
+
+	if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
+	    !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
+	    (bmsr != 0xffff)) {
+		if (aux & MII_AUXCTRL_SPEED)
+			bp->flags |= B44_FLAG_100_BASE_T;
+		else
+			bp->flags &= ~B44_FLAG_100_BASE_T;
+		if (aux & MII_AUXCTRL_DUPLEX)
+			bp->flags |= B44_FLAG_FULL_DUPLEX;
+		else
+			bp->flags &= ~B44_FLAG_FULL_DUPLEX;
+
+		if (!netif_carrier_ok(bp->dev) &&
+		    (bmsr & BMSR_LSTATUS)) {
+			u32 val = br32(B44_TX_CTRL);
+			u32 local_adv, remote_adv;
+
+			if (bp->flags & B44_FLAG_FULL_DUPLEX)
+				val |= TX_CTRL_DUPLEX;
+			else
+				val &= ~TX_CTRL_DUPLEX;
+			bw32(B44_TX_CTRL, val);
+
+			if (!(bp->flags & B44_FLAG_FORCE_LINK) &&
+			    !b44_readphy(bp, MII_ADVERTISE, &local_adv) &&
+			    !b44_readphy(bp, MII_LPA, &remote_adv))
+				b44_set_flow_ctrl(bp, local_adv, remote_adv);
+
+			/* Link now up */
+			netif_carrier_on(bp->dev);
+			b44_link_report(bp);
+		} else if (netif_carrier_ok(bp->dev) && !(bmsr & BMSR_LSTATUS)) {
+			/* Link now down */
+			netif_carrier_off(bp->dev);
+			b44_link_report(bp);
+		}
+
+		if (bmsr & BMSR_RFAULT)
+			printk(KERN_WARNING PFX "%s: Remote fault detected in PHY\n",
+			       bp->dev->name);
+		if (bmsr & BMSR_JCD)
+			printk(KERN_WARNING PFX "%s: Jabber detected in PHY\n",
+			       bp->dev->name);
+	}
+}
+
+static void b44_timer(unsigned long __opaque)
+{
+	struct b44 *bp = (struct b44 *) __opaque;
+
+	spin_lock_irq(&bp->lock);
+
+	b44_check_phy(bp);
+
+	b44_stats_update(bp);
+
+	spin_unlock_irq(&bp->lock);
+
+	bp->timer.expires = jiffies + HZ;
+	add_timer(&bp->timer);
+}
+
+static void b44_tx(struct b44 *bp)
+{
+	u32 cur, cons;
+
+	cur  = br32(B44_DMATX_STAT) & DMATX_STAT_CDMASK;
+	cur /= sizeof(struct dma_desc);
+
+	/* XXX needs updating when NETIF_F_SG is supported */
+	for (cons = bp->tx_cons; cons != cur; cons = NEXT_TX(cons)) {
+		struct ring_info *rp = &bp->tx_buffers[cons];
+		struct sk_buff *skb = rp->skb;
+
+		if (unlikely(skb == NULL))
+			BUG();
+
+		pci_unmap_single(bp->pdev,
+				 pci_unmap_addr(rp, mapping),
+				 skb->len,
+				 PCI_DMA_TODEVICE);
+		rp->skb = NULL;
+		dev_kfree_skb_irq(skb);
+	}
+
+	bp->tx_cons = cons;
+	if (netif_queue_stopped(bp->dev) &&
+	    TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH)
+		netif_wake_queue(bp->dev);
+
+	bw32(B44_GPTIMER, 0);
+}
+
+/* Works like this.  This chip writes a 'struct rx_header" 30 bytes
+ * before the DMA address you give it.  So we allocate 30 more bytes
+ * for the RX buffer, DMA map all of it, skb_reserve the 30 bytes, then
+ * point the chip at 30 bytes past where the rx_header will go.
+ */
+static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
+{
+	struct dma_desc *dp;
+	struct ring_info *src_map, *map;
+	struct rx_header *rh;
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	int dest_idx;
+	u32 ctrl;
+
+	src_map = NULL;
+	if (src_idx >= 0)
+		src_map = &bp->rx_buffers[src_idx];
+	dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
+	map = &bp->rx_buffers[dest_idx];
+	skb = dev_alloc_skb(RX_PKT_BUF_SZ);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	skb->dev = bp->dev;
+	mapping = pci_map_single(bp->pdev, skb->data,
+				 RX_PKT_BUF_SZ,
+				 PCI_DMA_FROMDEVICE);
+	skb_reserve(skb, bp->rx_offset);
+
+	rh = (struct rx_header *)
+		(skb->data - bp->rx_offset);
+	rh->len = 0;
+	rh->flags = 0;
+
+	map->skb = skb;
+	pci_unmap_addr_set(map, mapping, mapping);
+
+	if (src_map != NULL)
+		src_map->skb = NULL;
+
+	ctrl  = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - bp->rx_offset));
+	if (dest_idx == (B44_RX_RING_SIZE - 1))
+		ctrl |= DESC_CTRL_EOT;
+
+	dp = &bp->rx_ring[dest_idx];
+	dp->ctrl = cpu_to_le32(ctrl);
+	dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
+
+	return RX_PKT_BUF_SZ;
+}
+
+static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
+{
+	struct dma_desc *src_desc, *dest_desc;
+	struct ring_info *src_map, *dest_map;
+	struct rx_header *rh;
+	int dest_idx;
+	u32 ctrl;
+
+	dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
+	dest_desc = &bp->rx_ring[dest_idx];
+	dest_map = &bp->rx_buffers[dest_idx];
+	src_desc = &bp->rx_ring[src_idx];
+	src_map = &bp->rx_buffers[src_idx];
+
+	dest_map->skb = src_map->skb;
+	rh = (struct rx_header *) src_map->skb->data;
+	rh->len = 0;
+	rh->flags = 0;
+	pci_unmap_addr_set(dest_map, mapping,
+			   pci_unmap_addr(src_map, mapping));
+
+	ctrl = src_desc->ctrl;
+	if (dest_idx == (B44_RX_RING_SIZE - 1))
+		ctrl |= cpu_to_le32(DESC_CTRL_EOT);
+	else
+		ctrl &= cpu_to_le32(~DESC_CTRL_EOT);
+
+	dest_desc->ctrl = ctrl;
+	dest_desc->addr = src_desc->addr;
+	src_map->skb = NULL;
+}
+
+static int b44_rx(struct b44 *bp, int budget)
+{
+	int received;
+	u32 cons, prod;
+
+	received = 0;
+	prod  = br32(B44_DMARX_STAT) & DMARX_STAT_CDMASK;
+	prod /= sizeof(struct dma_desc);
+	cons = bp->rx_cons;
+
+	while (cons != prod && budget > 0) {
+		struct ring_info *rp = &bp->rx_buffers[cons];
+		struct sk_buff *skb = rp->skb;
+		dma_addr_t map = pci_unmap_addr(rp, mapping);
+		struct rx_header *rh;
+		u16 len;
+
+		pci_dma_sync_single(bp->pdev, map,
+				    RX_PKT_BUF_SZ,
+				    PCI_DMA_FROMDEVICE);
+		rh = (struct rx_header *) skb->data;
+		len = cpu_to_le16(rh->len);
+		if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
+		    (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
+		drop_it:
+			b44_recycle_rx(bp, cons, bp->rx_prod);
+		drop_it_no_recycle:
+			bp->stats.rx_dropped++;
+			goto next_pkt;
+		}
+
+		if (len == 0) {
+			int i = 0;
+
+			do {
+				udelay(2);
+				barrier();
+				len = cpu_to_le16(rh->len);
+			} while (len == 0 && i++ < 5);
+			if (len == 0)
+				goto drop_it;
+		}
+
+		/* Omit CRC. */
+		len -= 4;
+
+		if (len > RX_COPY_THRESHOLD) {
+			int skb_size;
+			skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
+			if (skb_size < 0)
+				goto drop_it;
+			pci_unmap_single(bp->pdev, map,
+					 skb_size, PCI_DMA_FROMDEVICE);
+			/* Leave out rx_header */
+                	skb_put(skb, len+bp->rx_offset);
+            	        skb_pull(skb,bp->rx_offset);
+		} else {
+			struct sk_buff *copy_skb;
+
+			b44_recycle_rx(bp, cons, bp->rx_prod);
+			copy_skb = dev_alloc_skb(len + 2);
+			if (copy_skb == NULL)
+				goto drop_it_no_recycle;
+
+			copy_skb->dev = bp->dev;
+			skb_reserve(copy_skb, 2);
+			skb_put(copy_skb, len);
+			/* DMA sync done above, copy just the actual packet */
+			memcpy(copy_skb->data, skb->data+bp->rx_offset, len);
+
+			skb = copy_skb;
+		}
+		skb->ip_summed = CHECKSUM_NONE;
+		skb->protocol = eth_type_trans(skb, bp->dev);
+		netif_receive_skb(skb);
+		bp->dev->last_rx = jiffies;
+		received++;
+		budget--;
+	next_pkt:
+		bp->rx_prod = (bp->rx_prod + 1) &
+			(B44_RX_RING_SIZE - 1);
+		cons = (cons + 1) & (B44_RX_RING_SIZE - 1);
+	}
+
+	bp->rx_cons = cons;
+	bw32(B44_DMARX_PTR, cons * sizeof(struct dma_desc));
+
+	return received;
+}
+
+static int b44_poll(struct net_device *netdev, int *budget)
+{
+	struct b44 *bp = netdev->priv;
+	int done;
+
+	spin_lock_irq(&bp->lock);
+
+	if (bp->istat & (ISTAT_TX | ISTAT_TO)) {
+		/* spin_lock(&bp->tx_lock); */
+		b44_tx(bp);
+		/* spin_unlock(&bp->tx_lock); */
+	}
+	spin_unlock_irq(&bp->lock);
+
+	done = 1;
+	if (bp->istat & ISTAT_RX) {
+		int orig_budget = *budget;
+		int work_done;
+
+		if (orig_budget > netdev->quota)
+			orig_budget = netdev->quota;
+
+		work_done = b44_rx(bp, orig_budget);
+
+		*budget -= work_done;
+		netdev->quota -= work_done;
+
+		if (work_done >= orig_budget)
+			done = 0;
+	}
+
+	if (bp->istat & ISTAT_ERRORS) {
+		spin_lock_irq(&bp->lock);
+		b44_halt(bp);
+		b44_init_rings(bp);
+		b44_init_hw(bp);
+		netif_wake_queue(bp->dev);
+		spin_unlock_irq(&bp->lock);
+		done = 1;
+	}
+
+	if (done) {
+		netif_rx_complete(netdev);
+		b44_enable_ints(bp);
+	}
+
+	return (done ? 0 : 1);
+}
+
+static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct b44 *bp = dev->priv;
+	unsigned long flags;
+	u32 istat, imask;
+	int handled = 0;
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	istat = br32(B44_ISTAT);
+	imask = br32(B44_IMASK);
+
+	/* ??? What the fuck is the purpose of the interrupt mask
+	 * ??? register if we have to mask it out by hand anyways?
+	 */
+	istat &= imask;
+	if (istat) {
+		handled = 1;
+		if (netif_rx_schedule_prep(dev)) {
+			/* NOTE: These writes are posted by the readback of
+			 *       the ISTAT register below.
+			 */
+			bp->istat = istat;
+			__b44_disable_ints(bp);
+			__netif_rx_schedule(dev);
+		} else {
+			printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
+			       dev->name);
+		}
+
+		bw32(B44_ISTAT, istat);
+		br32(B44_ISTAT);
+	}
+	spin_unlock_irqrestore(&bp->lock, flags);
+	return IRQ_RETVAL(handled);
+}
+
+static void b44_tx_timeout(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+
+	printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
+	       dev->name);
+
+	spin_lock_irq(&bp->lock);
+
+	b44_halt(bp);
+	b44_init_rings(bp);
+	b44_init_hw(bp);
+
+	spin_unlock_irq(&bp->lock);
+
+	netif_wake_queue(dev);
+}
+
+static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	dma_addr_t mapping;
+	u32 len, entry, ctrl;
+
+	len = skb->len;
+	spin_lock_irq(&bp->lock);
+
+	/* This is a hard error, log it. */
+	if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) {
+		netif_stop_queue(dev);
+		spin_unlock_irq(&bp->lock);
+		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
+		return 1;
+	}
+
+	entry = bp->tx_prod;
+	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+
+	bp->tx_buffers[entry].skb = skb;
+	pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
+
+	ctrl  = (len & DESC_CTRL_LEN);
+	ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
+	if (entry == (B44_TX_RING_SIZE - 1))
+		ctrl |= DESC_CTRL_EOT;
+
+	bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl);
+	bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
+
+	entry = NEXT_TX(entry);
+
+	bp->tx_prod = entry;
+
+	wmb();
+
+	bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc));
+	if (bp->flags & B44_FLAG_BUGGY_TXPTR)
+		bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc));
+	if (bp->flags & B44_FLAG_REORDER_BUG)
+		br32(B44_DMATX_PTR);
+
+	if (TX_BUFFS_AVAIL(bp) < 1)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&bp->lock);
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+static int b44_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct b44 *bp = dev->priv;
+
+	if (new_mtu < B44_MIN_MTU || new_mtu > B44_MAX_MTU)
+		return -EINVAL;
+
+	if (!netif_running(dev)) {
+		/* We'll just catch it later when the
+		 * device is up'd.
+		 */
+		dev->mtu = new_mtu;
+		return 0;
+	}
+
+	spin_lock_irq(&bp->lock);
+	b44_halt(bp);
+	dev->mtu = new_mtu;
+	b44_init_rings(bp);
+	b44_init_hw(bp);
+	spin_unlock_irq(&bp->lock);
+
+	return 0;
+}
+
+/* Free up pending packets in all rx/tx rings.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.  bp->lock is not held and we are not
+ * in an interrupt context and thus may sleep.
+ */
+static void b44_free_rings(struct b44 *bp)
+{
+	struct ring_info *rp;
+	int i;
+
+	for (i = 0; i < B44_RX_RING_SIZE; i++) {
+		rp = &bp->rx_buffers[i];
+
+		if (rp->skb == NULL)
+			continue;
+		pci_unmap_single(bp->pdev,
+				 pci_unmap_addr(rp, mapping),
+				 RX_PKT_BUF_SZ,
+				 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(rp->skb);
+		rp->skb = NULL;
+	}
+
+	/* XXX needs changes once NETIF_F_SG is set... */
+	for (i = 0; i < B44_TX_RING_SIZE; i++) {
+		rp = &bp->tx_buffers[i];
+
+		if (rp->skb == NULL)
+			continue;
+		pci_unmap_single(bp->pdev,
+				 pci_unmap_addr(rp, mapping),
+				 rp->skb->len,
+				 PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(rp->skb);
+		rp->skb = NULL;
+	}
+}
+
+/* Initialize tx/rx rings for packet processing.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.  bp->lock is not held and we are not
+ * in an interrupt context and thus may sleep.
+ */
+static void b44_init_rings(struct b44 *bp)
+{
+	int i;
+
+	b44_free_rings(bp);
+
+	memset(bp->rx_ring, 0, B44_RX_RING_BYTES);
+	memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
+
+	for (i = 0; i < bp->rx_pending; i++) {
+		if (b44_alloc_rx_skb(bp, -1, i) < 0)
+			break;
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.
+ */
+static void b44_free_consistent(struct b44 *bp)
+{
+	if (bp->rx_buffers) {
+		kfree(bp->rx_buffers);
+		bp->rx_buffers = NULL;
+	}
+	if (bp->tx_buffers) {
+		kfree(bp->tx_buffers);
+		bp->tx_buffers = NULL;
+	}
+	if (bp->rx_ring) {
+		pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+				    bp->rx_ring, bp->rx_ring_dma);
+		bp->rx_ring = NULL;
+	}
+	if (bp->tx_ring) {
+		pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+				    bp->tx_ring, bp->tx_ring_dma);
+		bp->tx_ring = NULL;
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.  Can sleep.
+ */
+static int b44_alloc_consistent(struct b44 *bp)
+{
+	int size;
+
+	size  = B44_RX_RING_SIZE * sizeof(struct ring_info);
+	bp->rx_buffers = kmalloc(size, GFP_KERNEL);
+	if (!bp->rx_buffers)
+		goto out_err;
+	memset(bp->rx_buffers, 0, size);
+
+	size = B44_TX_RING_SIZE * sizeof(struct ring_info);
+	bp->tx_buffers = kmalloc(size, GFP_KERNEL);
+	if (!bp->tx_buffers)
+		goto out_err;
+	memset(bp->tx_buffers, 0, size);
+
+	size = DMA_TABLE_BYTES;
+	bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
+	if (!bp->rx_ring)
+		goto out_err;
+
+	bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
+	if (!bp->tx_ring)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	b44_free_consistent(bp);
+	return -ENOMEM;
+}
+
+/* bp->lock is held. */
+static void b44_clear_stats(struct b44 *bp)
+{
+	unsigned long reg;
+
+	bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+	for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL)
+		br32(reg);
+	for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL)
+		br32(reg);
+}
+
+/* bp->lock is held. */
+static void b44_chip_reset(struct b44 *bp)
+{
+	if (ssb_is_core_up(bp)) {
+		bw32(B44_RCV_LAZY, 0);
+		bw32(B44_ENET_CTRL, ENET_CTRL_DISABLE);
+		b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1);
+		bw32(B44_DMATX_CTRL, 0);
+		bp->tx_prod = bp->tx_cons = 0;
+		if (br32(B44_DMARX_STAT) & DMARX_STAT_EMASK) {
+			b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE,
+				     100, 0);
+		}
+		bw32(B44_DMARX_CTRL, 0);
+		bp->rx_prod = bp->rx_cons = 0;
+	} else {
+		ssb_pci_setup(bp, (bp->core_unit == 0 ?
+				   SBINTVEC_ENET0 :
+				   SBINTVEC_ENET1));
+	}
+
+	ssb_core_reset(bp);
+
+	b44_clear_stats(bp);
+
+	/* Make PHY accessible. */
+	bw32(B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+			     (0x0d & MDIO_CTRL_MAXF_MASK)));
+	br32(B44_MDIO_CTRL);
+
+	if (!(br32(B44_DEVCTRL) & DEVCTRL_IPP)) {
+		bw32(B44_ENET_CTRL, ENET_CTRL_EPSEL);
+		br32(B44_ENET_CTRL);
+		bp->flags &= ~B44_FLAG_INTERNAL_PHY;
+	} else {
+		u32 val = br32(B44_DEVCTRL);
+
+		if (val & DEVCTRL_EPR) {
+			bw32(B44_DEVCTRL, (val & ~DEVCTRL_EPR));
+			br32(B44_DEVCTRL);
+			udelay(100);
+		}
+		bp->flags |= B44_FLAG_INTERNAL_PHY;
+	}
+}
+
+/* bp->lock is held. */
+static void b44_halt(struct b44 *bp)
+{
+	b44_disable_ints(bp);
+	b44_chip_reset(bp);
+}
+
+/* bp->lock is held. */
+static void __b44_set_mac_addr(struct b44 *bp)
+{
+	bw32(B44_CAM_CTRL, 0);
+	if (!(bp->dev->flags & IFF_PROMISC)) {
+		u32 val;
+
+		__b44_cam_write(bp, bp->dev->dev_addr, 0);
+		val = br32(B44_CAM_CTRL);
+		bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+	}
+}
+
+static int b44_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct b44 *bp = dev->priv;
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	spin_lock_irq(&bp->lock);
+	__b44_set_mac_addr(bp);
+	spin_unlock_irq(&bp->lock);
+
+	return 0;
+}
+
+/* Called at device open time to get the chip ready for
+ * packet processing.  Invoked with bp->lock held.
+ */
+static void __b44_set_rx_mode(struct net_device *);
+static int b44_init_hw(struct b44 *bp)
+{
+	u32 val;
+
+	b44_disable_ints(bp);
+	b44_chip_reset(bp);
+	b44_phy_reset(bp);
+	b44_setup_phy(bp);
+	val = br32(B44_MAC_CTRL);
+	bw32(B44_MAC_CTRL, val | MAC_CTRL_CRC32_ENAB);
+	bw32(B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
+
+	/* This sets the MAC address too.  */
+	__b44_set_rx_mode(bp->dev);
+
+	/* MTU + eth header + possible VLAN tag + struct rx_header */
+	bw32(B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
+	bw32(B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
+
+	bw32(B44_TX_WMARK, 56); /* XXX magic */
+	bw32(B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
+	bw32(B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
+	bw32(B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+			      (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+	bw32(B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
+
+	bw32(B44_DMARX_PTR, bp->rx_pending);
+	bp->rx_prod = bp->rx_pending;	
+
+	bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+
+	val = br32(B44_ENET_CTRL);
+	bw32(B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
+
+	return 0;
+}
+
+static int b44_open(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	int err;
+
+	err = b44_alloc_consistent(bp);
+	if (err)
+		return err;
+
+	err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
+	if (err)
+		goto err_out_free;
+
+	spin_lock_irq(&bp->lock);
+
+	b44_init_rings(bp);
+	err = b44_init_hw(bp);
+	if (err)
+		goto err_out_noinit;
+	bp->flags |= B44_FLAG_INIT_COMPLETE;
+
+	spin_unlock_irq(&bp->lock);
+
+	init_timer(&bp->timer);
+	bp->timer.expires = jiffies + HZ;
+	bp->timer.data = (unsigned long) bp;
+	bp->timer.function = b44_timer;
+	add_timer(&bp->timer);
+
+	b44_enable_ints(bp);
+
+	return 0;
+
+err_out_noinit:
+	b44_halt(bp);
+	b44_free_rings(bp);
+	spin_unlock_irq(&bp->lock);
+	free_irq(dev->irq, dev);
+err_out_free:
+	b44_free_consistent(bp);
+	return err;
+}
+
+#if 0
+/*static*/ void b44_dump_state(struct b44 *bp)
+{
+	u32 val32, val32_2, val32_3, val32_4, val32_5;
+	u16 val16;
+
+	pci_read_config_word(bp->pdev, PCI_STATUS, &val16);
+	printk("DEBUG: PCI status [%04x] \n", val16);
+
+}
+#endif
+
+static int b44_close(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+
+	netif_stop_queue(dev);
+
+	del_timer_sync(&bp->timer);
+
+	spin_lock_irq(&bp->lock);
+
+#if 0
+	b44_dump_state(bp);
+#endif
+	b44_halt(bp);
+	b44_free_rings(bp);
+	bp->flags &= ~B44_FLAG_INIT_COMPLETE;
+	netif_carrier_off(bp->dev);
+
+	spin_unlock_irq(&bp->lock);
+
+	free_irq(dev->irq, dev);
+
+	b44_free_consistent(bp);
+
+	return 0;
+}
+
+static struct net_device_stats *b44_get_stats(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	struct net_device_stats *nstat = &bp->stats;
+	struct b44_hw_stats *hwstat = &bp->hw_stats;
+
+	/* Convert HW stats into netdevice stats. */
+	nstat->rx_packets = hwstat->rx_pkts;
+	nstat->tx_packets = hwstat->tx_pkts;
+	nstat->rx_bytes   = hwstat->rx_octets;
+	nstat->tx_bytes   = hwstat->tx_octets;
+	nstat->tx_errors  = (hwstat->tx_jabber_pkts +
+			     hwstat->tx_oversize_pkts +
+			     hwstat->tx_underruns +
+			     hwstat->tx_excessive_cols +
+			     hwstat->tx_late_cols);
+	nstat->multicast  = hwstat->tx_multicast_pkts;
+	nstat->collisions = hwstat->tx_total_cols;
+
+	nstat->rx_length_errors = (hwstat->rx_oversize_pkts +
+				   hwstat->rx_undersize);
+	nstat->rx_over_errors   = hwstat->rx_missed_pkts;
+	nstat->rx_frame_errors  = hwstat->rx_align_errs;
+	nstat->rx_crc_errors    = hwstat->rx_crc_errs;
+	nstat->rx_errors        = (hwstat->rx_jabber_pkts +
+				   hwstat->rx_oversize_pkts +
+				   hwstat->rx_missed_pkts +
+				   hwstat->rx_crc_align_errs +
+				   hwstat->rx_undersize +
+				   hwstat->rx_crc_errs +
+				   hwstat->rx_align_errs +
+				   hwstat->rx_symbol_errs);
+
+	nstat->tx_aborted_errors = hwstat->tx_underruns;
+	nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
+
+	return nstat;
+}
+
+static void __b44_load_mcast(struct b44 *bp, struct net_device *dev)
+{
+	struct dev_mc_list *mclist;
+	int i, num_ents;
+
+	num_ents = min_t(int, dev->mc_count, B44_MCAST_TABLE_SIZE);
+	mclist = dev->mc_list;
+	for (i = 0; mclist && i < num_ents; i++, mclist = mclist->next) {
+		__b44_cam_write(bp, mclist->dmi_addr, i + 1);
+	}
+}
+
+static void __b44_set_rx_mode(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	u32 val;
+
+	val = br32(B44_RXCONFIG);
+	val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
+	if (dev->flags & IFF_PROMISC) {
+		val |= RXCONFIG_PROMISC;
+		bw32(B44_RXCONFIG, val);
+	} else {
+		__b44_set_mac_addr(bp);
+
+		if (dev->flags & IFF_ALLMULTI)
+			val |= RXCONFIG_ALLMULTI;
+		else
+			__b44_load_mcast(bp, dev);
+
+		bw32(B44_RXCONFIG, val);
+        	val = br32(B44_CAM_CTRL);
+	        bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+	}
+}
+
+static void b44_set_rx_mode(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+
+	spin_lock_irq(&bp->lock);
+	__b44_set_rx_mode(dev);
+	spin_unlock_irq(&bp->lock);
+}
+
+static int b44_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct b44 *bp = dev->priv;
+	struct pci_dev *pci_dev = bp->pdev;
+	u32 ethcmd;
+
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO:{
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_MODULE_NAME);
+		strcpy (info.version, DRV_MODULE_VERSION);
+		memset(&info.fw_version, 0, sizeof(info.fw_version));
+		strcpy (info.bus_info, pci_dev->slot_name);
+		info.eedump_len = 0;
+		info.regdump_len = 0;
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+		if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+			return -EAGAIN;
+		cmd.supported = (SUPPORTED_Autoneg);
+		cmd.supported |= (SUPPORTED_100baseT_Half |
+				  SUPPORTED_100baseT_Full |
+				  SUPPORTED_10baseT_Half |
+				  SUPPORTED_10baseT_Full |
+				  SUPPORTED_MII);
+
+		cmd.advertising = 0;
+		if (bp->flags & B44_FLAG_ADV_10HALF)
+			cmd.advertising |= ADVERTISE_10HALF;
+		if (bp->flags & B44_FLAG_ADV_10FULL)
+			cmd.advertising |= ADVERTISE_10FULL;
+		if (bp->flags & B44_FLAG_ADV_100HALF)
+			cmd.advertising |= ADVERTISE_100HALF;
+		if (bp->flags & B44_FLAG_ADV_100FULL)
+			cmd.advertising |= ADVERTISE_100FULL;
+		cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+		cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ?
+			SPEED_100 : SPEED_10;
+		cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
+			DUPLEX_FULL : DUPLEX_HALF;
+		cmd.port = 0;
+		cmd.phy_address = bp->phy_addr;
+		cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
+			XCVR_INTERNAL : XCVR_EXTERNAL;
+		cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
+			AUTONEG_DISABLE : AUTONEG_ENABLE;
+		cmd.maxtxpkt = 0;
+		cmd.maxrxpkt = 0;
+		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd cmd;
+
+		if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+			return -EAGAIN;
+
+		if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+			return -EFAULT;
+
+		/* We do not support gigabit. */
+		if (cmd.autoneg == AUTONEG_ENABLE) {
+			if (cmd.advertising &
+			    (ADVERTISED_1000baseT_Half |
+			     ADVERTISED_1000baseT_Full))
+				return -EINVAL;
+		} else if ((cmd.speed != SPEED_100 &&
+			    cmd.speed != SPEED_10) ||
+			   (cmd.duplex != DUPLEX_HALF &&
+			    cmd.duplex != DUPLEX_FULL)) {
+				return -EINVAL;
+		}
+
+		spin_lock_irq(&bp->lock);
+
+		if (cmd.autoneg == AUTONEG_ENABLE) {
+			bp->flags &= ~B44_FLAG_FORCE_LINK;
+			bp->flags &= ~(B44_FLAG_ADV_10HALF |
+				       B44_FLAG_ADV_10FULL |
+				       B44_FLAG_ADV_100HALF |
+				       B44_FLAG_ADV_100FULL);
+			if (cmd.advertising & ADVERTISE_10HALF)
+				bp->flags |= B44_FLAG_ADV_10HALF;
+			if (cmd.advertising & ADVERTISE_10FULL)
+				bp->flags |= B44_FLAG_ADV_10FULL;
+			if (cmd.advertising & ADVERTISE_100HALF)
+				bp->flags |= B44_FLAG_ADV_100HALF;
+			if (cmd.advertising & ADVERTISE_100FULL)
+				bp->flags |= B44_FLAG_ADV_100FULL;
+		} else {
+			bp->flags |= B44_FLAG_FORCE_LINK;
+			if (cmd.speed == SPEED_100)
+				bp->flags |= B44_FLAG_100_BASE_T;
+			if (cmd.duplex == DUPLEX_FULL)
+				bp->flags |= B44_FLAG_FULL_DUPLEX;
+		}
+
+		b44_setup_phy(bp);
+
+		spin_unlock_irq(&bp->lock);
+
+		return 0;
+	}
+
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+		edata.data = bp->msg_enable;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		bp->msg_enable = edata.data;
+		return 0;
+	}
+	case ETHTOOL_NWAY_RST: {
+		u32 bmcr;
+		int r;
+
+		spin_lock_irq(&bp->lock);
+		b44_readphy(bp, MII_BMCR, &bmcr);
+		b44_readphy(bp, MII_BMCR, &bmcr);
+		r = -EINVAL;
+		if (bmcr & BMCR_ANENABLE) {
+			b44_writephy(bp, MII_BMCR,
+				     bmcr | BMCR_ANRESTART);
+			r = 0;
+		}
+		spin_unlock_irq(&bp->lock);
+
+		return r;
+	}
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		edata.data = netif_carrier_ok(bp->dev) ? 1 : 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_GRINGPARAM: {
+		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
+
+		ering.rx_max_pending = B44_RX_RING_SIZE - 1;
+		ering.rx_pending = bp->rx_pending;
+
+		/* XXX ethtool lacks a tx_max_pending, oops... */
+
+		if (copy_to_user(useraddr, &ering, sizeof(ering)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SRINGPARAM: {
+		struct ethtool_ringparam ering;
+
+		if (copy_from_user(&ering, useraddr, sizeof(ering)))
+			return -EFAULT;
+
+		if ((ering.rx_pending > B44_RX_RING_SIZE - 1) ||
+		    (ering.rx_mini_pending != 0) ||
+		    (ering.rx_jumbo_pending != 0) ||
+		    (ering.tx_pending > B44_TX_RING_SIZE - 1))
+			return -EINVAL;
+
+		spin_lock_irq(&bp->lock);
+
+		bp->rx_pending = ering.rx_pending;
+		bp->tx_pending = ering.tx_pending;
+
+		b44_halt(bp);
+		b44_init_rings(bp);
+		b44_init_hw(bp);
+		netif_wake_queue(bp->dev);
+		spin_unlock_irq(&bp->lock);
+
+		return 0;
+	}
+	case ETHTOOL_GPAUSEPARAM: {
+		struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
+
+		epause.autoneg =
+			(bp->flags & B44_FLAG_PAUSE_AUTO) != 0;
+		epause.rx_pause =
+			(bp->flags & B44_FLAG_RX_PAUSE) != 0;
+		epause.tx_pause =
+			(bp->flags & B44_FLAG_TX_PAUSE) != 0;
+		if (copy_to_user(useraddr, &epause, sizeof(epause)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SPAUSEPARAM: {
+		struct ethtool_pauseparam epause;
+
+		if (copy_from_user(&epause, useraddr, sizeof(epause)))
+			return -EFAULT;
+
+		spin_lock_irq(&bp->lock);
+		if (epause.autoneg)
+			bp->flags |= B44_FLAG_PAUSE_AUTO;
+		else
+			bp->flags &= ~B44_FLAG_PAUSE_AUTO;
+		if (epause.rx_pause)
+			bp->flags |= B44_FLAG_RX_PAUSE;
+		else
+			bp->flags &= ~B44_FLAG_RX_PAUSE;
+		if (epause.tx_pause)
+			bp->flags |= B44_FLAG_TX_PAUSE;
+		else
+			bp->flags &= ~B44_FLAG_TX_PAUSE;
+		if (bp->flags & B44_FLAG_PAUSE_AUTO) {
+			b44_halt(bp);
+			b44_init_rings(bp);
+			b44_init_hw(bp);
+		} else {
+			__b44_set_flow_ctrl(bp, bp->flags);
+		}
+		spin_unlock_irq(&bp->lock);
+
+		return 0;
+	}
+	};
+
+	return -EOPNOTSUPP;
+}
+
+static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	struct b44 *bp = dev->priv;
+	int err;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return b44_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+
+	case SIOCGMIIPHY:
+		data->phy_id = bp->phy_addr;
+
+		/* fallthru */
+	case SIOCGMIIREG: {
+		u32 mii_regval;
+
+		spin_lock_irq(&bp->lock);
+		err = b44_readphy(bp, data->reg_num & 0x1f, &mii_regval);
+		spin_unlock_irq(&bp->lock);
+
+		data->val_out = mii_regval;
+
+		return err;
+	}
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		spin_lock_irq(&bp->lock);
+		err = b44_writephy(bp, data->reg_num & 0x1f, data->val_in);
+		spin_unlock_irq(&bp->lock);
+
+		return err;
+
+	default:
+		/* do nothing */
+		break;
+	};
+	return -EOPNOTSUPP;
+}
+
+/* Read 128-bytes of EEPROM. */
+static int b44_read_eeprom(struct b44 *bp, u8 *data)
+{
+	long i;
+	u16 *ptr = (u16 *) data;
+
+	for (i = 0; i < 128; i += 2)
+		ptr[i / 2] = readw(bp->regs + 4096 + i);
+
+	return 0;
+}
+
+static int __devinit b44_get_invariants(struct b44 *bp)
+{
+	u8 eeprom[128];
+	int err;
+
+	err = b44_read_eeprom(bp, &eeprom[0]);
+	if (err)
+		goto out;
+
+	bp->dev->dev_addr[0] = eeprom[79];
+	bp->dev->dev_addr[1] = eeprom[78];
+	bp->dev->dev_addr[2] = eeprom[81];
+	bp->dev->dev_addr[3] = eeprom[80];
+	bp->dev->dev_addr[4] = eeprom[83];
+	bp->dev->dev_addr[5] = eeprom[82];
+
+	bp->phy_addr = eeprom[90] & 0x1f;
+	bp->mdc_port = (eeprom[90] >> 14) & 0x1;
+
+	/* With this, plus the rx_header prepended to the data by the
+	 * hardware, we'll land the ethernet header on a 2-byte boundary.
+	 */
+	bp->rx_offset = 30;
+
+	bp->imask = IMASK_DEF;
+
+	bp->core_unit = ssb_core_unit(bp);
+	bp->dma_offset = ssb_get_addr(bp, SBID_PCI_DMA, 0);
+
+	/* XXX - really required? 
+	   bp->flags |= B44_FLAG_BUGGY_TXPTR;
+         */
+out:
+	return err;
+}
+
+static int __devinit b44_init_one(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	static int b44_version_printed = 0;
+	unsigned long b44reg_base, b44reg_len;
+	struct net_device *dev;
+	struct b44 *bp;
+	int err, i;
+
+	if (b44_version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device, "
+		       "aborting.\n");
+		return err;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX "Cannot find proper PCI device "
+		       "base address, aborting.\n");
+		err = -ENODEV;
+		goto err_out_disable_pdev;
+	}
+
+	err = pci_request_regions(pdev, DRV_MODULE_NAME);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+		       "aborting.\n");
+		goto err_out_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+	if (err) {
+		printk(KERN_ERR PFX "No usable DMA configuration, "
+		       "aborting.\n");
+		goto err_out_free_res;
+	}
+
+	b44reg_base = pci_resource_start(pdev, 0);
+	b44reg_len = pci_resource_len(pdev, 0);
+
+	dev = alloc_etherdev(sizeof(*bp));
+	if (!dev) {
+		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_res;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	/* No interesting netdevice features in this card... */
+	dev->features |= 0;
+
+	bp = dev->priv;
+	bp->pdev = pdev;
+	bp->dev = dev;
+	if (b44_debug >= 0)
+		bp->msg_enable = (1 << b44_debug) - 1;
+	else
+		bp->msg_enable = B44_DEF_MSG_ENABLE;
+
+	spin_lock_init(&bp->lock);
+
+	bp->regs = (unsigned long) ioremap(b44reg_base, b44reg_len);
+	if (bp->regs == 0UL) {
+		printk(KERN_ERR PFX "Cannot map device registers, "
+		       "aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_dev;
+	}
+
+	bp->rx_pending = B44_DEF_RX_RING_PENDING;
+	bp->tx_pending = B44_DEF_TX_RING_PENDING;
+
+	dev->open = b44_open;
+	dev->stop = b44_close;
+	dev->hard_start_xmit = b44_start_xmit;
+	dev->get_stats = b44_get_stats;
+	dev->set_multicast_list = b44_set_rx_mode;
+	dev->set_mac_address = b44_set_mac_addr;
+	dev->do_ioctl = b44_ioctl;
+	dev->tx_timeout = b44_tx_timeout;
+	dev->poll = b44_poll;
+	dev->weight = 64;
+	dev->watchdog_timeo = B44_TX_TIMEOUT;
+	dev->change_mtu = b44_change_mtu;
+	dev->irq = pdev->irq;
+
+	err = b44_get_invariants(bp);
+	if (err) {
+		printk(KERN_ERR PFX "Problem fetching invariants of chip, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	/* By default, advertise all speed/duplex settings. */
+	bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
+		      B44_FLAG_ADV_100HALF | B44_FLAG_ADV_100FULL);
+
+	/* By default, auto-negotiate PAUSE. */
+	bp->flags |= B44_FLAG_PAUSE_AUTO;
+
+	err = register_netdev(dev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	pci_save_state(bp->pdev, bp->pci_cfg_state);
+
+	printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i],
+		       i == 5 ? '\n' : ':');
+
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *) bp->regs);
+
+err_out_free_dev:
+	kfree(dev);
+
+err_out_free_res:
+	pci_release_regions(pdev);
+
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void __devexit b44_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		unregister_netdev(dev);
+		iounmap((void *) ((struct b44 *)(dev->priv))->regs);
+		kfree(dev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static struct pci_driver b44_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= b44_pci_tbl,
+	.probe		= b44_init_one,
+	.remove		= __devexit_p(b44_remove_one),
+};
+
+static int __init b44_init(void)
+{
+	return pci_module_init(&b44_driver);
+}
+
+static void __exit b44_cleanup(void)
+{
+	pci_unregister_driver(&b44_driver);
+}
+
+module_init(b44_init);
+module_exit(b44_cleanup);
+
diff -urN linux-2.4.22-pre9/drivers/net/b44.h linux-2.4.22-pre10/drivers/net/b44.h
--- linux-2.4.22-pre9/drivers/net/b44.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-pre10/drivers/net/b44.h	2003-08-01 09:16:08.000000000 -0700
@@ -0,0 +1,543 @@
+#ifndef _B44_H
+#define _B44_H
+
+/* Register layout. */
+#define	B44_DEVCTRL	0x0000UL /* Device Control */
+#define  DEVCTRL_PFE		0x00000080 /* Pattern Filtering Enable */
+#define  DEVCTRL_IPP		0x00000400 /* Internal EPHY Present */
+#define  DEVCTRL_EPR		0x00008000 /* EPHY Reset */
+#define  DEVCTRL_PME		0x00001000 /* PHY Mode Enable */
+#define  DEVCTRL_PMCE		0x00002000 /* PHY Mode Clocks Enable */
+#define  DEVCTRL_PADDR		0x0007c000 /* PHY Address */
+#define  DEVCTRL_PADDR_SHIFT	18
+#define B44_BIST_STAT	0x000CUL /* Built-In Self-Test Status */
+#define B44_WKUP_LEN	0x0010UL /* Wakeup Length */
+#define  WKUP_LEN_P0_MASK	0x0000007f /* Pattern 0 */
+#define  WKUP_LEN_D0		0x00000080
+#define  WKUP_LEN_P1_MASK	0x00007f00 /* Pattern 1 */
+#define  WKUP_LEN_P1_SHIFT	8
+#define  WKUP_LEN_D1		0x00008000
+#define  WKUP_LEN_P2_MASK	0x007f0000 /* Pattern 2 */
+#define  WKUP_LEN_P2_SHIFT	16
+#define  WKUP_LEN_D2		0x00000000
+#define  WKUP_LEN_P3_MASK	0x7f000000 /* Pattern 3 */
+#define  WKUP_LEN_P3_SHIFT	24
+#define  WKUP_LEN_D3		0x80000000
+#define B44_ISTAT	0x0020UL /* Interrupt Status */
+#define  ISTAT_PME		0x00000040 /* Power Management Event */
+#define  ISTAT_TO		0x00000080 /* General Purpose Timeout */
+#define  ISTAT_DSCE		0x00000400 /* Descriptor Error */
+#define  ISTAT_DATAE		0x00000800 /* Data Error */
+#define  ISTAT_DPE		0x00001000 /* Descr. Protocol Error */
+#define  ISTAT_RDU		0x00002000 /* Receive Descr. Underflow */
+#define  ISTAT_RFO		0x00004000 /* Receive FIFO Overflow */
+#define  ISTAT_TFU		0x00008000 /* Transmit FIFO Underflow */
+#define  ISTAT_RX		0x00010000 /* RX Interrupt */
+#define  ISTAT_TX		0x01000000 /* TX Interrupt */
+#define  ISTAT_EMAC		0x04000000 /* EMAC Interrupt */
+#define  ISTAT_MII_WRITE	0x08000000 /* MII Write Interrupt */
+#define  ISTAT_MII_READ		0x10000000 /* MII Read Interrupt */
+#define  ISTAT_ERRORS (ISTAT_DSCE|ISTAT_DATAE|ISTAT_DPE|ISTAT_RDU|ISTAT_RFO|ISTAT_TFU)
+#define B44_IMASK	0x0024UL /* Interrupt Mask */
+#define  IMASK_DEF		(ISTAT_ERRORS | ISTAT_TO | ISTAT_RX | ISTAT_TX)
+#define B44_GPTIMER	0x0028UL /* General Purpose Timer */
+#define B44_FILT_ADDR	0x0090UL /* ENET Filter Address */
+#define B44_FILT_DATA	0x0094UL /* ENET Filter Data */
+#define B44_TXBURST	0x00A0UL /* TX Max Burst Length */
+#define B44_RXBURST	0x00A4UL /* RX Max Burst Length */
+#define B44_MAC_CTRL	0x00A8UL /* MAC Control */
+#define  MAC_CTRL_CRC32_ENAB	0x00000001 /* CRC32 Generation Enable */
+#define  MAC_CTRL_PHY_PDOWN	0x00000004 /* Onchip EPHY Powerdown */
+#define  MAC_CTRL_PHY_EDET	0x00000008 /* Onchip EPHY Energy Detected */
+#define  MAC_CTRL_PHY_LEDCTRL	0x000000e0 /* Onchip EPHY LED Control */
+#define  MAC_CTRL_PHY_LEDCTRL_SHIFT 5
+#define B44_MAC_FLOW	0x00ACUL /* MAC Flow Control */
+#define  MAC_FLOW_RX_HI_WATER	0x000000ff /* Receive FIFO HI Water Mark */
+#define  MAC_FLOW_PAUSE_ENAB	0x00008000 /* Enable Pause Frame Generation */
+#define B44_RCV_LAZY	0x0100UL /* Lazy Interrupt Control */
+#define  RCV_LAZY_TO_MASK	0x00ffffff /* Timeout */
+#define  RCV_LAZY_FC_MASK	0xff000000 /* Frame Count */
+#define  RCV_LAZY_FC_SHIFT	24
+#define B44_DMATX_CTRL	0x0200UL /* DMA TX Control */
+#define  DMATX_CTRL_ENABLE	0x00000001 /* Enable */
+#define  DMATX_CTRL_SUSPEND	0x00000002 /* Suepend Request */
+#define  DMATX_CTRL_LPBACK	0x00000004 /* Loopback Enable */
+#define  DMATX_CTRL_FAIRPRIOR	0x00000008 /* Fair Priority */
+#define  DMATX_CTRL_FLUSH	0x00000010 /* Flush Request */
+#define B44_DMATX_ADDR	0x0204UL /* DMA TX Descriptor Ring Address */
+#define B44_DMATX_PTR	0x0208UL /* DMA TX Last Posted Descriptor */
+#define B44_DMATX_STAT	0x020CUL /* DMA TX Current Active Desc. + Status */
+#define  DMATX_STAT_CDMASK	0x00000fff /* Current Descriptor Mask */
+#define  DMATX_STAT_SMASK	0x0000f000 /* State Mask */
+#define  DMATX_STAT_SDISABLED	0x00000000 /* State Disabled */
+#define  DMATX_STAT_SACTIVE	0x00001000 /* State Active */
+#define  DMATX_STAT_SIDLE	0x00002000 /* State Idle Wait */
+#define  DMATX_STAT_SSTOPPED	0x00003000 /* State Stopped */
+#define  DMATX_STAT_SSUSP	0x00004000 /* State Suspend Pending */
+#define  DMATX_STAT_EMASK	0x000f0000 /* Error Mask */
+#define  DMATX_STAT_ENONE	0x00000000 /* Error None */
+#define  DMATX_STAT_EDPE	0x00010000 /* Error Desc. Protocol Error */
+#define  DMATX_STAT_EDFU	0x00020000 /* Error Data FIFO Underrun */
+#define  DMATX_STAT_EBEBR	0x00030000 /* Error Bus Error on Buffer Read */
+#define  DMATX_STAT_EBEDA	0x00040000 /* Error Bus Error on Desc. Access */
+#define  DMATX_STAT_FLUSHED	0x00100000 /* Flushed */
+#define B44_DMARX_CTRL	0x0210UL /* DMA RX Control */
+#define  DMARX_CTRL_ENABLE	0x00000001 /* Enable */
+#define  DMARX_CTRL_ROMASK	0x000000fe /* Receive Offset Mask */
+#define  DMARX_CTRL_ROSHIFT	1 	   /* Receive Offset Shift */
+#define B44_DMARX_ADDR	0x0214UL /* DMA RX Descriptor Ring Address */
+#define B44_DMARX_PTR	0x0218UL /* DMA RX Last Posted Descriptor */
+#define B44_DMARX_STAT	0x021CUL /* DMA RX Current Active Desc. + Status */
+#define  DMARX_STAT_CDMASK	0x00000fff /* Current Descriptor Mask */
+#define  DMARX_STAT_SMASK	0x0000f000 /* State Mask */
+#define  DMARX_STAT_SDISABLED	0x00000000 /* State Disbaled */
+#define  DMARX_STAT_SACTIVE	0x00001000 /* State Active */
+#define  DMARX_STAT_SIDLE	0x00002000 /* State Idle Wait */
+#define  DMARX_STAT_SSTOPPED	0x00003000 /* State Stopped */
+#define  DMARX_STAT_EMASK	0x000f0000 /* Error Mask */
+#define  DMARX_STAT_ENONE	0x00000000 /* Error None */
+#define  DMARX_STAT_EDPE	0x00010000 /* Error Desc. Protocol Error */
+#define  DMARX_STAT_EDFO	0x00020000 /* Error Data FIFO Overflow */
+#define  DMARX_STAT_EBEBW	0x00030000 /* Error Bus Error on Buffer Write */
+#define  DMARX_STAT_EBEDA	0x00040000 /* Error Bus Error on Desc. Access */
+#define B44_DMAFIFO_AD	0x0220UL /* DMA FIFO Diag Address */
+#define  DMAFIFO_AD_OMASK	0x0000ffff /* Offset Mask */
+#define  DMAFIFO_AD_SMASK	0x000f0000 /* Select Mask */
+#define  DMAFIFO_AD_SXDD	0x00000000 /* Select Transmit DMA Data */
+#define  DMAFIFO_AD_SXDP	0x00010000 /* Select Transmit DMA Pointers */
+#define  DMAFIFO_AD_SRDD	0x00040000 /* Select Receive DMA Data */
+#define  DMAFIFO_AD_SRDP	0x00050000 /* Select Receive DMA Pointers */
+#define  DMAFIFO_AD_SXFD	0x00080000 /* Select Transmit FIFO Data */
+#define  DMAFIFO_AD_SXFP	0x00090000 /* Select Transmit FIFO Pointers */
+#define  DMAFIFO_AD_SRFD	0x000c0000 /* Select Receive FIFO Data */
+#define  DMAFIFO_AD_SRFP	0x000c0000 /* Select Receive FIFO Pointers */
+#define B44_DMAFIFO_LO	0x0224UL /* DMA FIFO Diag Low Data */
+#define B44_DMAFIFO_HI	0x0228UL /* DMA FIFO Diag High Data */
+#define B44_RXCONFIG	0x0400UL /* EMAC RX Config */
+#define  RXCONFIG_DBCAST	0x00000001 /* Disable Broadcast */
+#define  RXCONFIG_ALLMULTI	0x00000002 /* Accept All Multicast */
+#define  RXCONFIG_NORX_WHILE_TX	0x00000004 /* Receive Disable While Transmitting */
+#define  RXCONFIG_PROMISC	0x00000008 /* Promiscuous Enable */
+#define  RXCONFIG_LPBACK	0x00000010 /* Loopback Enable */
+#define  RXCONFIG_FLOW		0x00000020 /* Flow Control Enable */
+#define  RXCONFIG_FLOW_ACCEPT	0x00000040 /* Accept Unicast Flow Control Frame */
+#define  RXCONFIG_RFILT		0x00000080 /* Reject Filter */
+#define B44_RXMAXLEN	0x0404UL /* EMAC RX Max Packet Length */
+#define B44_TXMAXLEN	0x0408UL /* EMAC TX Max Packet Length */
+#define B44_MDIO_CTRL	0x0410UL /* EMAC MDIO Control */
+#define  MDIO_CTRL_MAXF_MASK	0x0000007f /* MDC Frequency */
+#define  MDIO_CTRL_PREAMBLE	0x00000080 /* MII Preamble Enable */
+#define B44_MDIO_DATA	0x0414UL /* EMAC MDIO Data */
+#define  MDIO_DATA_DATA		0x0000ffff /* R/W Data */
+#define  MDIO_DATA_TA_MASK	0x00030000 /* Turnaround Value */
+#define  MDIO_DATA_TA_SHIFT	16
+#define  MDIO_TA_VALID		2
+#define  MDIO_DATA_RA_MASK	0x007c0000 /* Register Address */
+#define  MDIO_DATA_RA_SHIFT	18
+#define  MDIO_DATA_PMD_MASK	0x0f800000 /* Physical Media Device */
+#define  MDIO_DATA_PMD_SHIFT	23
+#define  MDIO_DATA_OP_MASK	0x30000000 /* Opcode */
+#define  MDIO_DATA_OP_SHIFT	28
+#define  MDIO_OP_WRITE		1
+#define  MDIO_OP_READ		2
+#define  MDIO_DATA_SB_MASK	0xc0000000 /* Start Bits */
+#define  MDIO_DATA_SB_SHIFT	30
+#define  MDIO_DATA_SB_START	0x40000000 /* Start Of Frame */
+#define B44_EMAC_IMASK	0x0418UL /* EMAC Interrupt Mask */
+#define B44_EMAC_ISTAT	0x041CUL /* EMAC Interrupt Status */
+#define  EMAC_INT_MII		0x00000001 /* MII MDIO Interrupt */
+#define  EMAC_INT_MIB		0x00000002 /* MIB Interrupt */
+#define  EMAC_INT_FLOW		0x00000003 /* Flow Control Interrupt */
+#define B44_CAM_DATA_LO	0x0420UL /* EMAC CAM Data Low */
+#define B44_CAM_DATA_HI	0x0424UL /* EMAC CAM Data High */
+#define  CAM_DATA_HI_VALID	0x00010000 /* Valid Bit */
+#define B44_CAM_CTRL	0x0428UL /* EMAC CAM Control */
+#define  CAM_CTRL_ENABLE	0x00000001 /* CAM Enable */
+#define  CAM_CTRL_MSEL		0x00000002 /* Mask Select */
+#define  CAM_CTRL_READ		0x00000004 /* Read */
+#define  CAM_CTRL_WRITE		0x00000008 /* Read */
+#define  CAM_CTRL_INDEX_MASK	0x003f0000 /* Index Mask */
+#define  CAM_CTRL_INDEX_SHIFT	16
+#define  CAM_CTRL_BUSY		0x80000000 /* CAM Busy */
+#define B44_ENET_CTRL	0x042CUL /* EMAC ENET Control */
+#define  ENET_CTRL_ENABLE	0x00000001 /* EMAC Enable */
+#define  ENET_CTRL_DISABLE	0x00000002 /* EMAC Disable */
+#define  ENET_CTRL_SRST		0x00000004 /* EMAC Soft Reset */
+#define  ENET_CTRL_EPSEL	0x00000008 /* External PHY Select */
+#define B44_TX_CTRL	0x0430UL /* EMAC TX Control */
+#define  TX_CTRL_DUPLEX		0x00000001 /* Full Duplex */
+#define  TX_CTRL_FMODE		0x00000002 /* Flow Mode */
+#define  TX_CTRL_SBENAB		0x00000004 /* Single Backoff Enable */
+#define  TX_CTRL_SMALL_SLOT	0x00000008 /* Small Slottime */
+#define B44_TX_WMARK	0x0434UL /* EMAC TX Watermark */
+#define B44_MIB_CTRL	0x0438UL /* EMAC MIB Control */
+#define  MIB_CTRL_CLR_ON_READ	0x00000001 /* Autoclear on Read */
+#define B44_TX_GOOD_O	0x0500UL /* MIB TX Good Octets */
+#define B44_TX_GOOD_P	0x0504UL /* MIB TX Good Packets */
+#define B44_TX_O	0x0508UL /* MIB TX Octets */
+#define B44_TX_P	0x050CUL /* MIB TX Packets */
+#define B44_TX_BCAST	0x0510UL /* MIB TX Broadcast Packets */
+#define B44_TX_MCAST	0x0514UL /* MIB TX Multicast Packets */
+#define B44_TX_64	0x0518UL /* MIB TX <= 64 byte Packets */
+#define B44_TX_65_127	0x051CUL /* MIB TX 65 to 127 byte Packets */
+#define B44_TX_128_255	0x0520UL /* MIB TX 128 to 255 byte Packets */
+#define B44_TX_256_511	0x0524UL /* MIB TX 256 to 511 byte Packets */
+#define B44_TX_512_1023	0x0528UL /* MIB TX 512 to 1023 byte Packets */
+#define B44_TX_1024_MAX	0x052CUL /* MIB TX 1024 to max byte Packets */
+#define B44_TX_JABBER	0x0530UL /* MIB TX Jabber Packets */
+#define B44_TX_OSIZE	0x0534UL /* MIB TX Oversize Packets */
+#define B44_TX_FRAG	0x0538UL /* MIB TX Fragment Packets */
+#define B44_TX_URUNS	0x053CUL /* MIB TX Underruns */
+#define B44_TX_TCOLS	0x0540UL /* MIB TX Total Collisions */
+#define B44_TX_SCOLS	0x0544UL /* MIB TX Single Collisions */
+#define B44_TX_MCOLS	0x0548UL /* MIB TX Multiple Collisions */
+#define B44_TX_ECOLS	0x054CUL /* MIB TX Excessive Collisions */
+#define B44_TX_LCOLS	0x0550UL /* MIB TX Late Collisions */
+#define B44_TX_DEFERED	0x0554UL /* MIB TX Defered Packets */
+#define B44_TX_CLOST	0x0558UL /* MIB TX Carrier Lost */
+#define B44_TX_PAUSE	0x055CUL /* MIB TX Pause Packets */
+#define B44_RX_GOOD_O	0x0580UL /* MIB RX Good Octets */
+#define B44_RX_GOOD_P	0x0584UL /* MIB RX Good Packets */
+#define B44_RX_O	0x0588UL /* MIB RX Octets */
+#define B44_RX_P	0x058CUL /* MIB RX Packets */
+#define B44_RX_BCAST	0x0590UL /* MIB RX Broadcast Packets */
+#define B44_RX_MCAST	0x0594UL /* MIB RX Multicast Packets */
+#define B44_RX_64	0x0598UL /* MIB RX <= 64 byte Packets */
+#define B44_RX_65_127	0x059CUL /* MIB RX 65 to 127 byte Packets */
+#define B44_RX_128_255	0x05A0UL /* MIB RX 128 to 255 byte Packets */
+#define B44_RX_256_511	0x05A4UL /* MIB RX 256 to 511 byte Packets */
+#define B44_RX_512_1023	0x05A8UL /* MIB RX 512 to 1023 byte Packets */
+#define B44_RX_1024_MAX	0x05ACUL /* MIB RX 1024 to max byte Packets */
+#define B44_RX_JABBER	0x05B0UL /* MIB RX Jabber Packets */
+#define B44_RX_OSIZE	0x05B4UL /* MIB RX Oversize Packets */
+#define B44_RX_FRAG	0x05B8UL /* MIB RX Fragment Packets */
+#define B44_RX_MISS	0x05BCUL /* MIB RX Missed Packets */
+#define B44_RX_CRCA	0x05C0UL /* MIB RX CRC Align Errors */
+#define B44_RX_USIZE	0x05C4UL /* MIB RX Undersize Packets */
+#define B44_RX_CRC	0x05C8UL /* MIB RX CRC Errors */
+#define B44_RX_ALIGN	0x05CCUL /* MIB RX Align Errors */
+#define B44_RX_SYM	0x05D0UL /* MIB RX Symbol Errors */
+#define B44_RX_PAUSE	0x05D4UL /* MIB RX Pause Packets */
+#define B44_RX_NPAUSE	0x05D8UL /* MIB RX Non-Pause Packets */
+#define B44_SBIPSFLAG	0x0F08UL /* SB Initiator Port OCP Slave Flag */
+#define  SBIPSFLAG_IMASK1	0x0000003f /* Which sbflags --> mips interrupt 1 */
+#define  SBIPSFLAG_ISHIFT1	0
+#define  SBIPSFLAG_IMASK2	0x00003f00 /* Which sbflags --> mips interrupt 2 */
+#define  SBIPSFLAG_ISHIFT2	8
+#define  SBIPSFLAG_IMASK3	0x003f0000 /* Which sbflags --> mips interrupt 3 */
+#define  SBIPSFLAG_ISHIFT3	16
+#define  SBIPSFLAG_IMASK4	0x3f000000 /* Which sbflags --> mips interrupt 4 */
+#define  SBIPSFLAG_ISHIFT4	24
+#define B44_SBTPSFLAG	0x0F18UL /* SB Target Port OCP Slave Flag */
+#define  SBTPS_NUM0_MASK	0x0000003f
+#define  SBTPS_F0EN0		0x00000040
+#define B44_SBADMATCH3	0x0F60UL /* SB Address Match 3 */
+#define B44_SBADMATCH2	0x0F68UL /* SB Address Match 2 */
+#define B44_SBADMATCH1	0x0F70UL /* SB Address Match 1 */
+#define B44_SBIMSTATE	0x0F90UL /* SB Initiator Agent State */
+#define  SBIMSTATE_PC		0x0000000f /* Pipe Count */
+#define  SBIMSTATE_AP_MASK	0x00000030 /* Arbitration Priority */
+#define  SBIMSTATE_AP_BOTH	0x00000000 /* Use both timeslices and token */
+#define  SBIMSTATE_AP_TS	0x00000010 /* Use timeslices only */
+#define  SBIMSTATE_AP_TK	0x00000020 /* Use token only */
+#define  SBIMSTATE_AP_RSV	0x00000030 /* Reserved */
+#define  SBIMSTATE_IBE		0x00020000 /* In Band Error */
+#define  SBIMSTATE_TO		0x00040000 /* Timeout */
+#define B44_SBINTVEC	0x0F94UL /* SB Interrupt Mask */
+#define  SBINTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+#define  SBINTVEC_ENET0		0x00000002 /* Enable interrupts for enet 0 */
+#define  SBINTVEC_ILINE20	0x00000004 /* Enable interrupts for iline20 */
+#define  SBINTVEC_CODEC		0x00000008 /* Enable interrupts for v90 codec */
+#define  SBINTVEC_USB		0x00000010 /* Enable interrupts for usb */
+#define  SBINTVEC_EXTIF		0x00000020 /* Enable interrupts for external i/f */
+#define  SBINTVEC_ENET1		0x00000040 /* Enable interrupts for enet 1 */
+#define B44_SBTMSLOW	0x0F98UL /* SB Target State Low */
+#define  SBTMSLOW_RESET		0x00000001 /* Reset */
+#define  SBTMSLOW_REJECT	0x00000002 /* Reject */
+#define  SBTMSLOW_CLOCK		0x00010000 /* Clock Enable */
+#define  SBTMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
+#define  SBTMSLOW_PE		0x40000000 /* Power Management Enable */
+#define  SBTMSLOW_BE		0x80000000 /* BIST Enable */
+#define B44_SBTMSHIGH	0x0F9CUL /* SB Target State High */
+#define  SBTMSHIGH_SERR		0x00000001 /* S-error */
+#define  SBTMSHIGH_INT		0x00000002 /* Interrupt */
+#define  SBTMSHIGH_BUSY		0x00000004 /* Busy */
+#define  SBTMSHIGH_GCR		0x20000000 /* Gated Clock Request */
+#define  SBTMSHIGH_BISTF	0x40000000 /* BIST Failed */
+#define  SBTMSHIGH_BISTD	0x80000000 /* BIST Done */
+#define B44_SBBWA0	0x0FA0UL /* SB Bandwidth Allocation Table 0 */
+#define  SBBWA0_TAB0_MASK	0x0000ffff /* Lookup Table 0 */
+#define  SBBWA0_TAB0_SHIFT	0
+#define  SBBWA0_TAB1_MASK	0xffff0000 /* Lookup Table 0 */
+#define  SBBWA0_TAB1_SHIFT	16
+#define B44_SBIMCFGLOW	0x0FA8UL /* SB Initiator Configuration Low */
+#define  SBIMCFGLOW_STO_MASK	0x00000003 /* Service Timeout */
+#define  SBIMCFGLOW_RTO_MASK	0x00000030 /* Request Timeout */
+#define  SBIMCFGLOW_RTO_SHIFT	4
+#define  SBIMCFGLOW_CID_MASK	0x00ff0000 /* Connection ID */
+#define  SBIMCFGLOW_CID_SHIFT	16
+#define B44_SBIMCFGHIGH	0x0FACUL /* SB Initiator Configuration High */
+#define  SBIMCFGHIGH_IEM_MASK	0x0000000c /* Inband Error Mode */
+#define  SBIMCFGHIGH_TEM_MASK	0x00000030 /* Timeout Error Mode */
+#define  SBIMCFGHIGH_TEM_SHIFT	4
+#define  SBIMCFGHIGH_BEM_MASK	0x000000c0 /* Bus Error Mode */
+#define  SBIMCFGHIGH_BEM_SHIFT	6
+#define B44_SBADMATCH0	0x0FB0UL /* SB Address Match 0 */
+#define  SBADMATCH0_TYPE_MASK	0x00000003 /* Address Type */
+#define  SBADMATCH0_AD64	0x00000004 /* Reserved */
+#define  SBADMATCH0_AI0_MASK	0x000000f8 /* Type0 Size */
+#define  SBADMATCH0_AI0_SHIFT	3
+#define  SBADMATCH0_AI1_MASK	0x000001f8 /* Type1 Size */
+#define  SBADMATCH0_AI1_SHIFT	3
+#define  SBADMATCH0_AI2_MASK	0x000001f8 /* Type2 Size */
+#define  SBADMATCH0_AI2_SHIFT	3
+#define  SBADMATCH0_ADEN	0x00000400 /* Enable */
+#define  SBADMATCH0_ADNEG	0x00000800 /* Negative Decode */
+#define  SBADMATCH0_BS0_MASK	0xffffff00 /* Type0 Base Address */
+#define  SBADMATCH0_BS0_SHIFT	8
+#define  SBADMATCH0_BS1_MASK	0xfffff000 /* Type1 Base Address */
+#define  SBADMATCH0_BS1_SHIFT	12
+#define  SBADMATCH0_BS2_MASK	0xffff0000 /* Type2 Base Address */
+#define  SBADMATCH0_BS2_SHIFT	16
+#define B44_SBTMCFGLOW	0x0FB8UL /* SB Target Configuration Low */
+#define  SBTMCFGLOW_CD_MASK	0x000000ff /* Clock Divide Mask */
+#define  SBTMCFGLOW_CO_MASK	0x0000f800 /* Clock Offset Mask */
+#define  SBTMCFGLOW_CO_SHIFT	11
+#define  SBTMCFGLOW_IF_MASK	0x00fc0000 /* Interrupt Flags Mask */
+#define  SBTMCFGLOW_IF_SHIFT	18
+#define  SBTMCFGLOW_IM_MASK	0x03000000 /* Interrupt Mode Mask */
+#define  SBTMCFGLOW_IM_SHIFT	24
+#define B44_SBTMCFGHIGH	0x0FBCUL /* SB Target Configuration High */
+#define  SBTMCFGHIGH_BM_MASK	0x00000003 /* Busy Mode */
+#define  SBTMCFGHIGH_RM_MASK	0x0000000C /* Retry Mode */
+#define  SBTMCFGHIGH_RM_SHIFT	2
+#define  SBTMCFGHIGH_SM_MASK	0x00000030 /* Stop Mode */
+#define  SBTMCFGHIGH_SM_SHIFT	4
+#define  SBTMCFGHIGH_EM_MASK	0x00000300 /* Error Mode */
+#define  SBTMCFGHIGH_EM_SHIFT	8
+#define  SBTMCFGHIGH_IM_MASK	0x00000c00 /* Interrupt Mode */
+#define  SBTMCFGHIGH_IM_SHIFT	10
+#define B44_SBBCFG	0x0FC0UL /* SB Broadcast Configuration */
+#define  SBBCFG_LAT_MASK	0x00000003 /* SB Latency */
+#define  SBBCFG_MAX0_MASK	0x000f0000 /* MAX Counter 0 */
+#define  SBBCFG_MAX0_SHIFT	16
+#define  SBBCFG_MAX1_MASK	0x00f00000 /* MAX Counter 1 */
+#define  SBBCFG_MAX1_SHIFT	20
+#define B44_SBBSTATE	0x0FC8UL /* SB Broadcast State */
+#define  SBBSTATE_SRD		0x00000001 /* ST Reg Disable */
+#define  SBBSTATE_HRD		0x00000002 /* Hold Reg Disable */
+#define B44_SBACTCNFG	0x0FD8UL /* SB Activate Configuration */
+#define B44_SBFLAGST	0x0FE8UL /* SB Current SBFLAGS */
+#define B44_SBIDLOW	0x0FF8UL /* SB Identification Low */
+#define  SBIDLOW_CS_MASK	0x00000003 /* Config Space Mask */
+#define  SBIDLOW_AR_MASK	0x00000038 /* Num Address Ranges Supported */
+#define  SBIDLOW_AR_SHIFT	3
+#define  SBIDLOW_SYNCH		0x00000040 /* Sync */
+#define  SBIDLOW_INIT		0x00000080 /* Initiator */
+#define  SBIDLOW_MINLAT_MASK	0x00000f00 /* Minimum Backplane Latency */
+#define  SBIDLOW_MINLAT_SHIFT	8
+#define  SBIDLOW_MAXLAT_MASK	0x0000f000 /* Maximum Backplane Latency */
+#define  SBIDLOW_MAXLAT_SHIFT	12
+#define  SBIDLOW_FIRST		0x00010000 /* This Initiator is First */
+#define  SBIDLOW_CW_MASK	0x000c0000 /* Cycle Counter Width */
+#define  SBIDLOW_CW_SHIFT	18
+#define  SBIDLOW_TP_MASK	0x00f00000 /* Target Ports */
+#define  SBIDLOW_TP_SHIFT	20
+#define  SBIDLOW_IP_MASK	0x0f000000 /* Initiator Ports */
+#define  SBIDLOW_IP_SHIFT	24
+#define B44_SBIDHIGH	0x0FFCUL /* SB Identification High */
+#define  SBIDHIGH_RC_MASK	0x0000000f /* Revision Code */
+#define  SBIDHIGH_CC_MASK	0x0000fff0 /* Core Code */
+#define  SBIDHIGH_CC_SHIFT	4
+#define  SBIDHIGH_VC_MASK	0xffff0000 /* Vendor Code */
+#define  SBIDHIGH_VC_SHIFT	16
+
+#define  CORE_CODE_ILINE20	0x801
+#define  CORE_CODE_SDRAM	0x803
+#define  CORE_CODE_PCI		0x804
+#define  CORE_CODE_MIPS		0x805
+#define  CORE_CODE_ENET		0x806
+#define  CORE_CODE_CODEC	0x807
+#define  CORE_CODE_USB		0x808
+#define  CORE_CODE_ILINE100	0x80a
+#define  CORE_CODE_EXTIF	0x811
+
+/* SSB PCI config space registers.  */
+#define	SSB_BAR0_WIN		0x80
+#define	SSB_BAR1_WIN		0x84
+#define	SSB_SPROM_CONTROL	0x88
+#define	SSB_BAR1_CONTROL	0x8c
+
+/* SSB core and hsot control registers.  */
+#define SSB_CONTROL		0x0000UL
+#define SSB_ARBCONTROL		0x0010UL
+#define SSB_ISTAT		0x0020UL
+#define SSB_IMASK		0x0024UL
+#define SSB_MBOX		0x0028UL
+#define SSB_BCAST_ADDR		0x0050UL
+#define SSB_BCAST_DATA		0x0054UL
+#define SSB_PCI_TRANS_0		0x0100UL
+#define SSB_PCI_TRANS_1		0x0104UL
+#define SSB_PCI_TRANS_2		0x0108UL
+#define SSB_SPROM		0x0800UL
+
+#define SSB_PCI_MEM		0x00000000
+#define SSB_PCI_IO		0x00000001
+#define SSB_PCI_CFG0		0x00000002
+#define SSB_PCI_CFG1		0x00000003
+#define SSB_PCI_PREF		0x00000004
+#define SSB_PCI_BURST		0x00000008
+#define SSB_PCI_MASK0		0xfc000000
+#define SSB_PCI_MASK1		0xfc000000
+#define SSB_PCI_MASK2		0xc0000000
+
+#define br32(REG)	readl(bp->regs + (REG))
+#define bw32(REG,VAL)	writel((VAL), bp->regs + (REG))
+
+/* 4400 PHY registers */
+#define B44_MII_AUXCTRL		24	/* Auxiliary Control */
+#define  MII_AUXCTRL_DUPLEX	0x0001  /* Full Duplex */
+#define  MII_AUXCTRL_SPEED	0x0002  /* 1=100Mbps, 0=10Mbps */
+#define  MII_AUXCTRL_FORCED	0x0004	/* Forced 10/100 */
+#define B44_MII_ALEDCTRL	26	/* Activity LED */
+#define  MII_ALEDCTRL_ALLMSK	0x7fff
+#define B44_MII_TLEDCTRL	27	/* Traffic Meter LED */
+#define  MII_TLEDCTRL_ENABLE	0x0040
+
+/* XXX Add this to mii.h */
+#ifndef ADVERTISE_PAUSE
+#define ADVERTISE_PAUSE_CAP		0x0400
+#endif
+#ifndef ADVERTISE_PAUSE_ASYM
+#define ADVERTISE_PAUSE_ASYM		0x0800
+#endif
+#ifndef LPA_PAUSE
+#define LPA_PAUSE_CAP			0x0400
+#endif
+#ifndef LPA_PAUSE_ASYM
+#define LPA_PAUSE_ASYM			0x0800
+#endif
+
+struct dma_desc {
+	u32	ctrl;
+	u32	addr;
+};
+
+/* There are only 12 bits in the DMA engine for descriptor offsetting
+ * so the table must be aligned on a boundary of this.
+ */
+#define DMA_TABLE_BYTES		4096
+
+#define DESC_CTRL_LEN	0x00001fff
+#define DESC_CTRL_CMASK	0x0ff00000 /* Core specific bits */
+#define DESC_CTRL_EOT	0x10000000 /* End of Table */
+#define DESC_CTRL_IOC	0x20000000 /* Interrupt On Completion */
+#define DESC_CTRL_EOF	0x40000000 /* End of Frame */
+#define DESC_CTRL_SOF	0x80000000 /* Start of Frame */
+
+#define RX_COPY_THRESHOLD  	256
+
+struct rx_header {
+	u16	len;
+	u16	flags;
+	u16	pad[12];
+};
+#define RX_HEADER_LEN	28
+
+#define RX_FLAG_OFIFO	0x00000001 /* FIFO Overflow */
+#define RX_FLAG_CRCERR	0x00000002 /* CRC Error */
+#define RX_FLAG_SERR	0x00000004 /* Receive Symbol Error */
+#define RX_FLAG_ODD	0x00000008 /* Frame has odd number of nibbles */
+#define RX_FLAG_LARGE	0x00000010 /* Frame is > RX MAX Length */
+#define RX_FLAG_MCAST	0x00000020 /* Dest is Multicast Address */
+#define RX_FLAG_BCAST	0x00000040 /* Dest is Broadcast Address */
+#define RX_FLAG_MISS	0x00000080 /* Received due to promisc mode */
+#define RX_FLAG_LAST	0x00000800 /* Last buffer in frame */
+#define RX_FLAG_ERRORS	(RX_FLAG_ODD | RX_FLAG_SERR | RX_FLAG_CRCERR | RX_FLAG_OFIFO)
+
+struct ring_info {
+	struct sk_buff		*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping);
+};
+
+#define B44_MCAST_TABLE_SIZE	32
+
+/* SW copy of device statistics, kept up to date by periodic timer
+ * which probes HW values.  Must have same relative layout as HW
+ * register above, because b44_stats_update depends upon this.
+ */
+struct b44_hw_stats {
+	u32 tx_good_octets, tx_good_pkts, tx_octets;
+	u32 tx_pkts, tx_broadcast_pkts, tx_multicast_pkts;
+	u32 tx_len_64, tx_len_65_to_127, tx_len_128_to_255;
+	u32 tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max;
+	u32 tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts;
+	u32 tx_underruns, tx_total_cols, tx_single_cols;
+	u32 tx_multiple_cols, tx_excessive_cols, tx_late_cols;
+	u32 tx_defered, tx_carrier_lost, tx_pause_pkts;
+	u32 __pad1[8];
+
+	u32 rx_good_octets, rx_good_pkts, rx_octets;
+	u32 rx_pkts, rx_broadcast_pkts, rx_multicast_pkts;
+	u32 rx_len_64, rx_len_65_to_127, rx_len_128_to_255;
+	u32 rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max;
+	u32 rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts;
+	u32 rx_missed_pkts, rx_crc_align_errs, rx_undersize;
+	u32 rx_crc_errs, rx_align_errs, rx_symbol_errs;
+	u32 rx_pause_pkts, rx_nonpause_pkts;
+};
+
+struct b44 {
+	spinlock_t		lock;
+
+	u32			imask, istat;
+
+	struct dma_desc		*rx_ring, *tx_ring;
+
+	u32			tx_prod, tx_cons;
+	u32			rx_prod, rx_cons;
+
+	struct ring_info	*rx_buffers;
+	struct ring_info	*tx_buffers;
+
+	u32			dma_offset;
+	u32			flags;
+#define B44_FLAG_INIT_COMPLETE	0x00000001
+#define B44_FLAG_BUGGY_TXPTR	0x00000002
+#define B44_FLAG_REORDER_BUG	0x00000004
+#define B44_FLAG_PAUSE_AUTO	0x00008000
+#define B44_FLAG_FULL_DUPLEX	0x00010000
+#define B44_FLAG_100_BASE_T	0x00020000
+#define B44_FLAG_TX_PAUSE	0x00040000
+#define B44_FLAG_RX_PAUSE	0x00080000
+#define B44_FLAG_FORCE_LINK	0x00100000
+#define B44_FLAG_ADV_10HALF	0x01000000
+#define B44_FLAG_ADV_10FULL	0x02000000
+#define B44_FLAG_ADV_100HALF	0x04000000
+#define B44_FLAG_ADV_100FULL	0x08000000
+#define B44_FLAG_INTERNAL_PHY	0x10000000
+
+	u32			rx_offset;
+
+	u32			msg_enable;
+
+	struct timer_list	timer;
+
+	struct net_device_stats	stats;
+	struct b44_hw_stats	hw_stats;
+
+	unsigned long		regs;
+	struct pci_dev		*pdev;
+	struct net_device	*dev;
+
+	dma_addr_t		rx_ring_dma, tx_ring_dma;
+
+	u32			rx_pending;
+	u32			tx_pending;
+	u32			pci_cfg_state[64 / sizeof(u32)];
+	u8			phy_addr;
+	u8			mdc_port;
+	u8			core_unit;
+};
+
+#endif /* _B44_H */
diff -urN linux-2.4.22-pre9/drivers/net/bonding/bond_main.c linux-2.4.22-pre10/drivers/net/bonding/bond_main.c
--- linux-2.4.22-pre9/drivers/net/bonding/bond_main.c	2003-08-01 09:15:58.000000000 -0700
+++ linux-2.4.22-pre10/drivers/net/bonding/bond_main.c	2003-08-01 09:16:08.000000000 -0700
@@ -460,7 +460,7 @@
 
 static int arp_interval = BOND_LINK_ARP_INTERV;
 static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, };
-static unsigned long arp_target[MAX_ARP_IP_TARGETS] = { 0, } ;
+static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ;
 static int arp_ip_count = 0;
 static u32 my_ip = 0;
 char *arp_target_hw_addr = NULL;
@@ -524,7 +524,7 @@
 MODULE_PARM(miimon, "i");
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
 MODULE_PARM(use_carrier, "i");
-MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 09 for off, 1 for on (default)");
+MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)");
 MODULE_PARM(mode, "s");
 MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
 MODULE_PARM(arp_interval, "i");
@@ -1594,11 +1594,14 @@
 #endif
 			bond_set_slave_inactive_flags(new_slave);
 		}
-		read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
-		ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list);
-		ifa = *ifap;
-		my_ip = ifa->ifa_address;
-		read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+		if (((struct in_device *)slave_dev->ip_ptr) != NULL) {
+			read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+			ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list);
+			ifa = *ifap;
+			if (ifa != NULL)
+				my_ip = ifa->ifa_address;
+			read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+		}
 
 		/* if there is a primary slave, remember it */
 		if (primary != NULL) {
@@ -3930,7 +3933,7 @@
                         arp_interval = 0;
 		} else { 
 			u32 ip = in_aton(arp_ip_target[arp_ip_count]); 
-			*(u32 *)(arp_ip_target[arp_ip_count]) = ip;
+			arp_target[arp_ip_count] = ip;
 		}
         }
 
diff -urN linux-2.4.22-pre9/drivers/net/wireless/airo.c linux-2.4.22-pre10/drivers/net/wireless/airo.c
--- linux-2.4.22-pre9/drivers/net/wireless/airo.c	2003-08-01 09:15:58.000000000 -0700
+++ linux-2.4.22-pre10/drivers/net/wireless/airo.c	2003-08-01 09:16:08.000000000 -0700
@@ -97,12 +97,12 @@
    infront of the label, that statistic will not be included in the list
    of statistics in the /proc filesystem */
 
-#define IGNLABEL 0&(int)
+#define IGNLABEL(comment) 0
 static char *statsLabels[] = {
 	"RxOverrun",
-	IGNLABEL "RxPlcpCrcErr",
-	IGNLABEL "RxPlcpFormatErr",
-	IGNLABEL "RxPlcpLengthErr",
+	IGNLABEL("RxPlcpCrcErr"),
+	IGNLABEL("RxPlcpFormatErr"),
+	IGNLABEL("RxPlcpLengthErr"),
 	"RxMacCrcErr",
 	"RxMacCrcOk",
 	"RxWepErr",
@@ -146,15 +146,15 @@
 	"HostRxBc",
 	"HostRxUc",
 	"HostRxDiscard",
-	IGNLABEL "HmacTxMc",
-	IGNLABEL "HmacTxBc",
-	IGNLABEL "HmacTxUc",
-	IGNLABEL "HmacTxFail",
-	IGNLABEL "HmacRxMc",
-	IGNLABEL "HmacRxBc",
-	IGNLABEL "HmacRxUc",
-	IGNLABEL "HmacRxDiscard",
-	IGNLABEL "HmacRxAccepted",
+	IGNLABEL("HmacTxMc"),
+	IGNLABEL("HmacTxBc"),
+	IGNLABEL("HmacTxUc"),
+	IGNLABEL("HmacTxFail"),
+	IGNLABEL("HmacRxMc"),
+	IGNLABEL("HmacRxBc"),
+	IGNLABEL("HmacRxUc"),
+	IGNLABEL("HmacRxDiscard"),
+	IGNLABEL("HmacRxAccepted"),
 	"SsidMismatch",
 	"ApMismatch",
 	"RatesMismatch",
@@ -162,26 +162,26 @@
 	"AuthTimeout",
 	"AssocReject",
 	"AssocTimeout",
-	IGNLABEL "ReasonOutsideTable",
-	IGNLABEL "ReasonStatus1",
-	IGNLABEL "ReasonStatus2",
-	IGNLABEL "ReasonStatus3",
-	IGNLABEL "ReasonStatus4",
-	IGNLABEL "ReasonStatus5",
-	IGNLABEL "ReasonStatus6",
-	IGNLABEL "ReasonStatus7",
-	IGNLABEL "ReasonStatus8",
-	IGNLABEL "ReasonStatus9",
-	IGNLABEL "ReasonStatus10",
-	IGNLABEL "ReasonStatus11",
-	IGNLABEL "ReasonStatus12",
-	IGNLABEL "ReasonStatus13",
-	IGNLABEL "ReasonStatus14",
-	IGNLABEL "ReasonStatus15",
-	IGNLABEL "ReasonStatus16",
-	IGNLABEL "ReasonStatus17",
-	IGNLABEL "ReasonStatus18",
-	IGNLABEL "ReasonStatus19",
+	IGNLABEL("ReasonOutsideTable"),
+	IGNLABEL("ReasonStatus1"),
+	IGNLABEL("ReasonStatus2"),
+	IGNLABEL("ReasonStatus3"),
+	IGNLABEL("ReasonStatus4"),
+	IGNLABEL("ReasonStatus5"),
+	IGNLABEL("ReasonStatus6"),
+	IGNLABEL("ReasonStatus7"),
+	IGNLABEL("ReasonStatus8"),
+	IGNLABEL("ReasonStatus9"),
+	IGNLABEL("ReasonStatus10"),
+	IGNLABEL("ReasonStatus11"),
+	IGNLABEL("ReasonStatus12"),
+	IGNLABEL("ReasonStatus13"),
+	IGNLABEL("ReasonStatus14"),
+	IGNLABEL("ReasonStatus15"),
+	IGNLABEL("ReasonStatus16"),
+	IGNLABEL("ReasonStatus17"),
+	IGNLABEL("ReasonStatus18"),
+	IGNLABEL("ReasonStatus19"),
 	"RxMan",
 	"TxMan",
 	"RxRefresh",
@@ -654,9 +654,38 @@
 	u16 currentXmitRate;
 	u16 apDevExtensions;
 	u16 normalizedSignalStrength;
-	u16 _reserved1;
+	u16 shortPreamble;
 	u8 apIP[4];
-	u16 _reserved[7];
+	u8 noisePercent; /* Noise percent in last second */
+	u8 noisedBm; /* Noise dBm in last second */
+	u8 noiseAvePercent; /* Noise percent in last minute */
+	u8 noiseAvedBm; /* Noise dBm in last minute */
+	u8 noiseMaxPercent; /* Highest noise percent in last minute */
+	u8 noiseMaxdBm; /* Highest noise dbm in last minute */
+	u16 load;
+	u8 carrier[4];
+	u16 assocStatus;
+#define STAT_NOPACKETS 0
+#define STAT_NOCARRIERSET 10
+#define STAT_GOTCARRIERSET 11
+#define STAT_WRONGSSID 20
+#define STAT_BADCHANNEL 25
+#define STAT_BADBITRATES 30
+#define STAT_BADPRIVACY 35
+#define STAT_APFOUND 40
+#define STAT_APREJECTED 50
+#define STAT_AUTHENTICATING 60
+#define STAT_DEAUTHENTICATED 61
+#define STAT_AUTHTIMEOUT 62
+#define STAT_ASSOCIATING 70
+#define STAT_DEASSOCIATED 71
+#define STAT_ASSOCTIMEOUT 72
+#define STAT_NOTAIROAP 73
+#define STAT_ASSOCIATED 80
+#define STAT_LEAPING 90
+#define STAT_LEAPFAILED 91
+#define STAT_LEAPTIMEDOUT 92
+#define STAT_LEAPCOMPLETE 93
 } StatusRid;
 
 typedef struct {
@@ -894,7 +923,7 @@
 
 #ifdef WIRELESS_EXT
 // Frequency list (map channels to frequencies)
-const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
 				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
 
 // A few details needed for WEP (Wireless Equivalent Privacy)
@@ -929,8 +958,8 @@
 static void OUT4500( struct airo_info *, u16 register, u16 value );
 static unsigned short IN4500( struct airo_info *, u16 register );
 static u16 setup_card(struct airo_info*, u8 *mac);
-static int enable_MAC( struct airo_info *ai, Resp *rsp );
-static void disable_MAC(struct airo_info *ai);
+static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock );
+static void disable_MAC(struct airo_info *ai, int lock);
 static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
@@ -944,11 +973,11 @@
 static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
 		     int whichbap);
 static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
-static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len);
+static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
 static int PC4500_writerid(struct airo_info*, u16 rid, const void
-			   *pBuf, int len);
+			   *pBuf, int len, int lock);
 static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
-			int len );
+			int len, int dummy );
 static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
 static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
 static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
@@ -976,7 +1005,7 @@
 	int open;
 	struct net_device             *dev;
 	/* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
-	   use the high bit to mark wether it is in use. */
+	   use the high bit to mark whether it is in use. */
 #define MAX_FIDS 6
 	int                           fids[MAX_FIDS];
 	int registered;
@@ -992,19 +1021,21 @@
 #define FLAG_PROMISC   IFF_PROMISC	/* 0x100 - include/linux/if.h */
 #define FLAG_RADIO_OFF 0x02		/* User disabling of MAC */
 #define FLAG_RADIO_DOWN 0x08		/* ifup/ifdown disabling of MAC */
-#define FLAG_LOCKED    2		/* 0x04 - use as a bit offset */
 #define FLAG_FLASHING  0x10
 #define FLAG_ADHOC        0x01 /* Needed by MIC */
 #define FLAG_MIC_CAPABLE  0x20
 #define FLAG_UPDATE_MULTI 0x40
 #define FLAG_UPDATE_UNI   0x80
 #define FLAG_802_11    0x200
+#define FLAG_PENDING_XMIT   0x400
+#define FLAG_PENDING_XMIT11 0x800
 	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
 	unsigned short *flash;
 	tdsRssiEntry *rssi;
 	struct semaphore sem;
 	struct task_struct *task;
+	struct tq_struct stats_task;
 	struct tq_struct promisc_task;
 	struct {
 		struct sk_buff *skb;
@@ -1062,7 +1093,7 @@
 			ai->task = NULL;
 		}
 	rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
-			    list, sizeof(*list));
+			    list, sizeof(*list), 1);
 
 	list->len = le16_to_cpu(list->len);
 	list->index = le16_to_cpu(list->index);
@@ -1077,7 +1108,7 @@
 
 static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) {
 	int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
-				wkr, sizeof(*wkr));
+				wkr, sizeof(*wkr), 1);
 
 	wkr->len = le16_to_cpu(wkr->len);
 	wkr->kindex = le16_to_cpu(wkr->kindex);
@@ -1086,17 +1117,17 @@
 }
 /* In the writeXXXRid routines we copy the rids so that we don't screwup
  * the originals when we endian them... */
-static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm) {
+static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) {
 	int rc;
 	WepKeyRid wkr = *pwkr;
 
 	wkr.len = cpu_to_le16(wkr.len);
 	wkr.kindex = cpu_to_le16(wkr.kindex);
 	wkr.klen = cpu_to_le16(wkr.klen);
-	rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
+	rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
 	if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc);
 	if (perm) {
-		rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
+		rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
 		if (rc!=SUCCESS) {
 			printk(KERN_ERR "airo:  WEP_PERM set %x\n", rc);
 		}
@@ -1106,7 +1137,7 @@
 
 static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
 	int i;
-	int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr));
+	int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
 
 	ssidr->len = le16_to_cpu(ssidr->len);
 	for(i = 0; i < 3; i++) {
@@ -1123,10 +1154,10 @@
 	for(i = 0; i < 3; i++) {
 		ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
 	}
-	rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr));
+	rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), 1);
 	return rc;
 }
-static int readConfigRid(struct airo_info*ai) {
+static int readConfigRid(struct airo_info*ai, int lock) {
 	int rc;
 	u16 *s;
 	ConfigRid cfg;
@@ -1134,7 +1165,7 @@
 	if (ai->config.len)
 		return SUCCESS;
 
-	rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg));
+	rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
 	if (rc != SUCCESS)
 		return rc;
 
@@ -1163,7 +1194,7 @@
 		}
 	}
 }
-static int writeConfigRid(struct airo_info*ai) {
+static int writeConfigRid(struct airo_info*ai, int lock) {
 	u16 *s;
 	ConfigRid cfgr;
 
@@ -1190,33 +1221,34 @@
 	for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++)
 		*s = cpu_to_le16(*s);
 
-	return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));
+	return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
 }
 static int readStatusRid(struct airo_info*ai, StatusRid *statr) {
-	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr));
+	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), 1);
 	u16 *s;
 
 	statr->len = le16_to_cpu(statr->len);
 	for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
 
-	for(s = &statr->beaconPeriod; s <= &statr->_reserved[9]; s++)
+	for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++)
 		*s = le16_to_cpu(*s);
-
+	statr->load = le16_to_cpu(statr->load);
+	statr->assocStatus = le16_to_cpu(statr->assocStatus);
 	return rc;
 }
 static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
-	int rc =  PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr));
+	int rc =  PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
 	aplr->len = le16_to_cpu(aplr->len);
 	return rc;
 }
 static int writeAPListRid(struct airo_info*ai, APListRid *aplr) {
 	int rc;
 	aplr->len = cpu_to_le16(aplr->len);
-	rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr));
+	rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
 	return rc;
 }
 static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) {
-	int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr));
+	int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), 1);
 	u16 *s;
 
 	capr->len = le16_to_cpu(capr->len);
@@ -1227,8 +1259,8 @@
 		*s = le16_to_cpu(*s);
 	return rc;
 }
-static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid) {
-	int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr));
+static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
+	int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
 	u32 *i;
 
 	sr->len = le16_to_cpu(sr->len);
@@ -1248,8 +1280,8 @@
 	 * is open (to pipeline changes and speed-up card setup). If
 	 * those changes are not yet commited, do it now - Jean II */
 	if(info->need_commit) {
-		disable_MAC(info);
-		writeConfigRid(info);
+		disable_MAC(info, 1);
+		writeConfigRid(info, 1);
 	}
 
 	if (info->wifidev != dev) {
@@ -1257,7 +1289,7 @@
 		info->flags &= ~FLAG_RADIO_DOWN;
 		enable_interrupts(info);
 	}
-	enable_MAC(info, &rsp);
+	enable_MAC(info, &rsp, 1);
 
 	netif_start_queue(dev);
 	return 0;
@@ -1321,6 +1353,7 @@
 	u32 *fids = priv->fids;
 
 	if (down_trylock(&priv->sem) != 0) {
+		priv->flags |= FLAG_PENDING_XMIT;
 		netif_stop_queue(dev);
 		priv->xmit.task.routine = (void (*)(void *))airo_do_xmit;
 		priv->xmit.task.data = (void *)dev;
@@ -1329,6 +1362,7 @@
 	}
 	status = transmit_802_3_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
+	priv->flags &= ~FLAG_PENDING_XMIT;
 
 	i = 0;
 	if ( status == SUCCESS ) {
@@ -1340,14 +1374,12 @@
 	}
 	if (i < MAX_FIDS / 2)
 		netif_wake_queue(dev);
-	else
-		netif_stop_queue(dev);
 	dev_kfree_skb(skb);
 }
 
 static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
-	int i;
+	int i, j;
 	struct airo_info *priv = dev->priv;
 	u32 *fids = priv->fids;
 
@@ -1358,19 +1390,23 @@
 
 	/* Find a vacant FID */
 	for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
+	for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ );
 
-	if ( i == MAX_FIDS / 2 ) {
-		priv->stats.tx_fifo_errors++;
-		dev_kfree_skb(skb);
-	} else {
-		/* check min length*/
-		len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	        /* Mark fid as used & save length for later */
-		fids[i] |= (len << 16);
-		priv->xmit.skb = skb;
-		priv->xmit.fid = i;
-		airo_do_xmit(dev);
+	if ( j >= MAX_FIDS / 2 ) {
+		netif_stop_queue(dev);
+
+		if (i == MAX_FIDS / 2) {
+			priv->stats.tx_fifo_errors++;
+			return 1;
+		}
 	}
+	/* check min length*/
+	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+        /* Mark fid as used & save length for later */
+	fids[i] |= (len << 16);
+	priv->xmit.skb = skb;
+	priv->xmit.fid = i;
+	airo_do_xmit(dev);
 	return 0;
 }
 
@@ -1383,6 +1419,7 @@
 	u32 *fids = priv->fids;
 
 	if (down_trylock(&priv->sem) != 0) {
+		priv->flags |= FLAG_PENDING_XMIT11;
 		netif_stop_queue(dev);
 		priv->xmit11.task.routine = (void (*)(void *))airo_do_xmit11;
 		priv->xmit11.task.data = (void *)dev;
@@ -1391,6 +1428,7 @@
 	}
 	status = transmit_802_11_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
+	priv->flags &= ~FLAG_PENDING_XMIT11;
 
 	i = MAX_FIDS / 2;
 	if ( status == SUCCESS ) {
@@ -1402,14 +1440,12 @@
 	}
 	if (i < MAX_FIDS)
 		netif_wake_queue(dev);
-	else
-		netif_stop_queue(dev);
 	dev_kfree_skb(skb);
 }
 
 static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
-	int i;
+	int i, j;
 	struct airo_info *priv = dev->priv;
 	u32 *fids = priv->fids;
 
@@ -1420,45 +1456,61 @@
 
 	/* Find a vacant FID */
 	for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
+	for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ );
 
-	if ( i == MAX_FIDS ) {
-		priv->stats.tx_fifo_errors++;
-		dev_kfree_skb(skb);
-	} else {
-		/* check min length*/
-		len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	        /* Mark fid as used & save length for later */
-		fids[i] |= (len << 16);
-		priv->xmit11.skb = skb;
-		priv->xmit11.fid = i;
-		airo_do_xmit11(dev);
+	if ( j >= MAX_FIDS ) {
+		netif_stop_queue(dev);
+
+		if (i == MAX_FIDS) {
+			priv->stats.tx_fifo_errors++;
+			return 1;
+		}
 	}
+	/* check min length*/
+	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+        /* Mark fid as used & save length for later */
+	fids[i] |= (len << 16);
+	priv->xmit11.skb = skb;
+	priv->xmit11.fid = i;
+	airo_do_xmit11(dev);
 	return 0;
 }
 
-struct net_device_stats *airo_get_stats(struct net_device *dev)
-{
-	struct airo_info *local =  dev->priv;
+static void airo_read_stats(struct airo_info *ai) {
 	StatsRid stats_rid;
 	u32 *vals = stats_rid.vals;
 
-	/* Get stats out of the card */
-	readStatsRid(local, &stats_rid, RID_STATS);
+	if (down_trylock(&ai->sem) == 0) {
+		readStatsRid(ai, &stats_rid, RID_STATS, 0);
+		up(&ai->sem);
 
-	local->stats.rx_packets = vals[43] + vals[44] + vals[45];
-	local->stats.tx_packets = vals[39] + vals[40] + vals[41];
-	local->stats.rx_bytes = vals[92];
-	local->stats.tx_bytes = vals[91];
-	local->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
-	local->stats.tx_errors = vals[42] + local->stats.tx_fifo_errors;
-	local->stats.multicast = vals[43];
-	local->stats.collisions = vals[89];
-
-	/* detailed rx_errors: */
-	local->stats.rx_length_errors = vals[3];
-	local->stats.rx_crc_errors = vals[4];
-	local->stats.rx_frame_errors = vals[2];
-	local->stats.rx_fifo_errors = vals[0];
+		ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
+		ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
+		ai->stats.rx_bytes = vals[92];
+		ai->stats.tx_bytes = vals[91];
+		ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
+		ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
+		ai->stats.multicast = vals[43];
+		ai->stats.collisions = vals[89];
+
+		/* detailed rx_errors: */
+		ai->stats.rx_length_errors = vals[3];
+		ai->stats.rx_crc_errors = vals[4];
+		ai->stats.rx_frame_errors = vals[2];
+		ai->stats.rx_fifo_errors = vals[0];
+	} else {
+		ai->stats_task.routine = (void (*)(void *))airo_read_stats;
+		ai->stats_task.data = (void *)ai;
+		schedule_task(&ai->stats_task);
+	}
+}
+
+struct net_device_stats *airo_get_stats(struct net_device *dev)
+{
+	struct airo_info *local =  dev->priv;
+
+	/* Get stats out of the card if available */
+	airo_read_stats(local);
 
 	return &local->stats;
 }
@@ -1513,9 +1565,9 @@
 
 	memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
 	ai->need_commit = 1;
-	disable_MAC(ai);
-	writeConfigRid (ai);
-	enable_MAC(ai, &rsp);
+	disable_MAC(ai, 1);
+	writeConfigRid (ai, 1);
+	enable_MAC(ai, &rsp, 1);
 	memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
 	if (ai->wifidev)
 		memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1544,7 +1596,7 @@
 		 * stack (i.e. the network stack won't try to broadcast
 		 * anything on the interface and routes are gone. Jean II */
 		ai->flags |= FLAG_RADIO_DOWN;
-		disable_MAC(ai);
+		disable_MAC(ai, 1);
 #endif
 		disable_interrupts( ai );
 	}
@@ -1557,6 +1609,8 @@
 {
 	struct airo_info *ai = dev->priv;
 	flush_scheduled_tasks();
+	disable_interrupts(ai);
+	free_irq( dev->irq, dev );
 	if (ai->flash)
 		kfree(ai->flash);
 	if (ai->rssi)
@@ -1571,8 +1625,6 @@
 		}
 		ai->registered = 0;
 	}
-	disable_interrupts(ai);
-	free_irq( dev->irq, dev );
 	if (auto_wep) del_timer_sync(&ai->timer);
 	if (freeres) {
 		/* PCMCIA frees this stuff, so only for PCI and ISA */
@@ -1768,6 +1820,9 @@
 	int i;
 	struct airo_info *ai = dev->priv;
 
+
+	if (down_interruptible(&ai->sem))
+		return -1;
 	waitbusy (ai);
 	OUT4500(ai,COMMAND,CMD_SOFTRESET);
 	set_current_state (TASK_UNINTERRUPTIBLE);
@@ -1777,6 +1832,7 @@
 	schedule_timeout (HZ/5);
 	if ( setup_card(ai, dev->dev_addr ) != SUCCESS ) {
 		printk( KERN_ERR "airo: MAC could not be enabled\n" );
+		up(&ai->sem);
 		return -1;
 	} else {
 		printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
@@ -1794,6 +1850,7 @@
 	}
 	enable_interrupts( ai );
 	netif_wake_queue(dev);
+	up(&ai->sem);
 	return 0;
 }
 
@@ -1806,9 +1863,7 @@
 	StatusRid status_rid;
 
 	if (down_trylock(&ai->sem) == 0) {
-		__set_bit(FLAG_LOCKED, &ai->flags);
-		PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid));
-		clear_bit(FLAG_LOCKED, &ai->flags);
+		PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
 		up(&ai->sem);
 		wrqu.data.length = 0;
 		wrqu.data.flags = 0;
@@ -1829,9 +1884,7 @@
 	MICRid mic_rid;
 
 	if (down_trylock(&ai->sem) == 0) {
-		__set_bit(FLAG_LOCKED, &ai->flags);
-		PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid));
-		clear_bit(FLAG_LOCKED, &ai->flags);
+		PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
 		up(&ai->sem);
 #ifdef MICSUPPORT
 		micinit (ai, &mic_rid);
@@ -1869,7 +1922,8 @@
 
 		if ( status & EV_MIC ) {
 			OUT4500( apriv, EVACK, EV_MIC );
-			airo_read_mic( apriv );
+			if (apriv->flags & FLAG_MIC_CAPABLE)
+				airo_read_mic( apriv );
 		}
 		if ( status & EV_LINK ) {
 #if WIRELESS_EXT > 13
@@ -2060,6 +2114,28 @@
 				}
 			}
 			if (len) {
+#if WIRELESS_EXT > 15
+#ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
+				if (apriv->spy_data.spy_number > 0) {
+					char *sa;
+					struct iw_quality wstats;
+					/* Prepare spy data : addr + qual */
+					sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6);
+					if (!(apriv->flags & FLAG_802_11)) {
+						bap_setup (apriv, fid, 8, BAP0);
+						bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
+					}
+					wstats.qual = hdr.rssi[0];
+					if (apriv->rssi)
+						wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
+					else
+						wstats.level = (hdr.rssi[1] + 321) / 2;
+					wstats.updated = 3;	
+					/* Update spy records */
+					wireless_spy_update(dev, sa, &wstats);
+				}
+#endif /* IW_WIRELESS_SPY */
+#else /* WIRELESS_EXT > 15 */
 #ifdef WIRELESS_SPY
 				if (apriv->spy_number > 0) {
 					int i;
@@ -2085,6 +2161,7 @@
 						}
 				}
 #endif /* WIRELESS_SPY  */
+#endif /* WIRELESS_EXT > 15 */
 				OUT4500( apriv, EVACK, EV_RX);
 
 				if (apriv->flags & FLAG_802_11) {
@@ -2116,17 +2193,23 @@
 				if ( ( apriv->fids[i] & 0xffff ) == fid ) {
 					len = apriv->fids[i] >> 16;
 					index = i;
-					/* Set up to be used again */
-					apriv->fids[i] &= 0xffff;
 				}
 			}
 			if (index != -1) {
-				netif_wake_queue(dev);
 				if (status & EV_TXEXC)
 					get_tx_error(apriv, index);
-			}
-			OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
-			if (index==-1) {
+				OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
+				/* Set up to be used again */
+				apriv->fids[index] &= 0xffff;
+				if (index < MAX_FIDS / 2) {
+					if (!(apriv->flags & FLAG_PENDING_XMIT))
+						netif_wake_queue(dev);
+				} else {
+					if (!(apriv->flags & FLAG_PENDING_XMIT11))
+						netif_wake_queue(apriv->wifidev);
+				}
+			} else {
+				OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
 				printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
 			}
 		}
@@ -2172,7 +2255,7 @@
 	return rc;
 }
 
-static int enable_MAC( struct airo_info *ai, Resp *rsp ) {
+static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
 	int rc;
         Cmd cmd;
 
@@ -2185,7 +2268,7 @@
 	if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS;
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_ENABLE;
-	if (test_bit(FLAG_LOCKED, &ai->flags) != 0)
+	if (!lock)
 		return issuecommand(ai, &cmd, rsp);
 
 	if (down_interruptible(&ai->sem))
@@ -2195,13 +2278,13 @@
 	return rc;
 }
 
-static void disable_MAC( struct airo_info *ai ) {
+static void disable_MAC( struct airo_info *ai, int lock ) {
         Cmd cmd;
 	Resp rsp;
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_DISABLE; // disable in case already enabled
-	if (test_bit(FLAG_LOCKED, &ai->flags) != 0) {
+	if (!lock) {
 		issuecommand(ai, &cmd, &rsp);
 		return;
 	}
@@ -2219,7 +2302,7 @@
 	/* Enable the interrupts */
 	OUT4500( ai, EVINTEN, STATUS_INTS );
 	/* Note there is a race condition between the last two lines that
-	   I dont know how to get rid of right now... */
+	   I don't know how to get rid of right now... */
 }
 
 static void disable_interrupts( struct airo_info *ai ) {
@@ -2279,13 +2362,13 @@
 		CapabilityRid cap_rid;
 
 		// general configuration (read/modify/write)
-		status = readConfigRid(ai);
+		status = readConfigRid(ai, 1);
 		if ( status != SUCCESS ) return ERROR;
 
 		status = readCapabilityRid(ai, &cap_rid);
 		if ( status != SUCCESS ) return ERROR;
 
-		status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid));
+		status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),1);
 		if ( status == SUCCESS ) {
 			if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
 				memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
@@ -2349,14 +2432,14 @@
 		}
 	}
 
-	status = writeConfigRid(ai);
+	status = writeConfigRid(ai, 1);
 	if ( status != SUCCESS ) return ERROR;
 
 	/* Set up the SSID list */
 	status = writeSsidRid(ai, &mySsid);
 	if ( status != SUCCESS ) return ERROR;
 
-	status = enable_MAC(ai, &rsp);
+	status = enable_MAC(ai, &rsp, 1);
 	if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
 		printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
 		return ERROR;
@@ -2500,7 +2583,7 @@
 	u16 next;
 	int words;
 	int i;
-	long flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&ai->aux_lock, flags);
 	page = IN4500(ai, SWS0+whichbap);
@@ -2571,13 +2654,12 @@
 
 /*  Note, that we are using BAP1 which is also used by transmit, so
  *  we must get a lock. */
-static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
+static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
 {
-	u16 status, dolock = 0;
+	u16 status;
         int rc = SUCCESS;
 
-	if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
-		dolock = 1;
+	if (lock) {
 		if (down_interruptible(&ai->sem))
 			return ERROR;
 	}
@@ -2605,7 +2687,7 @@
 	// read remainder of the rid
 	rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
 done:
-	if (dolock)
+	if (lock)
 		up(&ai->sem);
 	return rc;
 }
@@ -2613,13 +2695,14 @@
 /*  Note, that we are using BAP1 which is also used by transmit, so
  *  make sure this isnt called when a transmit is happening */
 static int PC4500_writerid(struct airo_info *ai, u16 rid,
-			   const void *pBuf, int len)
+			   const void *pBuf, int len, int lock)
 {
-	u16 status, dolock = 0;
+	u16 status;
 	int rc = SUCCESS;
 
-	if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
-		dolock = 1;
+	*(u16*)pBuf = cpu_to_le16((u16)len);
+
+	if (lock) {
 		if (down_interruptible(&ai->sem))
 			return ERROR;
 	}
@@ -2637,7 +2720,7 @@
 	// ---now commit the rid data
 	rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
  done:
-	if (dolock)
+	if (lock)
 		up(&ai->sem);
         return rc;
 }
@@ -2646,6 +2729,7 @@
    one for now. */
 static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
 {
+	unsigned int loop = 3000;
 	Cmd cmd;
 	Resp rsp;
 	u16 txFid;
@@ -2656,17 +2740,22 @@
 	if (down_interruptible(&ai->sem))
 		return ERROR;
 	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
-		txFid = 0;
+		txFid = ERROR;
 		goto done;
 	}
 	if ( (rsp.status & 0xFF00) != 0) {
-		txFid = 0;
+		txFid = ERROR;
 		goto done;
 	}
 	/* wait for the allocate event/indication
 	 * It makes me kind of nervous that this can just sit here and spin,
 	 * but in practice it only loops like four times. */
-	while ( (IN4500(ai, EVSTAT) & EV_ALLOC) == 0) ;
+	while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
+	if (!loop) {
+		txFid = ERROR;
+		goto done;
+	}
+
 	// get the allocated fid and acknowledge
 	txFid = IN4500(ai, TXALLOCFID);
 	OUT4500(ai, EVACK, EV_ALLOC);
@@ -2707,7 +2796,7 @@
 
 	len >>= 16;
 
-	if (len < ETH_ALEN * 2) {
+	if (len <= ETH_ALEN * 2) {
 		printk( KERN_WARNING "Short packet %d\n", len );
 		return ERROR;
 	}
@@ -3158,7 +3247,7 @@
 		return -ENOMEM;
 	}
 
-	readStatsRid(apriv, &stats, rid);
+	readStatsRid(apriv, &stats, rid, 1);
 
         j = 0;
 	for(i=0; statsLabels[i]!=(char *)-1 &&
@@ -3193,18 +3282,21 @@
 	return value;
 }
 
+static int airo_config_commit(struct net_device *dev,
+			      struct iw_request_info *info, void *zwrq,
+			      char *extra);
+
 static void proc_config_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = file->private_data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = dev->priv;
-	Resp rsp;
 	char *line;
-	int need_reset = 0;
 
 	if ( !data->writelen ) return;
 
-	readConfigRid(ai);
+	readConfigRid(ai, 1);
+	ai->need_commit = 1;
 
 	line = data->wbuffer;
 	while( line[0] ) {
@@ -3212,19 +3304,22 @@
 		if ( !strncmp( line, "Mode: ", 6 ) ) {
 			line += 6;
 			if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
-					need_reset = 1;
+					ai->need_commit = 2;
 			ai->config.rmode &= 0xfe00;
 			ai->flags &= ~FLAG_802_11;
 			ai->config.opmode &= 0xFF00;
+			ai->config.scanMode = SCANMODE_ACTIVE;
 			if ( line[0] == 'a' ) {
 				ai->config.opmode |= 0;
 			} else {
 				ai->config.opmode |= 1;
 				if ( line[0] == 'r' ) {
 					ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
+					ai->config.scanMode = SCANMODE_PASSIVE;
 					ai->flags |= FLAG_802_11;
 				} else if ( line[0] == 'y' ) {
 					ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
+					ai->config.scanMode = SCANMODE_PASSIVE;
 					ai->flags |= FLAG_802_11;
 				} else if ( line[0] == 'l' )
 					ai->config.rmode |= RXMODE_LANMON;
@@ -3390,22 +3485,7 @@
 		while( line[0] && line[0] != '\n' ) line++;
 		if ( line[0] ) line++;
 	}
-	disable_MAC(ai);
-	if (need_reset) {
-		APListRid APList_rid;
-		SsidRid SSID_rid;
-
-		readAPListRid(ai, &APList_rid);
-		readSsidRid(ai, &SSID_rid);
-		reset_airo_card(dev);
-		disable_MAC(ai);
-		writeSsidRid(ai, &SSID_rid);
-		writeAPListRid(ai, &APList_rid);
-	}
-	writeConfigRid(ai);
-	enable_MAC(ai, &rsp);
-	if (need_reset)
-		airo_set_promisc(ai);
+	airo_config_commit(dev, NULL, NULL, NULL);
 }
 
 static char *get_rmode(u16 mode) {
@@ -3443,7 +3523,7 @@
 	data->maxwritelen = 2048;
 	data->on_close = proc_config_on_close;
 
-	readConfigRid(ai);
+	readConfigRid(ai, 1);
 
 	i = sprintf( data->rbuffer,
 		     "Mode: %s\n"
@@ -3535,9 +3615,9 @@
 		       offset < data->writelen ) offset++;
 		offset++;
 	}
-	disable_MAC(ai);
+	disable_MAC(ai, 1);
 	writeSsidRid(ai, &SSID_rid);
-	enable_MAC(ai, &rsp);
+	enable_MAC(ai, &rsp, 1);
 }
 
 inline static u8 hexVal(char c) {
@@ -3576,20 +3656,20 @@
 			}
 		}
 	}
-	disable_MAC(ai);
+	disable_MAC(ai, 1);
 	writeAPListRid(ai, &APList_rid);
-	enable_MAC(ai, &rsp);
+	enable_MAC(ai, &rsp, 1);
 }
 
 /* This function wraps PC4500_writerid with a MAC disable */
 static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
-			int len ) {
+			int len, int dummy ) {
 	int rc;
 	Resp rsp;
 
-	disable_MAC(ai);
-	rc = PC4500_writerid(ai, rid, rid_data, len);
-	enable_MAC(ai, &rsp);
+	disable_MAC(ai, 1);
+	rc = PC4500_writerid(ai, rid, rid_data, len, 1);
+	enable_MAC(ai, &rsp, 1);
 	return rc;
 }
 
@@ -3617,7 +3697,7 @@
 }
 
 static int set_wep_key(struct airo_info *ai, u16 index,
-		       const char *key, u16 keylen, int perm ) {
+		       const char *key, u16 keylen, int perm, int lock ) {
 	static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
 	WepKeyRid wkr;
 
@@ -3639,7 +3719,7 @@
 		printk(KERN_INFO "Setting key %d\n", index);
 	}
 
-	writeWepKeyRid(ai, &wkr, perm);
+	writeWepKeyRid(ai, &wkr, perm, lock);
 	return 0;
 }
 
@@ -3662,7 +3742,7 @@
 	    (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
 		index = data->wbuffer[0] - '0';
 		if (data->wbuffer[1] == '\n') {
-			set_wep_key(ai, index, 0, 0, 1);
+			set_wep_key(ai, index, 0, 0, 1, 1);
 			return;
 		}
 		j = 2;
@@ -3681,7 +3761,7 @@
 			break;
 		}
 	}
-	set_wep_key(ai, index, key, i/3, 1);
+	set_wep_key(ai, index, key, i/3, 1, 1);
 }
 
 static int proc_wepkey_open( struct inode *inode, struct file *file ) {
@@ -3937,10 +4017,9 @@
 			add_timer(&apriv->timer);
 			return;
 		}
-		__set_bit(FLAG_LOCKED, &apriv->flags);
 
-		readConfigRid(apriv);
-		disable_MAC(apriv);
+		readConfigRid(apriv, 0);
+		disable_MAC(apriv, 0);
 		switch(apriv->config.authType) {
 		case AUTH_ENCRYPT:
 /* So drop to OPEN */
@@ -3948,13 +4027,13 @@
 			break;
 		case AUTH_SHAREDKEY:
 			if (apriv->keyindex < auto_wep) {
-				set_wep_key(apriv, apriv->keyindex, 0, 0, 0);
+				set_wep_key(apriv, apriv->keyindex, 0, 0, 0, 0);
 				apriv->config.authType = AUTH_SHAREDKEY;
 				apriv->keyindex++;
 			} else {
 			        /* Drop to ENCRYPT */
 				apriv->keyindex = 0;
-				set_wep_key(apriv, apriv->defindex, 0, 0, 0);
+				set_wep_key(apriv, apriv->defindex, 0, 0, 0, 0);
 				apriv->config.authType = AUTH_ENCRYPT;
 			}
 			break;
@@ -3962,9 +4041,8 @@
 			apriv->config.authType = AUTH_SHAREDKEY;
 		}
 		apriv->need_commit = 1;
-		writeConfigRid(apriv);
-		enable_MAC(apriv, &rsp);
-		clear_bit(FLAG_LOCKED, &apriv->flags);
+		writeConfigRid(apriv, 0);
+		enable_MAC(apriv, &rsp, 0);
 		up(&apriv->sem);
 
 /* Schedule check to see if the change worked */
@@ -4144,9 +4222,11 @@
 	struct airo_info *local = dev->priv;
 	StatusRid status_rid;		/* Card status info */
 
-	readStatusRid(local, &status_rid);
+	if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
+		status_rid.channel = local->config.channelSet;
+	else
+		readStatusRid(local, &status_rid);
 
-	/* Will return zero in infrastructure mode */
 #ifdef WEXT_USECHANNELS
 	fwrq->m = ((int)status_rid.channel) + 1;
 	fwrq->e = 0;
@@ -4200,9 +4280,9 @@
 		SSID_rid.ssids[index].len = dwrq->length - 1;
 	}
 	/* Write it to the card */
-	disable_MAC(local);
+	disable_MAC(local, 1);
 	writeSsidRid(local, &SSID_rid);
-	enable_MAC(local, &rsp);
+	enable_MAC(local, &rsp, 1);
 
 	return 0;
 }
@@ -4264,9 +4344,9 @@
 		memset(&APList_rid, 0, sizeof(APList_rid));
 		APList_rid.len = sizeof(APList_rid);
 		memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
-		disable_MAC(local);
+		disable_MAC(local, 1);
 		writeAPListRid(local, &APList_rid);
-		enable_MAC(local, &rsp);
+		enable_MAC(local, &rsp, 1);
 	}
 	return 0;
 }
@@ -4515,28 +4595,52 @@
 			 char *extra)
 {
 	struct airo_info *local = dev->priv;
+	int commit = 1;
+
+	if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
+		commit = 2;
 
 	switch(*uwrq) {
 		case IW_MODE_ADHOC:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_STA_IBSS;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
 			break;
 		case IW_MODE_INFRA:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_STA_ESS;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
 			break;
 		case IW_MODE_MASTER:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
 			break;
 		case IW_MODE_REPEAT:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP_RPTR;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
+			break;
+		case IW_MODE_MONITOR:
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_STA_ESS;
+			local->config.rmode &= 0xfe00;
+			local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
+			local->config.scanMode = SCANMODE_PASSIVE;
+			local->flags |= FLAG_802_11;
 			break;
 		default:
 			return -EINVAL;
 	}
-	local->need_commit = 1;
+	local->need_commit = commit;
 
 	return -EINPROGRESS;		/* Call commit handler */
 }
@@ -4622,7 +4726,7 @@
 			/* Copy the key in the driver */
 			memcpy(key.key, extra, dwrq->length);
 			/* Send the key to the card */
-			set_wep_key(local, index, key.key, key.len, 1);
+			set_wep_key(local, index, key.key, key.len, 1, 1);
 		}
 		/* WE specify that if a valid key is set, encryption
 		 * should be enabled (user may turn it off later)
@@ -4636,7 +4740,7 @@
 		/* Do we want to just set the transmit key index ? */
 		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 		if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) {
-			set_wep_key(local, index, 0, 0, 1);
+			set_wep_key(local, index, 0, 0, 1, 1);
 		} else
 			/* Don't complain if only change the mode */
 			if(!dwrq->flags & IW_ENCODE_MODE) {
@@ -4841,7 +4945,7 @@
 	readCapabilityRid(local, &cap_rid);
 
 	dwrq->length = sizeof(struct iw_range);
-	memset(range, 0, sizeof(range));
+	memset(range, 0, sizeof(*range));
 	range->min_nwid = 0x0000;
 	range->max_nwid = 0x0000;
 	range->num_channels = 14;
@@ -5132,7 +5236,7 @@
 	Resp rsp;
 
 	/* Note : you may have realised that, as this is a SET operation,
-	 * this is priviledged and therefore a normal user can't
+	 * this is privileged and therefore a normal user can't
 	 * perform scanning.
 	 * This is not an error, while the device perform scanning,
 	 * traffic doesn't flow, so it's a perfect DoS...
@@ -5154,7 +5258,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Translate scan data returned from the card to a card independant
+ * Translate scan data returned from the card to a card independent
  * format that the Wireless Tools will understand - Jean II
  */
 static inline char *airo_translate_scan(struct net_device *dev,
@@ -5281,7 +5385,7 @@
 	 * consequences are begnign. So I don't bother fixing it - Javier */
 
 	/* Try to read the first entry of the scan result */
-	rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList));
+	rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1);
 	if((rc) || (BSSList.index == 0xffff)) {
 		/* Client error, no scan results...
 		 * The caller need to restart the scan. */
@@ -5297,7 +5401,7 @@
 
 		/* Read next entry */
 		rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
-				    &BSSList, sizeof(BSSList));
+				    &BSSList, sizeof(BSSList), 1);
 	}
 	/* Length of data */
 	dwrq->length = (current_ev - extra);
@@ -5307,6 +5411,7 @@
 }
 #endif	/* WIRELESS_EXT > 13 */
 
+#if WIRELESS_EXT <= 15
 #ifdef WIRELESS_SPY
 /*------------------------------------------------------------------*/
 /*
@@ -5369,6 +5474,7 @@
 	return 0;
 }
 #endif			/* WIRELESS_SPY */
+#endif /* WIRELESS_EXT <= 15 */
 
 /*------------------------------------------------------------------*/
 /*
@@ -5387,9 +5493,22 @@
 
 	/* Some of the "SET" function may have modified some of the
 	 * parameters. It's now time to commit them in the card */
-	disable_MAC(local);
-	writeConfigRid(local);
-	enable_MAC(local, &rsp);
+	disable_MAC(local, 1);
+	if (local->need_commit > 1) {
+		APListRid APList_rid;
+		SsidRid SSID_rid;
+
+		readAPListRid(local, &APList_rid);
+		readSsidRid(local, &SSID_rid);
+		reset_airo_card(dev);
+		disable_MAC(local, 1);
+		writeSsidRid(local, &SSID_rid);
+		writeAPListRid(local, &APList_rid);
+	}
+	writeConfigRid(local, 1);
+	enable_MAC(local, &rsp, 1);
+	if (local->need_commit > 1)
+		airo_set_promisc(local);
 
 	return 0;
 }
@@ -5426,6 +5545,12 @@
 	(iw_handler) NULL,			/* SIOCGIWPRIV */
 	(iw_handler) NULL,			/* SIOCSIWSTATS */
 	(iw_handler) NULL,			/* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+	iw_handler_set_spy,			/* SIOCSIWSPY */
+	iw_handler_get_spy,			/* SIOCGIWSPY */
+	iw_handler_set_thrspy,			/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,			/* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
 #ifdef WIRELESS_SPY
 	(iw_handler) airo_set_spy,		/* SIOCSIWSPY */
 	(iw_handler) airo_get_spy,		/* SIOCGIWSPY */
@@ -5435,6 +5560,7 @@
 #endif	/* WIRELESS_SPY */
 	(iw_handler) NULL,			/* -- hole -- */
 	(iw_handler) NULL,			/* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
 	(iw_handler) airo_set_wap,		/* SIOCSIWAP */
 	(iw_handler) airo_get_wap,		/* SIOCGIWAP */
 	(iw_handler) NULL,			/* -- hole -- */
@@ -5488,6 +5614,10 @@
 	standard:	(iw_handler *) airo_handler,
 	private:	(iw_handler *) airo_private_handler,
 	private_args:	(struct iw_priv_args *) airo_private_args,
+#if WIRELESS_EXT > 15
+	spy_offset:	((void *) (&((struct airo_info *) NULL)->spy_data) -
+			   (void *) NULL),
+#endif /* WIRELESS_EXT > 15 */
 };
 
 #endif /* WIRELESS_EXT > 12 */
@@ -5822,7 +5952,7 @@
 			break;
 		}
 
-		/* Seperate R/W functions bracket legality here
+		/* Separate R/W functions bracket legality here
 		 */
 		if ( com.command <= AIROGMICSTATS )
 			rc = readrids(dev,&com);
@@ -5860,7 +5990,6 @@
  *
  * TODO :
  *	o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
- *	o Find the noise level
  *
  * Jean
  */
@@ -5873,7 +6002,7 @@
 
 	/* Get stats out of the card */
 	readStatusRid(local, &status_rid);
-	readStatsRid(local, &stats_rid, RID_STATS);
+	readStatsRid(local, &stats_rid, RID_STATS, 1);
 
 	/* The status */
 	local->wstats.status = status_rid.mode;
@@ -5884,8 +6013,13 @@
 		local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm;
 	else
 		local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
-	local->wstats.qual.noise = 0;
-	local->wstats.qual.updated = 3;
+	if (status_rid.len >= 124) {
+		local->wstats.qual.noise = 256 - status_rid.noisedBm;
+		local->wstats.qual.updated = 7;
+	} else {
+		local->wstats.qual.noise = 0;
+		local->wstats.qual.updated = 3;
+	}
 
 	/* Packets discarded in the wireless adapter due to wireless
 	 * specific problems */
@@ -5900,6 +6034,7 @@
 #endif /* WIRELESS_EXT */
 
 #ifdef CISCO_EXT
+#define RIDS_SIZE	2048
 /*
  * This just translates from driver IOCTL codes to the command codes to
  * feed to the radio's host interface. Things can be added/deleted
@@ -5908,7 +6043,7 @@
  */
 static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 	unsigned short ridcode;
-	unsigned char iobuf[2048];
+	unsigned char *iobuf;
 	struct airo_info *ai = dev->priv;
 
 	if (ai->flags & FLAG_FLASHING)
@@ -5917,7 +6052,7 @@
 	switch(comp->command)
 	{
 	case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
-	case AIROGCFG: writeConfigRid (ai);
+	case AIROGCFG: writeConfigRid (ai, 1);
 			    ridcode = RID_CONFIG;       break;
 	case AIROGSLIST:    ridcode = RID_SSID;         break;
 	case AIROGVLIST:    ridcode = RID_APLIST;       break;
@@ -5946,15 +6081,21 @@
 		break;
 	}
 
-	PC4500_readrid(ai,ridcode,iobuf,sizeof(iobuf));
+	if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	PC4500_readrid(ai,ridcode,iobuf,RIDS_SIZE, 1);
 	/* get the count of bytes in the rid  docs say 1st 2 bytes is it.
 	 * then return it to the user
 	 * 9/22/2000 Honor user given length
 	 */
 
 	if (copy_to_user(comp->data, iobuf,
-			 min((int)comp->len, (int)sizeof(iobuf))))
+			 min((int)comp->len, (int)RIDS_SIZE))) {
+		kfree (iobuf);
 		return -EFAULT;
+	}
+	kfree (iobuf);
 	return 0;
 }
 
@@ -5966,8 +6107,8 @@
 	struct airo_info *ai = dev->priv;
 	int  ridcode, enabled;
 	Resp      rsp;
-	static int (* writer)(struct airo_info *, u16 rid, const void *, int);
-	unsigned char iobuf[2048];
+	static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
+	unsigned char *iobuf;
 
 	/* Only super-user can write RIDs */
 	if (!capable(CAP_NET_ADMIN))
@@ -5996,7 +6137,7 @@
 		 * same with MAC off
 		 */
 	case AIROPMACON:
-		if (enable_MAC(ai, &rsp) != 0)
+		if (enable_MAC(ai, &rsp, 1) != 0)
 			return -EIO;
 		return 0;
 
@@ -6005,7 +6146,7 @@
 		 * as disable_MAC. it's probably so short the compiler does not gen one.
 		 */
 	case AIROPMACOFF:
-		disable_MAC(ai);
+		disable_MAC(ai, 1);
 		return 0;
 
 		/* This command merely clears the counts does not actually store any data
@@ -6013,25 +6154,36 @@
 		 * writerid routines.
 		 */
 	case AIROPSTCLR:
-		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,sizeof(iobuf));
+		if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+
+		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1);
 
 		enabled = ai->micstats.enabled;
 		memset(&ai->micstats,0,sizeof(ai->micstats));
 		ai->micstats.enabled = enabled;
 
 		if (copy_to_user(comp->data, iobuf,
-				 min((int)comp->len, (int)sizeof(iobuf))))
+				 min((int)comp->len, (int)RIDS_SIZE))) {
+			kfree (iobuf);
 			return -EFAULT;
+		}
+		kfree (iobuf);
 		return 0;
 
 	default:
 		return -EOPNOTSUPP;	/* Blarg! */
 	}
-	if(comp->len > sizeof(iobuf))
+	if(comp->len > RIDS_SIZE)
 		return -EINVAL;
 
-	if (copy_from_user(iobuf,comp->data,comp->len))
+	if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(iobuf,comp->data,comp->len)) {
+		kfree (iobuf);
 		return -EFAULT;
+	}
 
 	if (comp->command == AIROPCFG) {
 		ConfigRid *cfg = (ConfigRid *)iobuf;
@@ -6045,8 +6197,11 @@
 			ai->flags &= ~FLAG_ADHOC;
 	}
 
-	if((*writer)(ai, ridcode, iobuf,comp->len))
+	if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
+		kfree (iobuf);
 		return -EIO;
+	}
+	kfree (iobuf);
 	return 0;
 }
 
@@ -6125,7 +6280,7 @@
  */
 
 int cmdreset(struct airo_info *ai) {
-	disable_MAC(ai);
+	disable_MAC(ai, 1);
 
 	if(!waitbusy (ai)){
 		printk(KERN_INFO "Waitbusy hang before RESET\n");
diff -urN linux-2.4.22-pre9/drivers/scsi/3w-xxxx.c linux-2.4.22-pre10/drivers/scsi/3w-xxxx.c
--- linux-2.4.22-pre9/drivers/scsi/3w-xxxx.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.22-pre10/drivers/scsi/3w-xxxx.c	2003-08-01 09:16:08.000000000 -0700
@@ -165,6 +165,14 @@
                  Add support for "twe" character device for ioctls.
                  Clean up request_id queueing code.
                  Fix tw_scsi_queue() spinlocks.
+   1.02.00.033 - Fix tw_aen_complete() to not queue 'queue empty' AEN's.
+                 Initialize queues correctly when loading with no valid units.
+   1.02.00.034 - Fix tw_decode_bits() to handle multiple errors.
+                 Add support for user configurable cmd_per_lun.
+                 Add support for sht->select_queue_depths.
+   1.02.00.035 - Improve tw_allocate_memory() memory allocation.
+                 Fix tw_chrdev_ioctl() to sleep correctly.
+   1.02.00.036 - Increase character ioctl timeout to 60 seconds.
 */
 
 #include <linux/module.h>
@@ -232,7 +240,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.032";
+char *tw_driver_version="1.02.00.036";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 static int twe_major = -1;
@@ -271,25 +279,24 @@
 			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
 		}
 	}
-	if (aen != 0x0) 
+	if (aen != TW_AEN_QUEUE_EMPTY) {
 		tw_dev->aen_count++;
 
-	/* Now queue the code */
-	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
-	if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
-		tw_dev->aen_tail = TW_Q_START;
-	} else {
-		tw_dev->aen_tail = tw_dev->aen_tail + 1;
-	}
-	if (tw_dev->aen_head == tw_dev->aen_tail) {
-		if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
-			tw_dev->aen_head = TW_Q_START;
+		/* Now queue the code */
+		tw_dev->aen_queue[tw_dev->aen_tail] = aen;
+		if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
+			tw_dev->aen_tail = TW_Q_START;
 		} else {
-			tw_dev->aen_head = tw_dev->aen_head + 1;
+			tw_dev->aen_tail = tw_dev->aen_tail + 1;
+		}
+		if (tw_dev->aen_head == tw_dev->aen_tail) {
+			if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+				tw_dev->aen_head = TW_Q_START;
+			} else {
+				tw_dev->aen_head = tw_dev->aen_head + 1;
+			}
 		}
-	}
 
-	if (aen != TW_AEN_QUEUE_EMPTY) {
 		error = tw_aen_read_queue(tw_dev, request_id);
 		if (error) {
 			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
@@ -556,34 +563,33 @@
 	else
 		imax = TW_Q_LENGTH;
 
-	for (i=0;i<imax;i++) {
-		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
-		if (cpu_addr == NULL) {
-			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
-			return 1;
-		}
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*imax, &dma_handle);
+	if (cpu_addr == NULL) {
+		printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+		return 1;
+	}
 
-		if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
-			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
-			pci_free_consistent(tw_dev->tw_pci_dev, size, cpu_addr, dma_handle);
-			return 1;
-		}
+	if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
+		printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
+		pci_free_consistent(tw_dev->tw_pci_dev, size*imax, cpu_addr, dma_handle);
+		return 1;
+	}
+
+	memset(cpu_addr, 0, size*imax);
 
+	for (i=0;i<imax;i++) {
 		switch(which) {
 		case 0:
-			tw_dev->command_packet_virtual_address[i] = cpu_addr;
-			tw_dev->command_packet_physical_address[i] = dma_handle;
-			memset(tw_dev->command_packet_virtual_address[i], 0, size);
+			tw_dev->command_packet_physical_address[i] = dma_handle+(i*size);
+			tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
 			break;
 		case 1:
-			tw_dev->alignment_virtual_address[i] = cpu_addr;
-			tw_dev->alignment_physical_address[i] = dma_handle;
-			memset(tw_dev->alignment_virtual_address[i], 0, size);
+			tw_dev->alignment_physical_address[i] = dma_handle+(i*size);
+			tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
 			break;
 		case 2:
-			tw_dev->bounce_buffer[i] = cpu_addr;
-			tw_dev->bounce_buffer_phys[i] = dma_handle;
-			memset(tw_dev->bounce_buffer[i], 0, size);
+			tw_dev->bounce_buffer_phys[i] = dma_handle+(i*size);
+			tw_dev->bounce_buffer[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
 			break;
 		default:
 			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
@@ -631,11 +637,11 @@
 	int error, request_id;
 	dma_addr_t dma_handle;
 	unsigned short tw_aen_code;
-	unsigned long before;
 	unsigned long flags;
 	unsigned int data_buffer_length = 0;
 	unsigned long data_buffer_length_adjusted = 0;
 	unsigned long *cpu_addr;
+	long timeout;
 	TW_New_Ioctl *tw_ioctl;
 	TW_Passthru *passthru;
 	TW_Device_Extension *tw_dev = tw_device_extension_list[MINOR(inode->i_rdev)];
@@ -735,30 +741,30 @@
 			tw_post_command_packet(tw_dev, request_id);
 			spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
 
+			timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
 			/* Now wait for the command to complete */
-			before = jiffies;
+			tw_wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
 
-			while (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
-				/* FIXME: we need to sleep here */
-				udelay(10);
-				if (time_after(jiffies, before + HZ *TW_IOCTL_CHRDEV_TIMEOUT)) {
-					/* Now we need to reset the board */
+			/* Check if we timed out, got a signal, or didn't get 
+                           an interrupt */
+			if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+				/* Now we need to reset the board */
+				if (timeout == -ERESTARTSYS) {
+					retval = timeout;
+				} else {
 					printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
-					spin_lock_irqsave(&tw_dev->tw_lock, flags);
-					tw_dev->state[request_id] = TW_S_COMPLETED;
-					tw_state_request_finish(tw_dev, request_id);
-					pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
-					tw_dev->posted_request_count--;
-					if (tw_reset_device_extension(tw_dev)) {
-						printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
-					}
-					spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
-					if (signal_pending(current))
-						retval = -EINTR;
-					else
-						retval = -EIO;
-					goto out2;
+					retval = -EIO;
+				}
+				spin_lock_irqsave(&tw_dev->tw_lock, flags);
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				tw_state_request_finish(tw_dev, request_id);
+				tw_dev->posted_request_count--;
+				if (tw_reset_device_extension(tw_dev)) {
+					printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
 				}
+				spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+				goto out2;
 			}
 
 			/* Now copy in the command packet response */
@@ -886,30 +892,33 @@
 	else
 		host[0] = '\0';
 
-	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
-	case TW_STATUS_PCI_PARITY_ERROR:
+	if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
 		printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
-		break;
-	case TW_STATUS_MICROCONTROLLER_ERROR:
-		if (tw_dev->reset_print == 0) {
-			printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
-			tw_dev->reset_print = 1;
-		}
-		return 1;
-	case TW_STATUS_PCI_ABORT:
+	}
+
+	if (status_reg_value & TW_STATUS_PCI_ABORT) {
 		printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
 		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
-		break;
-	case TW_STATUS_QUEUE_ERROR:
+	}
+	
+	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
 		printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr);
-		break;
-	case TW_STATUS_SBUF_WRITE_ERROR:
+	}
+	
+	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
 		printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr);
-		break;
+	}
+
+	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+		if (tw_dev->reset_print == 0) {
+			printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+			tw_dev->reset_print = 1;
+		}
+		return 1;
 	}
 
 	return 0;
@@ -1143,19 +1152,24 @@
 			tw_dev->online = 1;
 
 			/* Calculate max cmds per lun, and setup queues */
-			if (tw_dev->num_units > 0) {
-				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-2)/tw_dev->num_units;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_Q_START;
-					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
-				} else {
-					/* Use SHT cmd_per_lun here */
+			if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
+				tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-2)/tw_dev->num_units;
+				tw_dev->free_head = TW_Q_START;
+				tw_dev->free_tail = TW_Q_START;
+				tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
+			} else {
+				/* Check for user configured cmd_per_lun */
+#ifdef CONFIG_3W_XXXX_CMD_PER_LUN
+				tw_host->cmd_per_lun = CONFIG_3W_XXXX_CMD_PER_LUN;
+				if (tw_host->cmd_per_lun > TW_MAX_CMDS_PER_LUN)
 					tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_Q_START;
-					tw_dev->free_wrap = TW_Q_LENGTH - 1;
-				}
+#else
+				/* Use SHT cmd_per_lun default */
+				tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN;
+#endif
+				tw_dev->free_head = TW_Q_START;
+				tw_dev->free_tail = TW_Q_START;
+				tw_dev->free_wrap = TW_Q_LENGTH - 1;
 			}
 
 		/* Register the card with the kernel SCSI layer */
@@ -1184,6 +1198,8 @@
 				host->max_sectors = TW_MAX_SECTORS;
 #endif
 
+			host->select_queue_depths = tw_select_queue_depths;
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
 			scsi_set_pci_device(host, tw_pci_dev);
 #endif
@@ -1198,6 +1214,10 @@
 			if (host->hostdata) {
 				tw_dev2 = (TW_Device_Extension *)host->hostdata;
 				memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
+				/* Need to init the sem/wqueue after the copy */
+				init_MUTEX(&tw_dev2->ioctl_sem);
+				init_waitqueue_head(&tw_dev2->ioctl_wqueue);
+
 				tw_device_extension_list[tw_device_extension_count] = tw_dev2;
 				numcards++;
 				tw_device_extension_count = numcards;
@@ -1254,22 +1274,17 @@
 /* This function will free up device extension resources */
 void tw_free_device_extension(TW_Device_Extension *tw_dev)
 {
-	int i;
-
 	dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
+
 	/* Free command packet and generic buffer memory */
-	for (i=0;i<TW_Q_LENGTH;i++) {
-		if (tw_dev->command_packet_virtual_address[i])
-			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);
+	if (tw_dev->command_packet_physical_address[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);
 
-		if (tw_dev->alignment_virtual_address[i])
-			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
+	if (tw_dev->alignment_physical_address[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);
 
-	}
-	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-		if (tw_dev->bounce_buffer[i])
-			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS, tw_dev->bounce_buffer[i], tw_dev->bounce_buffer_phys[i]);
-	}
+	if (tw_dev->bounce_buffer[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_MAX_BOUNCE_SECTORS*TW_MAX_BOUNCEBUF, tw_dev->bounce_buffer[0], tw_dev->bounce_buffer_phys[0]);
 } /* End tw_free_device_extension() */
 
 /* Clean shutdown routine */
@@ -1379,8 +1394,6 @@
 	tw_dev->pending_tail = TW_Q_START;
 	spin_lock_init(&tw_dev->tw_lock);
 	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-	init_waitqueue_head(&tw_dev->ioctl_wqueue);
-	init_MUTEX(&tw_dev->ioctl_sem);
 
 	return 0;
 } /* End tw_initialize_device_extension() */
@@ -1720,6 +1733,7 @@
 						}
 					} else {
 						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+						wake_up(&tw_dev->ioctl_wqueue);
 					}
 				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
@@ -3395,6 +3409,31 @@
 	return 0;
 } /* End tw_scsiop_test_unit_ready_complete() */
 
+/* This function will select queue depths for a target */
+void tw_select_queue_depths(struct Scsi_Host *host, Scsi_Device *dev)
+{
+	Scsi_Device *ptr;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_select_queue_depths()\n");
+
+	for (ptr = dev; ptr != NULL; ptr = ptr->next) {
+		if (ptr->host == host) {
+			if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
+				ptr->queue_depth = (TW_MAX_BOUNCEBUF-2)/tw_dev->num_units;
+			} else {
+#ifdef CONFIG_3W_XXXX_CMD_PER_LUN
+				ptr->queue_depth = CONFIG_3W_XXXX_CMD_PER_LUN;
+				if (ptr->queue_depth > TW_MAX_CMDS_PER_LUN)
+					ptr->queue_depth = TW_MAX_CMDS_PER_LUN;
+#else
+				ptr->queue_depth = TW_MAX_CMDS_PER_LUN;
+#endif
+			}
+		}
+	}
+} /* End tw_select_queue_depths() */
+
 /* Set a value in the features table */
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
                   unsigned char *val)
diff -urN linux-2.4.22-pre9/drivers/scsi/3w-xxxx.h linux-2.4.22-pre10/drivers/scsi/3w-xxxx.h
--- linux-2.4.22-pre9/drivers/scsi/3w-xxxx.h	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.22-pre10/drivers/scsi/3w-xxxx.h	2003-08-01 09:16:08.000000000 -0700
@@ -115,10 +115,10 @@
   {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
   {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
   {0x37, 0x02, 0x04, 0x00}, // Unit offline                 Not ready
+  {0x09, 0x02, 0x04, 0x00}, // Unrecovered disk error       Not ready
 
   /* Codes for older firmware */
                             // 3ware Error                  SCSI Error
-  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
   {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
 };
 
@@ -238,7 +238,7 @@
 #define TW_ISR_DONT_COMPLETE                  2
 #define TW_ISR_DONT_RESULT                    3
 #define TW_IOCTL_TIMEOUT                      25 /* 25 seconds */
-#define TW_IOCTL_CHRDEV_TIMEOUT               25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_TIMEOUT               60 /* 60 seconds */
 #define TW_IOCTL_CHRDEV_FREE                  -1
 
 /* Macros */
@@ -249,6 +249,30 @@
 	(x & TW_STATUS_MICROCONTROLLER_ERROR)) && \
 	(x & TW_STATUS_MICROCONTROLLER_READY))
 
+/* This was taken from 2.5 kernel */
+#define tw_wait_event_interruptible_timeout(wq, condition, ret)         \
+do {                                                                    \
+        wait_queue_t __wait;                                            \
+        init_waitqueue_entry(&__wait, current);                         \
+                                                                        \
+        add_wait_queue(&wq, &__wait);                                   \
+        for (;;) {                                                      \
+                set_current_state(TASK_INTERRUPTIBLE);                  \
+                if (condition)                                          \
+                        break;                                          \
+                if (!signal_pending(current)) {                         \
+                        ret = schedule_timeout(ret);                    \
+                        if (!ret)                                       \
+                                break;                                  \
+                        continue;                                       \
+                }                                                       \
+                ret = -ERESTARTSYS;                                     \
+                break;                                                  \
+        }                                                               \
+        current->state = TASK_RUNNING;                                  \
+        remove_wait_queue(&wq, &__wait);                                \
+} while (0)
+
 #ifdef TW_DEBUG
 #define dprintk(msg...) printk(msg)
 #else
@@ -498,6 +522,7 @@
 int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id);
+void tw_select_queue_depths(struct Scsi_Host *host, Scsi_Device *dev);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, 
 		  unsigned char *val);
 int tw_setup_irq(TW_Device_Extension *tw_dev);
diff -urN linux-2.4.22-pre9/drivers/video/matrox/matroxfb_DAC1064.c linux-2.4.22-pre10/drivers/video/matrox/matroxfb_DAC1064.c
--- linux-2.4.22-pre9/drivers/video/matrox/matroxfb_DAC1064.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/drivers/video/matrox/matroxfb_DAC1064.c	2003-08-01 09:16:09.000000000 -0700
@@ -1177,6 +1177,7 @@
 
 	DAC1064_restore_1(PMINFO2);
 	matroxfb_vgaHWrestore(PMINFO2);
+	ACCESS_FBINFO(crtc1.panpos) = -1;
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(PMINFO p);
@@ -1203,6 +1204,7 @@
 	if (ACCESS_FBINFO(devflags.support32MB))
 		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
 #endif
+	ACCESS_FBINFO(crtc1.panpos) = -1;
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(PMINFO p);
diff -urN linux-2.4.22-pre9/drivers/video/matrox/matroxfb_Ti3026.c linux-2.4.22-pre10/drivers/video/matrox/matroxfb_Ti3026.c
--- linux-2.4.22-pre9/drivers/video/matrox/matroxfb_Ti3026.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/drivers/video/matrox/matroxfb_Ti3026.c	2003-08-01 09:16:09.000000000 -0700
@@ -716,6 +716,7 @@
 
 	CRITBEGIN
 
+	ACCESS_FBINFO(crtc1.panpos) = -1;
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 
diff -urN linux-2.4.22-pre9/drivers/video/matrox/matroxfb_base.c linux-2.4.22-pre10/drivers/video/matrox/matroxfb_base.c
--- linux-2.4.22-pre9/drivers/video/matrox/matroxfb_base.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/drivers/video/matrox/matroxfb_base.c	2003-08-01 09:16:09.000000000 -0700
@@ -152,6 +152,165 @@
 
 /* --------------------------------------------------------------------- */
 
+static void matroxfb_crtc1_panpos(WPMINFO2) {
+	if (ACCESS_FBINFO(crtc1.panpos) >= 0) {
+		unsigned long flags;
+		int panpos;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		panpos = ACCESS_FBINFO(crtc1.panpos);
+		if (panpos >= 0) {
+			unsigned int extvga_reg;
+			
+			ACCESS_FBINFO(crtc1.panpos) = -1; /* No update pending anymore */
+			extvga_reg = mga_inb(M_EXTVGA_INDEX);
+			mga_setr(M_EXTVGA_INDEX, 0x00, panpos);
+			if (extvga_reg != 0x00) {
+				mga_outb(M_EXTVGA_INDEX, extvga_reg);
+			}
+		}
+		matroxfb_DAC_unlock_irqrestore(flags);
+	}
+}
+
+static void matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
+{
+	u_int32_t status;
+	int handled = 0;
+
+	MINFO_FROM(dev_id);
+
+	status = mga_inl(M_STATUS);
+
+	if (status & 0x20) {
+		mga_outl(M_ICLEAR, 0x20);
+		ACCESS_FBINFO(crtc1.vsync.cnt)++;
+		matroxfb_crtc1_panpos(PMINFO2);
+		wake_up_interruptible(&ACCESS_FBINFO(crtc1.vsync.wait));
+		handled = 1;
+	}
+	if (status & 0x200) {
+		mga_outl(M_ICLEAR, 0x200);
+		ACCESS_FBINFO(crtc2.vsync.cnt)++;
+		wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait));
+		handled = 1;
+	}
+	return;
+}
+
+int matroxfb_enable_irq(WPMINFO int reenable) {
+	u_int32_t bm;
+	
+	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+		bm = 0x220;
+	else
+		bm = 0x020;
+
+	if (!test_and_set_bit(0, &ACCESS_FBINFO(irq_flags))) {
+		if (request_irq(ACCESS_FBINFO(pcidev)->irq, matrox_irq,
+				SA_SHIRQ, "matroxfb", MINFO)) {
+			clear_bit(0, &ACCESS_FBINFO(irq_flags));
+			return -EINVAL;
+		}
+		/* Clear any pending field interrupts */
+		mga_outl(M_ICLEAR, bm);
+		mga_outl(M_IEN, mga_inl(M_IEN) | bm);
+	} else if (reenable) {
+		u_int32_t ien;
+		
+		ien = mga_inl(M_IEN);
+		if ((ien & bm) != bm) {
+			printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
+			mga_outl(M_IEN, ien | bm);
+		}
+	}
+	return 0;
+}
+
+static void matroxfb_disable_irq(WPMINFO2) {
+	if (test_and_clear_bit(0, &ACCESS_FBINFO(irq_flags))) {
+		/* Flush pending pan-at-vbl request... */
+		matroxfb_crtc1_panpos(PMINFO2);
+		if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+			mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220);
+		else
+			mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20);
+		free_irq(ACCESS_FBINFO(pcidev)->irq, MINFO);
+	}
+}
+
+#ifndef wait_event_interruptible_timeout
+#define __wait_event_interruptible_timeout(wq, condition, ret)		\
+do {									\
+	wait_queue_t __wait;						\
+	init_waitqueue_entry(&__wait, current);				\
+									\
+	add_wait_queue(&wq, &__wait);					\
+	for (;;) {							\
+		set_current_state(TASK_INTERRUPTIBLE);			\
+		if (condition)						\
+			break;						\
+		if (!signal_pending(current)) {				\
+			ret = schedule_timeout(ret);			\
+			if (!ret)					\
+				break;					\
+			continue;					\
+		}							\
+		ret = -ERESTARTSYS;					\
+		break;							\
+	}								\
+	current->state = TASK_RUNNING;					\
+	remove_wait_queue(&wq, &__wait);				\
+} while (0)
+
+#define wait_event_interruptible_timeout(wq, condition, timeout)	\
+({									\
+	long __ret = timeout;						\
+	if (!(condition))						\
+		__wait_event_interruptible_timeout(wq, condition, __ret); \
+	__ret;								\
+})
+#endif
+
+int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc) {
+	wait_queue_t __wait;
+	struct matrox_vsync *vs;
+	unsigned int cnt;
+	int ret;
+
+	switch (crtc) {
+		case 0:
+			vs = &ACCESS_FBINFO(crtc1.vsync);
+			break;
+		case 1:
+			if (ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG400) {
+				return -ENODEV;
+			}
+			vs = &ACCESS_FBINFO(crtc2.vsync);
+			break;
+		default:
+			return -ENODEV;
+	}
+	ret = matroxfb_enable_irq(PMINFO 0);
+	if (ret) {
+		return ret;
+	}
+        init_waitqueue_entry(&__wait, current);
+
+	cnt = vs->cnt;
+	ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10);
+	if (ret < 0) {
+		return ret;
+	}
+	if (ret == 0) {
+		matroxfb_enable_irq(PMINFO 1);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
 static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
 	unsigned int pos;
 	unsigned short p0, p1, p2;
@@ -159,6 +318,8 @@
 	unsigned int p3;
 #endif
 	struct display *disp;
+	int vbl;
+	unsigned long flags;
 	CRITFLAGS
 
 	DBG("matrox_pan_var")
@@ -180,15 +341,27 @@
 	p3 = ACCESS_FBINFO(hw).CRTCEXT[8] = pos >> 21;
 #endif
 
+	/* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */
+	vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(PMINFO 0) == 0);
+
 	CRITBEGIN
 
+	matroxfb_DAC_lock_irqsave(flags);
+
 	mga_setr(M_CRTC_INDEX, 0x0D, p0);
 	mga_setr(M_CRTC_INDEX, 0x0C, p1);
 #ifdef CONFIG_FB_MATROX_32MB
 	if (ACCESS_FBINFO(devflags.support32MB))
 		mga_setr(M_EXTVGA_INDEX, 0x08, p3);
 #endif
-	mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+	if (vbl) {
+		ACCESS_FBINFO(crtc1.panpos) = p2;
+	} else {
+		/* Abort any pending change */
+		ACCESS_FBINFO(crtc1.panpos) = -1;
+		mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+	}
+	matroxfb_DAC_unlock_irqrestore(flags);
 
 	CRITEND
 }
@@ -231,53 +404,61 @@
 
 static int matroxfb_open(struct fb_info *info, int user)
 {
-#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
-	DBG_LOOP("matroxfb_open")
-
-	if (ACCESS_FBINFO(dead)) {
-		return -ENXIO;
+	MINFO_FROM_INFO(info);
+	
+	DBG_LOOP(__FUNCTION__)
+ 
+ 	if (ACCESS_FBINFO(dead)) {
+ 		return -ENXIO;
+ 	}
+ 	ACCESS_FBINFO(usecount)++;
+	if (user) {
+		ACCESS_FBINFO(userusecount)++;
 	}
-	ACCESS_FBINFO(usecount)++;
-#undef minfo
-	return(0);
+	return 0;
 }
 
 static int matroxfb_release(struct fb_info *info, int user)
 {
-#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
-	DBG_LOOP("matroxfb_release")
-
+	MINFO_FROM_INFO(info);
+	
+	DBG_LOOP(__FUNCTION__)
+
+	if (user) {
+		if (0 == --ACCESS_FBINFO(userusecount)) {
+			matroxfb_disable_irq(PMINFO2);
+		}
+	}
 	if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
 		matroxfb_remove(PMINFO 0);
 	}
-#undef minfo
-	return(0);
+	return 0;
 }
 
 static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
 		struct fb_info* info) {
-#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
-
+	struct display* dsp;
+	MINFO_FROM_INFO(info);
 	DBG("matroxfb_pan_display")
 
+	if (con < 0) {
+		dsp = info->disp;
+	} else {
+		dsp = fb_display + con;
+	}
 	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
-			return -EINVAL;
+		return -EINVAL;
 	} else {
-		if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
-		    var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+		if (var->xoffset+dsp->var.xres > dsp->var.xres_virtual ||
+		    var->yoffset+dsp->var.yres > dsp->var.yres_virtual)
 			return -EINVAL;
 	}
 	if (con == ACCESS_FBINFO(currcon))
 		matrox_pan_var(PMINFO var);
-	fb_display[con].var.xoffset = var->xoffset;
-	fb_display[con].var.yoffset = var->yoffset;
-	if (var->vmode & FB_VMODE_YWRAP)
-		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
-	else
-		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+	dsp->var.xoffset = var->xoffset;
+	dsp->var.yoffset = var->yoffset;
+	dsp->var.vmode &= ~FB_VMODE_YWRAP;
 	return 0;
-#undef minfo
 }
 
 static int matroxfb_updatevar(int con, struct fb_info *info)
@@ -963,10 +1144,11 @@
 #undef minfo
 }
 
-static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank)
+static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank)
 {
 	unsigned int sts1;
 
+	matroxfb_enable_irq(PMINFO 0);
 	memset(vblank, 0, sizeof(*vblank));
 	vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC |
 			FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK;
@@ -981,8 +1163,12 @@
 		vblank->flags |= FB_VBLANK_VSYNCING;
 	if (vblank->vcount >= ACCESS_FBINFO(currcon_display)->var.yres)
 		vblank->flags |= FB_VBLANK_VBLANKING;
-	vblank->hcount = 0;
-	vblank->count = 0;
+	if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
+		vblank->flags |= FB_VBLANK_HAVE_COUNT;
+		/* Only one writer, aligned int value... 
+		   it should work without lock and without atomic_t */
+		vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
+	}
 	return 0;
 }
 
@@ -1015,6 +1201,15 @@
 					return -EFAULT;
 				return 0;
 			}
+		case FBIO_WAITFORVSYNC:
+			{
+				u_int32_t crt;
+
+				if (get_user(crt, (u_int32_t *)arg))
+					return -EFAULT;
+
+				return matroxfb_wait_for_sync(PMINFO crt);
+			}
 		case MATROXFB_SET_OUTPUT_MODE:
 			{
 				struct matroxioc_output_mode mom;
@@ -2230,6 +2425,10 @@
 	spin_lock_init(&ACCESS_FBINFO(lock.accel));
 	init_rwsem(&ACCESS_FBINFO(crtc2.lock));
 	init_rwsem(&ACCESS_FBINFO(altout.lock));
+	ACCESS_FBINFO(irq_flags) = 0;
+	init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait));
+	init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait));
+	ACCESS_FBINFO(crtc1.panpos) = -1;
 
 	err = initMatrox2(PMINFO d, b);
 	if (!err) {
@@ -2768,6 +2967,8 @@
 EXPORT_SYMBOL(matroxfb_register_driver);
 EXPORT_SYMBOL(matroxfb_unregister_driver);
 EXPORT_SYMBOL(matroxfb_switch);
+EXPORT_SYMBOL(matroxfb_wait_for_sync);
+EXPORT_SYMBOL(matroxfb_enable_irq);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.4.22-pre9/drivers/video/matrox/matroxfb_base.h linux-2.4.22-pre10/drivers/video/matrox/matroxfb_base.h
--- linux-2.4.22-pre9/drivers/video/matrox/matroxfb_base.h	2003-08-01 09:16:00.000000000 -0700
+++ linux-2.4.22-pre10/drivers/video/matrox/matroxfb_base.h	2003-08-01 09:16:09.000000000 -0700
@@ -468,6 +468,11 @@
 struct matroxfb_driver;
 struct matroxfb_dh_fb_info;
 
+struct matrox_vsync {
+	wait_queue_head_t	wait;
+	unsigned int		cnt;
+};
+
 struct matrox_fb_info {
 	struct fb_info		fbcon;
 
@@ -476,6 +481,9 @@
 	int			dead;
 	unsigned int		usecount;
 
+	unsigned int		userusecount;
+	unsigned long		irq_flags;
+
 	struct matroxfb_par	curr;
 	struct matrox_hw_state	hw;
 
@@ -603,10 +611,13 @@
 			      } cursor;
 	struct matrox_bios	bios;
 	struct {
+		struct matrox_vsync	vsync;
+		int		panpos;
 		unsigned int	pixclock;
 		int		mnp;
 			      } crtc1;
 	struct {
+		struct matrox_vsync	vsync;
 		unsigned int 	pixclock;
 		int		mnp;
 	struct matroxfb_dh_fb_info*	info;
@@ -663,6 +674,8 @@
 #endif
 };
 
+#define info2minfo(info) list_entry(info, struct matrox_fb_info, fbcon)
+
 #ifdef CONFIG_FB_MATROX_MULTIHEAD
 #define ACCESS_FBINFO2(info, x) (info->x)
 #define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x)
@@ -677,12 +690,11 @@
 #define PMINFO   PMINFO2 ,
 
 static inline struct matrox_fb_info* mxinfo(const struct display* p) {
-	return list_entry(p->fb_info, struct matrox_fb_info, fbcon);
+	return info2minfo(p->fb_info);
 }
 
 #define PMXINFO(p)	   mxinfo(p),
 #define MINFO_FROM(x)	   struct matrox_fb_info* minfo = x
-#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
 
 #else
 
@@ -700,18 +712,14 @@
 #define PMINFO2
 #define PMINFO
 
-#if 0
-static inline struct matrox_fb_info* mxinfo(const struct display* p) {
-	return &matroxfb_global_mxinfo;
-}
-#endif
-
 #define PMXINFO(p)
 #define MINFO_FROM(x)
-#define MINFO_FROM_DISP(x)
 
 #endif
 
+#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
+#define MINFO_FROM_INFO(x) MINFO_FROM(info2minfo(x))
+
 struct matrox_switch {
 	int	(*preinit)(WPMINFO2);
 	void	(*reset)(WPMINFO2);
@@ -793,7 +801,7 @@
 
 #define M_FIFOSTATUS	0x1E10
 #define M_STATUS	0x1E14
-
+#define M_ICLEAR	0x1E18
 #define M_IEN		0x1E1C
 
 #define M_VCOUNT	0x1E20
@@ -916,6 +924,8 @@
 extern struct list_head matroxfb_list;
 extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt);
 extern int matroxfb_switch(int con, struct fb_info *);
+extern int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc);
+extern int matroxfb_enable_irq(WPMINFO int reenable);
 
 #ifdef MATROXFB_USE_SPINLOCKS
 #define CRITBEGIN  spin_lock_irqsave(&ACCESS_FBINFO(lock.accel), critflags);
diff -urN linux-2.4.22-pre9/drivers/video/matrox/matroxfb_crtc2.c linux-2.4.22-pre10/drivers/video/matrox/matroxfb_crtc2.c
--- linux-2.4.22-pre9/drivers/video/matrox/matroxfb_crtc2.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/drivers/video/matrox/matroxfb_crtc2.c	2003-08-01 09:16:09.000000000 -0700
@@ -193,7 +193,7 @@
 	{
 		u_int32_t tmp;
 
-		tmp = 0x0FFF0000;		/* line compare */
+		tmp = mt->VDisplay << 16;		/* line compare */
 		if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
 			tmp |= 0x00000100;
 		if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
@@ -338,8 +338,14 @@
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
-		if (ACCESS_FBINFO(dead)) {
-			return -ENXIO;
+		int err;
+
+ 		if (ACCESS_FBINFO(dead)) {
+ 			return -ENXIO;
+ 		}
+		err = ACCESS_FBINFO(fbcon.fbops)->fb_open(&ACCESS_FBINFO(fbcon), user);
+		if (err) {
+			return err;
 		}
 	}
 	return 0;
@@ -348,11 +354,13 @@
 
 static int matroxfb_dh_release(struct fb_info* info, int user) {
 #define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
+	int err = 0;
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
+		err = ACCESS_FBINFO(fbcon.fbops)->fb_release(&ACCESS_FBINFO(fbcon), user);
 	}
-	return 0;
+	return err;
 #undef m2info
 }
 
@@ -544,13 +552,19 @@
 static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
 #define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
-	if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
-	    var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+	struct display* dsp;
+
+	if (con < 0)
+		dsp = m2info->fbcon.disp;
+	else
+		dsp = fb_display + con;
+	if (var->xoffset + dsp->var.xres > dsp->var.xres_virtual ||
+	    var->yoffset + dsp->var.yres > dsp->var.yres_virtual)
 		return -EINVAL;
 	if (con == m2info->currcon)
 		matroxfb_dh_pan_var(m2info, var);
-	fb_display[con].var.xoffset = var->xoffset;
-	fb_display[con].var.yoffset = var->yoffset;
+	dsp->var.xoffset = var->xoffset;
+	dsp->var.yoffset = var->yoffset;
 	return 0;
 #undef m2info
 }
@@ -560,6 +574,7 @@
 static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) {
 	MINFO_FROM(m2info->primary_dev);
 
+	matroxfb_enable_irq(PMINFO 0);
 	memset(vblank, 0, sizeof(*vblank));
 	vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK;
 	/* mask out reserved bits + field number (odd/even) */
@@ -567,6 +582,12 @@
 	/* compatibility stuff */
 	if (vblank->vcount >= m2info->currcon_display->var.yres)
 		vblank->flags |= FB_VBLANK_VBLANKING;
+	if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
+		vblank->flags |= FB_VBLANK_HAVE_COUNT;
+		/* Only one writer, aligned int value...
+		   it should work without lock and without atomic_t */
+		vblank->count = ACCESS_FBINFO(crtc2).vsync.cnt;
+	}
 	return 0;
 }
 
@@ -594,6 +615,17 @@
 					return -EFAULT;
 				return 0;
 			}
+		case FBIO_WAITFORVSYNC:
+			{
+				u_int32_t crt;
+
+				if (get_user(crt, (u_int32_t *)arg))
+					return -EFAULT;
+
+				if (crt != 0)
+					return -ENODEV;
+				return matroxfb_wait_for_sync(PMINFO 1);
+			}
 		case MATROXFB_SET_OUTPUT_MODE:
 		case MATROXFB_GET_OUTPUT_MODE:
 		case MATROXFB_GET_ALL_OUTPUTS:
diff -urN linux-2.4.22-pre9/drivers/video/matrox/matroxfb_misc.c linux-2.4.22-pre10/drivers/video/matrox/matroxfb_misc.c
--- linux-2.4.22-pre9/drivers/video/matrox/matroxfb_misc.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/drivers/video/matrox/matroxfb_misc.c	2003-08-01 09:16:09.000000000 -0700
@@ -223,7 +223,7 @@
 
 int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) {
 	unsigned int hd, hs, he, hbe, ht;
-	unsigned int vd, vs, ve, vt;
+	unsigned int vd, vs, ve, vt, lc;
 	unsigned int wd;
 	unsigned int divider;
 	int i;
@@ -336,6 +336,7 @@
 	vs = m->VSyncStart - 1;
 	ve = m->VSyncEnd - 1;
 	vt = m->VTotal - 2;
+	lc = vd;
 	/* G200 cannot work with (ht & 7) == 6 */
 	if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
 		ht++;
@@ -367,7 +368,8 @@
 	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
 			  ((vd & 0x400) >>  8) |	/* disp end */
 			  ((vd & 0xC00) >>  7) |	/* vblanking start */
-			  ((vs & 0xC00) >>  5);
+			  ((vs & 0xC00) >>  5) |
+			  ((lc & 0x400) >>  3);
 	if (text)
 		hw->CRTCEXT[3] = 0x00;
 	else
@@ -387,12 +389,13 @@
 		      ((vd & 0x100) >> 7) |
 		      ((vs & 0x100) >> 6) |
 		      ((vd & 0x100) >> 5) |
-		      0x10                |
+		      ((lc & 0x100) >> 4) |
 		      ((vt & 0x200) >> 4) |
 		      ((vd & 0x200) >> 3) |
 		      ((vs & 0x200) >> 2);
 	hw->CRTC[8] = 0x00;
-	hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
+	hw->CRTC[9] = ((vd & 0x200) >> 4) |
+		      ((lc & 0x200) >> 3);
 	if (text)
 		hw->CRTC[9] |= fontheight(p) - 1;
 	if (m->dblscan && !m->interlaced)
@@ -417,7 +420,7 @@
 			hw->CRTC[20] = 0x1F;
 	} else
 		hw->CRTC[23] = 0xC3;
-	hw->CRTC[24] = 0xFF;
+	hw->CRTC[24] = lc;
 	return 0;
 };
 
diff -urN linux-2.4.22-pre9/fs/coda/dir.c linux-2.4.22-pre10/fs/coda/dir.c
--- linux-2.4.22-pre9/fs/coda/dir.c	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.22-pre10/fs/coda/dir.c	2003-08-01 09:16:09.000000000 -0700
@@ -79,6 +79,7 @@
 };
 
 struct file_operations coda_dir_operations = {
+	llseek:		generic_file_llseek,
 	read:		generic_read_dir,
 	readdir:	coda_readdir,
 	open:		coda_open,
@@ -507,7 +508,11 @@
 		ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
 	} else {
 		/* potemkin case: we were handed a directory inode */
-		ret = vfs_readdir(host_file, filldir, dirent);
+		/* We can't call vfs_readdir because we are already holding
+		 * the inode semaphore. */
+		ret = -ENOENT;
+		if (!IS_DEADDIR(host_file->f_dentry->d_inode))
+			ret = host_file->f_op->readdir(host_file, filldir, dirent);
 	}
 
 	coda_file->f_pos = host_file->f_pos;
diff -urN linux-2.4.22-pre9/fs/coda/file.c linux-2.4.22-pre10/fs/coda/file.c
--- linux-2.4.22-pre9/fs/coda/file.c	2002-08-02 17:39:45.000000000 -0700
+++ linux-2.4.22-pre10/fs/coda/file.c	2003-08-01 09:16:09.000000000 -0700
@@ -117,16 +117,18 @@
 	coda_vfs_stat.open++;
 
 	cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
-	if (!cfi) {
-		unlock_kernel();
+	if (!cfi)
 		return -ENOMEM;
-	}
 
 	lock_kernel();
 
 	error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
 			   &host_file); 
-	if (error || !host_file) {
+
+	if (!error && !host_file)
+		error = EBADF;
+
+	if (error) {
 		kfree(cfi);
 		unlock_kernel();
 		return error;
diff -urN linux-2.4.22-pre9/fs/jfs/super.c linux-2.4.22-pre10/fs/jfs/super.c
--- linux-2.4.22-pre9/fs/jfs/super.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/fs/jfs/super.c	2003-08-01 09:16:09.000000000 -0700
@@ -337,6 +337,7 @@
 	if (!(sb->s_flags & MS_RDONLY)) {
 		txQuiesce(sb);
 		lmLogShutdown(log);
+		updateSuper(sb, FM_CLEAN);
 	}
 }
 
@@ -347,6 +348,7 @@
 	int rc = 0;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
+		updateSuper(sb, FM_MOUNT);
 		if ((rc = lmLogInit(log)))
 			jfs_err("jfs_unlock failed with return code %d", rc);
 		else
diff -urN linux-2.4.22-pre9/fs/namei.c linux-2.4.22-pre10/fs/namei.c
--- linux-2.4.22-pre9/fs/namei.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/fs/namei.c	2003-08-01 09:16:09.000000000 -0700
@@ -627,6 +627,8 @@
 			nd->last_type = LAST_DOT;
 		else if (this.len == 2 && this.name[1] == '.')
 			nd->last_type = LAST_DOTDOT;
+		else
+			goto return_base;
 return_reval:
 		/*
 		 * We bypassed the ordinary revalidation routines.
diff -urN linux-2.4.22-pre9/fs/nfs/nfsroot.c linux-2.4.22-pre10/fs/nfs/nfsroot.c
--- linux-2.4.22-pre9/fs/nfs/nfsroot.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/fs/nfs/nfsroot.c	2003-08-01 09:16:09.000000000 -0700
@@ -305,7 +305,7 @@
  */
 int __init nfs_root_setup(char *line)
 {
-	ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
+	ROOT_DEV = MKDEV(NFS_MAJOR, NFS_MINOR);
 	if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
 		strncpy(nfs_root_name, line, sizeof(nfs_root_name));
 		nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
diff -urN linux-2.4.22-pre9/fs/proc/base.c linux-2.4.22-pre10/fs/proc/base.c
--- linux-2.4.22-pre9/fs/proc/base.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/fs/proc/base.c	2003-08-01 09:16:09.000000000 -0700
@@ -124,20 +124,56 @@
 	return result;
 }
 
+#define MAY_PTRACE(task) \
+	(task == current || \
+	(task->p_pptr == current && \
+	(task->ptrace & PT_PTRACED) && task->state == TASK_STOPPED))
+
+static int may_ptrace_attach(struct task_struct *task)
+{
+	int retval = 0;
+
+	task_lock(task);
+
+	if (((current->uid != task->euid) ||
+	    (current->uid != task->suid) ||
+	    (current->uid != task->uid) ||
+	    (current->gid != task->egid) ||
+	    (current->gid != task->sgid) ||
+	    (!cap_issubset(task->cap_permitted, current->cap_permitted)) ||
+	    (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+		goto out;
+	rmb();
+	if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE))
+		goto out;
+
+	retval = 1;
+
+out:
+	task_unlock(task);
+	return retval;
+}
+
 static int proc_pid_environ(struct task_struct *task, char * buffer)
 {
 	struct mm_struct *mm;
 	int res = 0;
+
+	if (!may_ptrace_attach(task))
+		return -ESRCH;
+
 	task_lock(task);
 	mm = task->mm;
 	if (mm)
 		atomic_inc(&mm->mm_users);
 	task_unlock(task);
 	if (mm) {
-		int len = mm->env_end - mm->env_start;
+		unsigned int len = mm->env_end - mm->env_start;
 		if (len > PAGE_SIZE)
 			len = PAGE_SIZE;
 		res = access_process_vm(task, mm->env_start, buffer, len, 0);
+		if (!may_ptrace_attach(task))
+			res = -ESRCH;
 		mmput(mm);
 	}
 	return res;
@@ -328,10 +364,6 @@
 	read:		proc_info_read,
 };
 
-#define MAY_PTRACE(p) \
-(p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED))
-
-
 static int mem_open(struct inode* inode, struct file* file)
 {
 	file->private_data = (void*)((long)current->self_exec_id);
@@ -347,8 +379,7 @@
 	int copied = 0;
 	struct mm_struct *mm;
 
-
-	if (!MAY_PTRACE(task))
+	if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
 		return -ESRCH;
 
 	page = (char *)__get_free_page(GFP_USER);
@@ -370,14 +401,13 @@
 		copied = -EIO;
 		goto out_free;
 	}
-		
 
 	while (count > 0) {
 		int this_len, retval;
 
 		this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
 		retval = access_process_vm(task, src, page, this_len, 0);
-		if (!retval) {
+		if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) {
 			if (!copied)
 				copied = -EIO;
 			break;
@@ -411,7 +441,7 @@
 	struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
 	unsigned long dst = *ppos;
 
-	if (!MAY_PTRACE(task))
+	if (!MAY_PTRACE(task) || !may_ptrace_attach(task))
 		return -ESRCH;
 
 	page = (char *)__get_free_page(GFP_USER);
diff -urN linux-2.4.22-pre9/fs/proc/proc_misc.c linux-2.4.22-pre10/fs/proc/proc_misc.c
--- linux-2.4.22-pre9/fs/proc/proc_misc.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.22-pre10/fs/proc/proc_misc.c	2003-08-01 09:16:09.000000000 -0700
@@ -423,9 +423,9 @@
 				 int count, int *eof, void *data)
 {
 	extern char saved_command_line[];
-	int len;
+	int len = 0;
 
-	len = snprintf(page, count, "%s\n", saved_command_line);
+	proc_sprintf(page, &off, &len, "%s\n", saved_command_line);
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
@@ -495,7 +495,8 @@
 		buf++; p++; count--; read++;
 	}
 	pnt = (char *)prof_buffer + p - sizeof(unsigned int);
-	copy_to_user(buf,(void *)pnt,count);
+	if (copy_to_user(buf,(void *)pnt,count))
+		return -EFAULT;
 	read += count;
 	*ppos += read;
 	return read;
diff -urN linux-2.4.22-pre9/fs/reiserfs/super.c linux-2.4.22-pre10/fs/reiserfs/super.c
--- linux-2.4.22-pre9/fs/reiserfs/super.c	2003-08-01 09:16:00.000000000 -0700
+++ linux-2.4.22-pre10/fs/reiserfs/super.c	2003-08-01 09:16:09.000000000 -0700
@@ -284,7 +284,7 @@
     }
 
     /* body of "save" link */
-    link = cpu_to_le32 (INODE_PKEY (inode)->k_dir_id);
+    link = INODE_PKEY (inode)->k_dir_id;
 
     /* put "save" link inot tree */
     retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link);
diff -urN linux-2.4.22-pre9/include/asm-i386/hw_irq.h linux-2.4.22-pre10/include/asm-i386/hw_irq.h
--- linux-2.4.22-pre9/include/asm-i386/hw_irq.h	2001-11-22 11:46:18.000000000 -0800
+++ linux-2.4.22-pre10/include/asm-i386/hw_irq.h	2003-08-01 09:16:10.000000000 -0700
@@ -13,8 +13,10 @@
  */
 
 #include <linux/config.h>
+#include <linux/smp_lock.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
+#include <asm/current.h>
 
 /*
  * IDT vectors usable for external interrupt sources start
@@ -213,7 +215,7 @@
 	atomic_inc((atomic_t *)&prof_buffer[eip]);
 }
 
-#ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
+#if defined(CONFIG_X86_IO_APIC)
 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
 	if (IO_APIC_IRQ(i))
 		send_IPI_self(IO_APIC_VECTOR(i));
diff -urN linux-2.4.22-pre9/include/linux/matroxfb.h linux-2.4.22-pre10/include/linux/matroxfb.h
--- linux-2.4.22-pre9/include/linux/matroxfb.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.22-pre10/include/linux/matroxfb.h	2003-08-01 09:16:12.000000000 -0700
@@ -76,5 +76,7 @@
 #define MATROXFB_G_TVOCTRL	_IOWR('V',27,struct matroxfb_control)
 #define MATROXFB_S_TVOCTRL	_IOW ('V',28,struct matroxfb_control)
 
+#define FBIO_WAITFORVSYNC	_IOW('F', 0x20, u_int32_t)
+
 #endif
 
diff -urN linux-2.4.22-pre9/include/linux/ncp.h linux-2.4.22-pre10/include/linux/ncp.h
--- linux-2.4.22-pre9/include/linux/ncp.h	2001-11-22 11:46:18.000000000 -0800
+++ linux-2.4.22-pre10/include/linux/ncp.h	2003-08-01 09:16:12.000000000 -0700
@@ -44,7 +44,7 @@
 };
 
 #define NCP_VOLNAME_LEN (16)
-#define NCP_NUMBER_OF_VOLUMES (64)
+#define NCP_NUMBER_OF_VOLUMES (256)
 struct ncp_volume_info {
 	__u32 total_blocks;
 	__u32 free_blocks;
diff -urN linux-2.4.22-pre9/include/linux/nfs.h linux-2.4.22-pre10/include/linux/nfs.h
--- linux-2.4.22-pre9/include/linux/nfs.h	2000-04-01 08:04:27.000000000 -0800
+++ linux-2.4.22-pre10/include/linux/nfs.h	2003-08-01 09:16:13.000000000 -0700
@@ -30,6 +30,9 @@
 #define NFS_MNT_PROGRAM	100005
 #define NFS_MNT_PORT	627
 
+#define NFS_MAJOR   	UNNAMED_MAJOR
+#define NFS_MINOR   	0xff
+
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
diff -urN linux-2.4.22-pre9/include/linux/sunrpc/xprt.h linux-2.4.22-pre10/include/linux/sunrpc/xprt.h
--- linux-2.4.22-pre9/include/linux/sunrpc/xprt.h	2003-08-01 09:16:03.000000000 -0700
+++ linux-2.4.22-pre10/include/linux/sunrpc/xprt.h	2003-08-01 09:16:13.000000000 -0700
@@ -98,6 +98,10 @@
 
 	struct list_head	rq_list;
 
+	struct xdr_buf		rq_private_buf;		/* The receive buffer
+							 * used in the softirq.
+							 */
+
 	/*
 	 * For authentication (e.g. auth_des)
 	 */
diff -urN linux-2.4.22-pre9/init/do_mounts.c linux-2.4.22-pre10/init/do_mounts.c
--- linux-2.4.22-pre9/init/do_mounts.c	2003-08-01 09:16:03.000000000 -0700
+++ linux-2.4.22-pre10/init/do_mounts.c	2003-08-01 09:16:13.000000000 -0700
@@ -88,7 +88,7 @@
 	const char *name;
 	const int num;
 } root_dev_names[] __initdata = {
-	{ "nfs",     0x00ff },
+	{ "nfs",     MKDEV(NFS_MAJOR, NFS_MINOR) },
 	{ "hda",     0x0300 },
 	{ "hdb",     0x0340 },
 	{ "loop",    0x0700 },
@@ -759,7 +759,8 @@
 static void __init mount_root(void)
 {
 #ifdef CONFIG_ROOT_NFS
-	if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
+       if (MAJOR(ROOT_DEV) == NFS_MAJOR
+           && MINOR(ROOT_DEV) == NFS_MINOR) {
 		if (mount_nfs_root()) {
 			sys_chdir("/root");
 			ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
diff -urN linux-2.4.22-pre9/kernel/sysctl.c linux-2.4.22-pre10/kernel/sysctl.c
--- linux-2.4.22-pre9/kernel/sysctl.c	2003-08-01 09:16:04.000000000 -0700
+++ linux-2.4.22-pre10/kernel/sysctl.c	2003-08-01 09:16:13.000000000 -0700
@@ -474,7 +474,8 @@
 	 * zero, proceed with automatic r/w */
 	if (table->data && table->maxlen) {
 		if (oldval && oldlenp) {
-			get_user(len, oldlenp);
+			if (get_user(len, oldlenp))
+				return -EFAULT;
 			if (len) {
 				if (len > table->maxlen)
 					len = table->maxlen;
@@ -765,7 +766,7 @@
 		len = 0;
 		p = buffer;
 		while (len < *lenp) {
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (c == 0 || c == '\n')
 				break;
@@ -848,7 +849,7 @@
 		if (write) {
 			while (left) {
 				char c;
-				if(get_user(c,(char *) buffer))
+				if (get_user(c, (char *) buffer))
 					return -EFAULT;
 				if (!isspace(c))
 					break;
@@ -914,7 +915,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1001,7 +1002,7 @@
 		if (write) {
 			while (left) {
 				char c;
-				if(get_user(c, (char *) buffer))
+				if (get_user(c, (char *) buffer))
 					return -EFAULT;
 				if (!isspace(c))
 					break;
@@ -1060,7 +1061,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1102,7 +1103,7 @@
 		if (write) {
 			while (left) {
 				char c;
-				if(get_user(c, (char *) buffer))
+				if (get_user(c, (char *) buffer))
 					return -EFAULT;
 				if (!isspace(c))
 					break;
@@ -1165,7 +1166,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1319,7 +1320,7 @@
 		return -ENOTDIR;
 	
 	if (oldval && oldlenp) {
-		if(get_user(len, oldlenp))
+		if (get_user(len, oldlenp))
 			return -EFAULT;
 		if (len) {
 			l = strlen(table->data);
@@ -1376,7 +1377,8 @@
 
 		for (i = 0; i < length; i++) {
 			int value;
-			get_user(value, vec + i);
+			if (get_user(value, vec + i))
+				return -EFAULT;
 			if (min && value < min[i])
 				return -EINVAL;
 			if (max && value > max[i])
diff -urN linux-2.4.22-pre9/net/ipv4/ipconfig.c linux-2.4.22-pre10/net/ipv4/ipconfig.c
--- linux-2.4.22-pre9/net/ipv4/ipconfig.c	2003-08-01 09:16:04.000000000 -0700
+++ linux-2.4.22-pre10/net/ipv4/ipconfig.c	2003-08-01 09:16:14.000000000 -0700
@@ -1234,7 +1234,7 @@
 			 * 				-- Chip
 			 */
 #ifdef CONFIG_ROOT_NFS
-			if (ROOT_DEV == MKDEV(UNNAMED_MAJOR, 255)) {
+			if (ROOT_DEV == MKDEV(NFS_MAJOR, NFS_MINOR)) {
 				printk(KERN_ERR 
 					"IP-Config: Retrying forever (NFS root)...\n");
 				goto try_try_again;
diff -urN linux-2.4.22-pre9/net/sunrpc/clnt.c linux-2.4.22-pre10/net/sunrpc/clnt.c
--- linux-2.4.22-pre9/net/sunrpc/clnt.c	2003-08-01 09:16:04.000000000 -0700
+++ linux-2.4.22-pre10/net/sunrpc/clnt.c	2003-08-01 09:16:14.000000000 -0700
@@ -646,7 +646,8 @@
 	struct rpc_rqst	*req = task->tk_rqstp;
 	int		status;
 
-	if (req->rq_received != 0)
+	smp_rmb();
+	if (req->rq_received > 0 && !req->rq_bytes_sent)
 		task->tk_status = req->rq_received;
 
 	dprintk("RPC: %4d call_status (status %d)\n", 
@@ -754,17 +755,23 @@
 		if (!clnt->cl_softrtry) {
 			task->tk_action = call_transmit;
 			clnt->cl_stats->rpcretrans++;
-		} else {
-			printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
-				clnt->cl_protname, task->tk_status);
-			rpc_exit(task, -EIO);
+			goto out_retry;
 		}
+		printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
+			clnt->cl_protname, task->tk_status);
+		rpc_exit(task, -EIO);
 		return;
 	}
 
+	/* Check that the softirq receive buffer is valid */
+	if (unlikely(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
+				sizeof(req->rq_rcv_buf)) != 0))
+		printk(KERN_WARNING "%s: receive buffer is inconsistent. Please contact maintainer.\n",
+				__FUNCTION__);
+
 	/* Verify the RPC header */
 	if (!(p = call_verify(task)))
-		return;
+		goto out_retry;
 
 	/*
 	 * The following is an NFS-specific hack to cater for setuid
@@ -777,7 +784,7 @@
 			task->tk_flags ^= RPC_CALL_REALUID;
 			task->tk_action = call_encode;
 			task->tk_suid_retry--;
-			return;
+			goto out_retry;
 		}
 	}
 
@@ -787,6 +794,10 @@
 		task->tk_status = decode(req, p, task->tk_msg.rpc_resp);
 	dprintk("RPC: %4d call_decode result %d\n", task->tk_pid,
 					task->tk_status);
+	return;
+out_retry:
+	req->rq_received = 0;
+	task->tk_status = 0;
 }
 
 /*
diff -urN linux-2.4.22-pre9/net/sunrpc/xdr.c linux-2.4.22-pre10/net/sunrpc/xdr.c
--- linux-2.4.22-pre9/net/sunrpc/xdr.c	2003-08-01 09:16:04.000000000 -0700
+++ linux-2.4.22-pre10/net/sunrpc/xdr.c	2003-08-01 09:16:14.000000000 -0700
@@ -180,7 +180,8 @@
 {
 	struct iovec	*iov = iov_base;
 	struct page	**ppage = xdr->pages;
-	unsigned int	len, pglen = xdr->page_len, first_kmap;
+	struct page	**first_kmap = NULL;
+	unsigned int	len, pglen = xdr->page_len;
 
 	len = xdr->head[0].iov_len;
 	if (base < len) {
@@ -203,16 +204,15 @@
 		ppage += base >> PAGE_CACHE_SHIFT;
 		base &= ~PAGE_CACHE_MASK;
 	}
-	first_kmap = 1;
 	do {
 		len = PAGE_CACHE_SIZE;
-		if (first_kmap) {
-			first_kmap = 0;
+		if (!first_kmap) {
+			first_kmap = ppage;
 			iov->iov_base = kmap(*ppage);
 		} else {
 			iov->iov_base = kmap_nonblock(*ppage);
 			if (!iov->iov_base)
-				goto out;
+				goto out_err;
 		}
 		if (base) {
 			iov->iov_base += base;
@@ -233,6 +233,10 @@
 	}
  out:
 	return (iov - iov_base);
+out_err:
+	for (; first_kmap != ppage; first_kmap++)
+		kunmap(*first_kmap);
+	return 0;
 }
 
 void xdr_kunmap(struct xdr_buf *xdr, unsigned int base, int niov)
diff -urN linux-2.4.22-pre9/net/sunrpc/xprt.c linux-2.4.22-pre10/net/sunrpc/xprt.c
--- linux-2.4.22-pre9/net/sunrpc/xprt.c	2003-08-01 09:16:04.000000000 -0700
+++ linux-2.4.22-pre10/net/sunrpc/xprt.c	2003-08-01 09:16:14.000000000 -0700
@@ -237,6 +237,10 @@
 		unsigned int slen_part, n;
 
 		niov = xdr_kmap(niv, xdr, skip);
+		if (!niov) {
+			result = -EAGAIN;
+			break;
+		}
 
 		msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
 		msg.msg_iov	= niv;
@@ -726,11 +730,11 @@
 	xprt_pktdump("packet data:",
 		     (u32 *) (skb->h.raw+sizeof(struct udphdr)), repsize);
 
-	if ((copied = rovr->rq_rlen) > repsize)
+	if ((copied = rovr->rq_private_buf.len) > repsize)
 		copied = repsize;
 
 	/* Suck it into the iovec, verify checksum if not done by hw. */
-	if (csum_partial_copy_to_xdr(&rovr->rq_rcv_buf, skb))
+	if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb))
 		goto out_unlock;
 
 	/* Something worked... */
@@ -852,7 +856,7 @@
 		return;
 	}
 
-	rcvbuf = &req->rq_rcv_buf;
+	rcvbuf = &req->rq_private_buf;
 	len = desc->count;
 	if (len > xprt->tcp_reclen - xprt->tcp_offset) {
 		skb_reader_t my_desc;
@@ -870,7 +874,7 @@
 	xprt->tcp_copied += len;
 	xprt->tcp_offset += len;
 
-	if (xprt->tcp_copied == req->rq_rlen)
+	if (xprt->tcp_copied == req->rq_private_buf.len)
 		xprt->tcp_flags &= ~XPRT_COPY_DATA;
 	else if (xprt->tcp_offset == xprt->tcp_reclen) {
 		if (xprt->tcp_flags & XPRT_LAST_FRAG)
@@ -1102,6 +1106,9 @@
 	}
 
 	spin_lock_bh(&xprt->sock_lock);
+	if (req->rq_received != 0 && !req->rq_bytes_sent)
+		goto out_notrans;
+
 	if (!__xprt_lock_write(xprt, task))
 		goto out_notrans;
 
@@ -1111,8 +1118,10 @@
 	}
 
 	if (list_empty(&req->rq_list)) {
+		/* Update the softirq receive buffer */
+		memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
+				sizeof(req->rq_private_buf));
 		list_add_tail(&req->rq_list, &xprt->recv);
-		req->rq_received = 0;
 	}
 	spin_unlock_bh(&xprt->sock_lock);
 
@@ -1145,8 +1154,12 @@
 		if (xprt->stream) {
 			req->rq_bytes_sent += status;
 
-			if (req->rq_bytes_sent >= req->rq_slen)
+			/* If we've sent the entire packet, immediately
+			 * reset the count of bytes sent. */
+			if (req->rq_bytes_sent >= req->rq_slen) {
+				req->rq_bytes_sent = 0;
 				goto out_receive;
+			}
 		} else {
 			if (status >= req->rq_slen)
 				goto out_receive;
@@ -1168,9 +1181,6 @@
 	 * Note, though, that we can't do this if we've already started
 	 * resending down a TCP stream.
 	 */
-	if (req->rq_received && !req->rq_bytes_sent)
-		goto out_release;
-
 	task->tk_status = status;
 
 	switch (status) {
@@ -1200,7 +1210,6 @@
 		if (xprt->stream)
 			xprt_disconnect(xprt);
 	}
- out_release:
 	xprt_release_write(xprt, task);
 	return;
  out_receive:
