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

diff -urN linux-2.4.20-rc1/CREDITS linux-2.4.20-rc2/CREDITS
--- linux-2.4.20-rc1/CREDITS	Fri Nov 15 10:08:22 2002
+++ linux-2.4.20-rc2/CREDITS	Fri Nov 15 10:08:41 2002
@@ -2346,8 +2346,8 @@
 D: modularized BSD Unix domain sockets
 
 N: Martin Kasper Petersen
-E: mkp@linuxcare.com
 E: mkp@mkp.net
+D: forte FM801 audio driver
 D: PA-RISC port
 D: XFS file system
 D: kiobuf based block I/O work
diff -urN linux-2.4.20-rc1/Makefile linux-2.4.20-rc2/Makefile
--- linux-2.4.20-rc1/Makefile	Fri Nov 15 10:08:22 2002
+++ linux-2.4.20-rc2/Makefile	Fri Nov 15 10:08:42 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 20
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.20-rc1/arch/i386/kernel/entry.S linux-2.4.20-rc2/arch/i386/kernel/entry.S
--- linux-2.4.20-rc1/arch/i386/kernel/entry.S	Fri Nov 15 10:08:23 2002
+++ linux-2.4.20-rc2/arch/i386/kernel/entry.S	Fri Nov 15 10:08:42 2002
@@ -63,7 +63,9 @@
 OLDSS		= 0x38
 
 CF_MASK		= 0x00000001
+TF_MASK		= 0x00000100
 IF_MASK		= 0x00000200
+DF_MASK		= 0x00000400
 NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
@@ -140,6 +142,9 @@
 	movl CS(%esp),%edx	# this is eip..
 	movl EFLAGS(%esp),%ecx	# and this is cs..
 	movl %eax,EFLAGS(%esp)	#
+	andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+	pushl %eax
+	popfl
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp,%ebx
@@ -161,6 +166,9 @@
 	movl CS(%esp),%edx	# this is eip..
 	movl EFLAGS(%esp),%ecx	# and this is cs..
 	movl %eax,EFLAGS(%esp)	#
+	andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+	pushl %eax
+	popfl
 	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
 	movl %ecx,CS(%esp)	#
 	movl %esp,%ebx
diff -urN linux-2.4.20-rc1/arch/ppc/kernel/ppc_ksyms.c linux-2.4.20-rc2/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.20-rc1/arch/ppc/kernel/ppc_ksyms.c	Fri Nov 15 10:08:25 2002
+++ linux-2.4.20-rc2/arch/ppc/kernel/ppc_ksyms.c	Fri Nov 15 10:08:43 2002
@@ -168,7 +168,7 @@
 EXPORT_SYMBOL(mm_ptov);
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
-	defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
+	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
 EXPORT_SYMBOL(ppc_ide_md);
 EXPORT_SYMBOL(ppc_generic_ide_fix_driveid);
 #endif
diff -urN linux-2.4.20-rc1/arch/sparc/mm/io-unit.c linux-2.4.20-rc2/arch/sparc/mm/io-unit.c
--- linux-2.4.20-rc1/arch/sparc/mm/io-unit.c	Sun Feb 18 19:49:54 2001
+++ linux-2.4.20-rc2/arch/sparc/mm/io-unit.c	Fri Nov 15 10:08:44 2002
@@ -130,7 +130,8 @@
 
 	/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
 	spin_lock_irqsave(&iounit->lock, flags);
-	for (; sz >= 0; sz--) {
+	while (sz != 0) {
+		sz--;
 		sg[sz].dvma_address = iounit_get_area(iounit, (unsigned long)sg[sz].address, sg[sz].length);
 		sg[sz].dvma_length = sg[sz].length;
 	}
@@ -158,7 +159,8 @@
 	struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
 
 	spin_lock_irqsave(&iounit->lock, flags);
-	for (; sz >= 0; sz--) {
+	while (sz != 0) {
+		--sz;
 		len = ((sg[sz].dvma_address & ~PAGE_MASK) + sg[sz].length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
 		vaddr = (sg[sz].dvma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
 		IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
diff -urN linux-2.4.20-rc1/arch/sparc/mm/iommu.c linux-2.4.20-rc2/arch/sparc/mm/iommu.c
--- linux-2.4.20-rc1/arch/sparc/mm/iommu.c	Fri Aug  2 17:39:43 2002
+++ linux-2.4.20-rc2/arch/sparc/mm/iommu.c	Fri Nov 15 10:08:44 2002
@@ -167,7 +167,8 @@
 
 static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 {
-	for (; sz >= 0; sz--) {
+	while (sz != 0) {
+		sz--;
 		sg[sz].dvma_address = (__u32) (sg[sz].address);
 		sg[sz].dvma_length = (__u32) (sg[sz].length);
 	}
@@ -176,7 +177,8 @@
 static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 {
 	flush_page_for_dma(0);
-	for (; sz >= 0; sz--) {
+	while (sz != 0) {
+		sz--;
 		sg[sz].dvma_address = (__u32) (sg[sz].address);
 		sg[sz].dvma_length = (__u32) (sg[sz].length);
 	}
@@ -187,6 +189,7 @@
 	unsigned long page, oldpage = 0;
 
 	while(sz >= 0) {
+		sz--;
 		page = ((unsigned long) sg[sz].address) & PAGE_MASK;
 		if (oldpage == page)
 			page += PAGE_SIZE; /* We flushed that page already */
@@ -196,7 +199,6 @@
 		}
 		sg[sz].dvma_address = (__u32) (sg[sz].address);
 		sg[sz].dvma_length = (__u32) (sg[sz].length);
-		sz--;
 		oldpage = page - PAGE_SIZE;
 	}
 }
diff -urN linux-2.4.20-rc1/arch/sparc/mm/sun4c.c linux-2.4.20-rc2/arch/sparc/mm/sun4c.c
--- linux-2.4.20-rc1/arch/sparc/mm/sun4c.c	Fri Nov 15 10:08:26 2002
+++ linux-2.4.20-rc2/arch/sparc/mm/sun4c.c	Fri Nov 15 10:08:44 2002
@@ -1226,10 +1226,10 @@
 
 static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 {
-	while (sz >= 0) {
+	while (sz != 0) {
+		sz--;
 		sg[sz].dvma_address = (__u32)sun4c_lockarea(sg[sz].address, sg[sz].length);
 		sg[sz].dvma_length = sg[sz].length;
-		sz--;
 	}
 }
 
@@ -1242,9 +1242,9 @@
 
 static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 {
-	while (sz >= 0) {
+	while (sz != 0) {
+		--sz;
 		sun4c_unlockarea((char *)sg[sz].dvma_address, sg[sz].length);
-		sz--;
 	}
 }
 
diff -urN linux-2.4.20-rc1/arch/sparc64/kernel/cpu.c linux-2.4.20-rc2/arch/sparc64/kernel/cpu.c
--- linux-2.4.20-rc1/arch/sparc64/kernel/cpu.c	Fri Nov 15 10:08:27 2002
+++ linux-2.4.20-rc2/arch/sparc64/kernel/cpu.c	Fri Nov 15 10:08:44 2002
@@ -31,7 +31,7 @@
  */
 struct cpu_fp_info linux_sparc_fpu[] = {
   { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
+  { 0x22, 0x10, 0, "UltraSparc I integrated FPU"},
   { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
   { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
@@ -43,7 +43,7 @@
 
 struct cpu_iu_info linux_sparc_chips[] = {
   { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x22, 0x10, "TI UltraSparc II  (BlackBird)"},
+  { 0x22, 0x10, "TI UltraSparc I   (SpitFire)"},
   { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x12, "TI UltraSparc IIi"},
   { 0x17, 0x13, "TI UltraSparc IIe"},
diff -urN linux-2.4.20-rc1/arch/sparc64/kernel/head.S linux-2.4.20-rc2/arch/sparc64/kernel/head.S
--- linux-2.4.20-rc1/arch/sparc64/kernel/head.S	Fri Nov 15 10:08:27 2002
+++ linux-2.4.20-rc2/arch/sparc64/kernel/head.S	Fri Nov 15 10:08:44 2002
@@ -485,7 +485,7 @@
 	membar	#Sync
 
 	mov	2, %g2		/* Set TLB type to cheetah+. */
-	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g5,g2,1f)
+	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g5,g7,1f)
 
 	mov	1, %g2		/* Set TLB type to cheetah. */
 
diff -urN linux-2.4.20-rc1/arch/sparc64/kernel/ioctl32.c linux-2.4.20-rc2/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.20-rc1/arch/sparc64/kernel/ioctl32.c	Fri Nov 15 10:08:27 2002
+++ linux-2.4.20-rc2/arch/sparc64/kernel/ioctl32.c	Fri Nov 15 10:08:44 2002
@@ -3217,7 +3217,7 @@
 }
 #endif
 
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+#if defined(CONFIG_DRM_NEW) || defined(CONFIG_DRM_NEW_MODULE)
 /* This really belongs in include/linux/drm.h -DaveM */
 #include "../../../drivers/char/drm/drm.h"
 
@@ -4930,7 +4930,7 @@
 COMPATIBLE_IOCTL(LV_BMAP)
 COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+#if defined(CONFIG_DRM_NEW) || defined(CONFIG_DRM_NEW_MODULE)
 COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
 COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
 COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
@@ -5189,7 +5189,7 @@
 HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+#if defined(CONFIG_DRM_NEW) || defined(CONFIG_DRM_NEW_MODULE)
 HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version)
 HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique)
 HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique)
diff -urN linux-2.4.20-rc1/arch/sparc64/kernel/sys32.S linux-2.4.20-rc2/arch/sparc64/kernel/sys32.S
--- linux-2.4.20-rc1/arch/sparc64/kernel/sys32.S	Mon Mar 27 10:35:56 2000
+++ linux-2.4.20-rc2/arch/sparc64/kernel/sys32.S	Fri Nov 15 10:08:44 2002
@@ -42,7 +42,7 @@
 	 and		%o2, %g2, %o2
 
 	.align		32
-	.globl		sys32_sendto, sys32_recvfrom, sys32_getsockopt
+	.globl		sys32_sendto, sys32_recvfrom
 sys32_sendto:
 	sethi		%hi(sys_sendto), %g1
 	jmpl		%g1 + %lo(sys_sendto), %g0
@@ -52,10 +52,6 @@
 	sethi		%hi(sys_recvfrom), %g1
 	jmpl		%g1 + %lo(sys_recvfrom), %g0
 	 srl		%o5, 0, %o5
-sys32_getsockopt:
-	sethi		%hi(sys_getsockopt), %g1
-	jmpl		%g1 + %lo(sys_getsockopt), %g0
-	 srl		%o4, 0, %o4
 
 	.globl		sys32_bdflush
 sys32_bdflush:
diff -urN linux-2.4.20-rc1/arch/sparc64/kernel/sys_sparc32.c linux-2.4.20-rc2/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.20-rc1/arch/sparc64/kernel/sys_sparc32.c	Fri Nov 15 10:08:27 2002
+++ linux-2.4.20-rc2/arch/sparc64/kernel/sys_sparc32.c	Fri Nov 15 10:08:44 2002
@@ -2847,12 +2847,34 @@
 	return ret;
 }
 
+static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int optlen)
+{
+	struct timeval32 *up = (struct timeval32 *) optval;
+	struct timeval ktime;
+	mm_segment_t old_fs;
+	int err;
+
+	if (optlen < sizeof(*up))
+		return -EINVAL;
+	if (get_user(ktime.tv_sec, &up->tv_sec) ||
+	    __get_user(ktime.tv_usec, &up->tv_usec))
+		return -EFAULT;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_setsockopt(fd, level, optname, (char *) &ktime, sizeof(ktime));
+	set_fs(old_fs);
+
+	return err;
+}
+
 asmlinkage int sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
 	if (optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname,
 					    optval, optlen);
+	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+		return do_set_sock_timeout(fd, level, optname, optval, optlen);
 	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
 		return do_set_icmpv6_filter(fd, level, optname,
 					    optval, optlen);
@@ -2860,6 +2882,43 @@
 	return sys_setsockopt(fd, level, optname, optval, optlen);
 }
 
+extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
+				      char *optval, int *optlen);
+
+static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int *optlen)
+{
+	struct timeval32 *up = (struct timeval32 *) optval;
+	struct timeval ktime;
+	mm_segment_t old_fs;
+	int len, err;
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+	if (len < sizeof(*up))
+		return -EINVAL;
+	len = sizeof(ktime);
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_getsockopt(fd, level, optname, (char *) &ktime, &len);
+	set_fs(old_fs);
+
+	if (!err) {
+		if (put_user(sizeof(*up), optlen) ||
+		    put_user(ktime.tv_sec, &up->tv_sec) ||
+		    __put_user(ktime.tv_usec, &up->tv_usec))
+			err = -EFAULT;
+	}
+	return err;
+}
+
+asmlinkage int sys32_getsockopt(int fd, int level, int optname,
+				char *optval, int *optlen)
+{
+	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+		return do_get_sock_timeout(fd, level, optname, optval, optlen);
+	return sys_getsockopt(fd, level, optname, optval, optlen);
+}
+
 extern void check_pending(int signum);
 
 asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
diff -urN linux-2.4.20-rc1/arch/sparc64/kernel/traps.c linux-2.4.20-rc2/arch/sparc64/kernel/traps.c
--- linux-2.4.20-rc1/arch/sparc64/kernel/traps.c	Fri Nov 15 10:08:27 2002
+++ linux-2.4.20-rc2/arch/sparc64/kernel/traps.c	Fri Nov 15 10:08:44 2002
@@ -1491,6 +1491,8 @@
 {
 	siginfo_t info;
 
+	if (regs->tstate & TSTATE_PRIV)
+		die_if_kernel("TL0: Kernel divide by zero.", regs);
 	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
diff -urN linux-2.4.20-rc1/drivers/char/Config.in linux-2.4.20-rc2/drivers/char/Config.in
--- linux-2.4.20-rc1/drivers/char/Config.in	Fri Nov 15 10:08:27 2002
+++ linux-2.4.20-rc2/drivers/char/Config.in	Fri Nov 15 10:08:45 2002
@@ -150,7 +150,7 @@
 fi
 
 if [ "$CONFIG_PPC64" ] ; then 
-bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE
+   bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE
 fi
 
 source drivers/i2c/Config.in
@@ -246,6 +246,7 @@
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
    dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
 fi
+dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
 if [ "$CONFIG_IA64" = "y" ]; then
diff -urN linux-2.4.20-rc1/drivers/char/sx.c linux-2.4.20-rc2/drivers/char/sx.c
--- linux-2.4.20-rc1/drivers/char/sx.c	Fri Nov 15 10:08:27 2002
+++ linux-2.4.20-rc2/drivers/char/sx.c	Fri Nov 15 10:08:45 2002
@@ -2216,6 +2216,23 @@
 		}
 	}
 
+	/* Now we're pretty much convinced that there is an SI board here, 
+	   but to prevent trouble, we'd better double check that we don't
+	   have an SI1 board when we're probing for an SI2 board.... */
+
+	write_sx_byte (board, SI2_ISA_ID_BASE,0x10); 
+	if ( IS_SI1_BOARD(board)) {
+		/* This should be an SI1 board, which has this
+		   location writable... */
+		if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10)
+			return 0; 
+	} else {
+		/* This should be an SI2 board, which has the bottom
+		   3 bits non-writable... */
+		if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10)
+			return 0; 
+	}
+
 	printheader ();
 
 	printk (KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
diff -urN linux-2.4.20-rc1/drivers/ide/via82cxxx.c linux-2.4.20-rc2/drivers/ide/via82cxxx.c
--- linux-2.4.20-rc1/drivers/ide/via82cxxx.c	Fri Aug  2 17:39:44 2002
+++ linux-2.4.20-rc2/drivers/ide/via82cxxx.c	Fri Nov 15 10:08:46 2002
@@ -1,61 +1,24 @@
 /*
- * $Id: via82cxxx.c,v 3.34 2002/02/12 11:26:11 vojtech Exp $
+ * Version 3.35
  *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Michel Aubry
- *	Jeff Garzik
- *	Andre Hedrick
- */
-
-/*
- * VIA IDE driver for Linux. Supports
+ * VIA IDE driver for Linux. Supported southbridges:
  *
  *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a
- *
- * southbridges, which can be found in
- *
- *  VIA Apollo Master, VP, VP2, VP2/97, VP3, VPX, VPX/97, MVP3, MVP4, P6, Pro,
- *    ProII, ProPlus, Pro133, Pro133+, Pro133A, Pro133A Dual, Pro133T, Pro133Z,
- *    PLE133, PLE133T, Pro266, Pro266T, ProP4X266, PM601, PM133, PN133, PL133T,
- *    PX266, PM266, KX133, KT133, KT133A, KT133E, KLE133, KT266, KX266, KM133,
- *    KM133A, KL133, KN133, KM266
- *  PC-Chips VXPro, VXPro+, VXTwo, TXPro-III, TXPro-AGP, AGPPro, ViaGra, BXToo,
- *    BXTel, BXpert
- *  AMD 640, 640 AGP, 750 IronGate, 760, 760MP
- *  ETEQ 6618, 6628, 6629, 6638
- *  Micron Samurai
- *
- * chipsets. Supports
+ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ *   vt8235
  *
- *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-6
+ * Copyright (c) 2000-2002 Vojtech Pavlik
  *
- * (this includes UDMA33, 66, 100 and 133) modes. UDMA66 and higher modes are
- * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore
- * the BIOS data and assume the cable is present, use 'ide0=ata66' or
- * 'ide1=ata66' on the kernel command line.
+ * Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
  */
 
 /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #include <linux/config.h>
@@ -92,6 +55,10 @@
 #define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
 #define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
 
+#ifndef PCI_DEVICE_ID_VIA_8235
+#define PCI_DEVICE_ID_VIA_8235 0x3177
+#endif
+
 /*
  * VIA SouthBridge chips.
  */
@@ -105,8 +72,8 @@
 } via_isa_bridges[] = {
 #ifdef FUTURE_BRIDGES
 	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
 #endif
+	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
 	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
 	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
@@ -163,7 +130,7 @@
 
 	via_print("----------VIA BusMastering IDE Configuration----------------");
 
-	via_print("Driver Version:                     3.34");
+	via_print("Driver Version:                     3.35");
 	via_print("South Bridge:                       VIA %s", via_config->name);
 
 	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
diff -urN linux-2.4.20-rc1/drivers/net/sundance.c linux-2.4.20-rc2/drivers/net/sundance.c
--- linux-2.4.20-rc1/drivers/net/sundance.c	Fri Nov 15 10:08:28 2002
+++ linux-2.4.20-rc2/drivers/net/sundance.c	Fri Nov 15 10:08:47 2002
@@ -63,14 +63,20 @@
 	- Better rx buf size calculation (Donald Becker)
 
 	Version LK1.05 (D-Link):
-	- fix DFE-580TX packet drop issue
-	- fix reset_tx logic
+	- Fix DFE-580TX packet drop issue (for DL10050C)
+	- Fix reset_tx logic
+
+	Version LK1.06 (D-Link):
+	- Fix crash while unloading driver
+
+	Versin LK1.06b (D-Link):
+	- New tx scheme, adaptive tx_coalesce
 
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.01+LK1.05"
-#define DRV_RELDATE	"28-Sep-2002"
+#define DRV_VERSION	"1.01+LK1.06b"
+#define DRV_RELDATE	"6-Nov-2002"
 
 
 /* The user-configurable values.
@@ -87,7 +93,6 @@
    This chip can receive into offset buffers, so the Alpha does not
    need a copy-align. */
 static int rx_copybreak;
-static int tx_coalesce=1;
 static int flowctrl=1;
 
 /* media[] specifies the media type the NIC operates at.
@@ -114,7 +119,7 @@
    bonding and packet priority, and more than 128 requires modifying the
    Tx error recovery.
    Large receive rings merely waste memory. */
-#define TX_RING_SIZE	64
+#define TX_RING_SIZE	32
 #define TX_QUEUE_LEN	(TX_RING_SIZE - 1) /* Limit ring entries actually used.  */
 #define RX_RING_SIZE	64
 #define RX_BUDGET	32
@@ -459,7 +464,9 @@
 	unsigned int an_enable:1;
 	unsigned int speed;
 	struct tasklet_struct rx_tasklet;
+	struct tasklet_struct tx_tasklet;
 	int budget;
+	int cur_task;
 	/* Multicast and receive mode. */
 	spinlock_t mcastlock;			/* SMP lock multicast updates. */
 	u16 mcast_filter[4];
@@ -468,6 +475,7 @@
 	int mii_preamble_required;
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	struct pci_dev *pci_dev;
+	unsigned char pci_rev_id;
 };
 
 /* The station address location in the EEPROM. */
@@ -489,6 +497,7 @@
 static int reset_tx (struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static void rx_poll(unsigned long data);
+static void tx_poll(unsigned long data);
 static void refill_rx (struct net_device *dev);
 static void netdev_error(struct net_device *dev, int intr_status);
 static void netdev_error(struct net_device *dev, int intr_status);
@@ -557,6 +566,7 @@
 	np->msg_enable = (1 << debug) - 1;
 	spin_lock_init(&np->lock);
 	tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
+	tasklet_init(&np->tx_tasklet, tx_poll, (unsigned long)dev);
 
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
@@ -588,6 +598,8 @@
 	dev->change_mtu = &change_mtu;
 	pci_set_drvdata(pdev, dev);
 
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
+
 	i = register_netdev(dev);
 	if (i)
 		goto err_out_unmap_rx;
@@ -650,10 +662,6 @@
 				np->an_enable = 1;
 			}
 		}
-		if (tx_coalesce < 1)
-			tx_coalesce = 1;
-		else if (tx_coalesce > TX_QUEUE_LEN - 1)
-			tx_coalesce = TX_QUEUE_LEN - 1;
 		if (flowctrl == 0)
 			np->flowctrl = 0;
 	}
@@ -867,7 +875,8 @@
 	writeb(100, ioaddr + RxDMAPollPeriod);
 	writeb(127, ioaddr + TxDMAPollPeriod);
 	/* Fix DFE-580TX packet drop issue */
-	writeb(0x01, ioaddr + DebugCtrl1);
+	if (np->pci_rev_id >= 0x14)
+		writeb(0x01, ioaddr + DebugCtrl1);
 	netif_start_queue(dev);
 
 	writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
@@ -943,7 +952,9 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	long flag;
-
+	
+	netif_stop_queue(dev);
+	tasklet_disable(&np->tx_tasklet);
 	writew(0, ioaddr + IntrEnable);
 	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
 		   "TxFrameId %2.2x,"
@@ -952,31 +963,39 @@
 
 	{
 		int i;
-		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %8.8x", np->tx_ring[i].status);
-		printk("\n");
-		printk(KERN_DEBUG "cur_tx=%d dirty_tx=%d\n", np->cur_tx, np->dirty_tx);
+		for (i=0; i<TX_RING_SIZE; i++) {
+			printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
+				np->tx_ring_dma + i*sizeof(*np->tx_ring),	
+				np->tx_ring[i].next_desc,
+				np->tx_ring[i].status,
+				(np->tx_ring[i].status >> 2) & 0xff,
+				np->tx_ring[i].frag[0].addr, 
+				np->tx_ring[i].frag[0].length);
+		}
+		printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", 
+			readl(dev->base_addr + TxListPtr), 
+			netif_queue_stopped(dev));
+		printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", 
+			np->cur_tx, np->cur_tx % TX_RING_SIZE,
+			np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
 		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+		printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
 	}
 	spin_lock_irqsave(&np->lock, flag);
+
+	/* Stop and restart the chip's Tx processes . */
 	reset_tx(dev);
 	spin_unlock_irqrestore(&np->lock, flag);
 
-	/* Perhaps we should reinitialize the hardware here. */
 	dev->if_port = 0;
-	/* Stop and restart the chip's Tx processes . */
-
-	/* Trigger an immediate transmit demand. */
-	writew(DEFAULT_INTR, ioaddr + IntrEnable);
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
-	if (!netif_queue_stopped(dev))
+	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
 		netif_wake_queue(dev);
+	}
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
+	tasklet_enable(&np->tx_tasklet);
 }
 
 
@@ -988,6 +1007,7 @@
 
 	np->cur_rx = np->cur_tx = 0;
 	np->dirty_rx = np->dirty_tx = 0;
+	np->cur_task = 0;
 
 	np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16);
 
@@ -1022,39 +1042,57 @@
 	return;
 }
 
+static void tx_poll (unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	unsigned head = np->cur_task % TX_RING_SIZE;
+	struct netdev_desc *txdesc = 
+		&np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
+	
+	/* Chain the next pointer */
+	for (; np->cur_tx - np->cur_task > 0; np->cur_task++) {
+		int entry = np->cur_task % TX_RING_SIZE;
+		txdesc = &np->tx_ring[entry];
+		if (np->last_tx) {
+			np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
+				entry*sizeof(struct netdev_desc));
+		}
+		np->last_tx = txdesc;
+	}
+	/* Indicate the latest descriptor of tx ring */
+	txdesc->status |= cpu_to_le32(DescIntrOnTx);
+
+	if (readl (dev->base_addr + TxListPtr) == 0)
+		writel (np->tx_ring_dma + head * sizeof(struct netdev_desc),
+			dev->base_addr + TxListPtr);
+	return;
+}
+
 static int
 start_tx (struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	struct netdev_desc *txdesc;
 	unsigned entry;
-	long ioaddr = dev->base_addr;
 
-	/* Note: Ordering is important here, set the field with the
-	   "ownership" bit last, and only then increment cur_tx. */
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 	np->tx_skbuff[entry] = skb;
 	txdesc = &np->tx_ring[entry];
 
 	txdesc->next_desc = 0;
-	/* Note: disable the interrupt generation here before releasing. */
-	if (entry % tx_coalesce == 0) {
-		txdesc->status = cpu_to_le32 ((entry << 2) |
-				 DescIntrOnTx | DisableAlign);
-
-	} else {
-		txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
-	}
+	txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
 	txdesc->frag[0].addr = cpu_to_le32 (pci_map_single (np->pci_dev, skb->data,
 							skb->len,
 							PCI_DMA_TODEVICE));
 	txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
-	if (np->last_tx)
-		np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
-			entry*sizeof(struct netdev_desc));
-	np->last_tx = txdesc;
+
+	/* Increment cur_tx before tasklet_schedule() */
 	np->cur_tx++;
+	mb();
+	/* Schedule a tx_poll() task */
+	tasklet_schedule(&np->tx_tasklet);
 
 	/* On some architectures: explicitly flush cache lines here. */
 	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1
@@ -1063,23 +1101,16 @@
 	} else {
 		netif_stop_queue (dev);
 	}
-	/* Side effect: The read wakes the potentially-idle transmit channel. */
-	if (readl (dev->base_addr + TxListPtr) == 0)
-		writel (np->tx_ring_dma + entry*sizeof(*np->tx_ring),
-			dev->base_addr + TxListPtr);
-
 	dev->trans_start = jiffies;
-
 	if (netif_msg_tx_queued(np)) {
 		printk (KERN_DEBUG
 			"%s: Transmit frame #%d queued in slot %d.\n",
 			dev->name, np->cur_tx, entry);
 	}
-	if (tx_coalesce > 1)
-		writel (1000, ioaddr + DownCounter);
 	return 0;
 }
-/* Reset hardware tx and reset TxListPtr to TxFrameId */
+
+/* Reset hardware tx and free all of tx buffers */
 static int
 reset_tx (struct net_device *dev)
 {
@@ -1089,8 +1120,8 @@
 	int i;
 	int irq = in_interrupt();
 	
-	/* reset tx logic */
-	writel (0, dev->base_addr + TxListPtr);
+	/* Reset tx logic, TxListPtr will be cleaned */
+	writew (TxDisable, ioaddr + MACCtrl1);
 	writew (TxReset | DMAReset | FIFOReset | NetworkReset,
 			ioaddr + ASICCtrl + 2);
 	for (i=50; i > 0; i--) {
@@ -1114,11 +1145,13 @@
 		}
 	}
 	np->cur_tx = np->dirty_tx = 0;
+	np->cur_task = 0;
+	writew (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
 	return 0;
 }
 
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
+/* The interrupt handler cleans up after the Tx thread, 
+   and schedule a Rx thread work */
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
@@ -1126,6 +1159,8 @@
 	long ioaddr;
 	int boguscnt = max_interrupt_work;
 	int hw_frame_id;
+	int tx_cnt;
+	int tx_status;
 
 	ioaddr = dev->base_addr;
 	np = dev->priv;
@@ -1148,15 +1183,13 @@
 				np->budget = RX_BUDGET;
 			tasklet_schedule(&np->rx_tasklet);
 		}
-
 		if (intr_status & (IntrTxDone | IntrDrvRqst)) {
-			int boguscnt = 32;
-			int tx_status = readw (ioaddr + TxStatus);
-			while (tx_status & 0x80) {
+			tx_status = readw (ioaddr + TxStatus);
+			for (tx_cnt=32; tx_status & 0x80; --tx_cnt) {
 				if (netif_msg_tx_done(np))
 					printk
 					    ("%s: Transmit status is %2.2x.\n",
-					     dev->name, tx_status);
+				     	dev->name, tx_status);
 				if (tx_status & 0x1e) {
 					np->stats.tx_errors++;
 					if (tx_status & 0x10)
@@ -1179,35 +1212,62 @@
 				/* Yup, this is a documentation bug.  It cost me *hours*. */
 				writew (0, ioaddr + TxStatus);
 				tx_status = readw (ioaddr + TxStatus);
-				if (--boguscnt < 0)
+				if (tx_cnt < 0)
 					break;
 			}
+			hw_frame_id = (tx_status >> 8) & 0xff;
+		} else 	{
+			hw_frame_id = readb(ioaddr + TxFrameId);
 		}
-		spin_lock(&np->lock);
-		hw_frame_id = readb(ioaddr + TxFrameId);
-		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-			int entry = np->dirty_tx % TX_RING_SIZE;
-			struct sk_buff *skb;
-			int sw_frame_id;
-			sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff;
 			
-			if (sw_frame_id == hw_frame_id)
-				break;
-			skb = np->tx_skbuff[entry];
-			/* Free the original skb. */
-			pci_unmap_single(np->pci_dev,
-				np->tx_ring[entry].frag[0].addr,
-				skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_irq (np->tx_skbuff[entry]);
-			np->tx_skbuff[entry] = 0;
+		if (np->pci_rev_id >= 0x14) {	
+			spin_lock(&np->lock);
+			for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+				int entry = np->dirty_tx % TX_RING_SIZE;
+				struct sk_buff *skb;
+				int sw_frame_id;
+				sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff;
+					if (sw_frame_id == hw_frame_id &&
+						!(np->tx_ring[entry].status & 0x00010000))
+						break;
+					if (sw_frame_id == (hw_frame_id + 1) % TX_RING_SIZE)
+						break;
+				skb = np->tx_skbuff[entry];
+				/* Free the original skb. */
+				pci_unmap_single(np->pci_dev,
+					np->tx_ring[entry].frag[0].addr,
+					skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq (np->tx_skbuff[entry]);
+				np->tx_skbuff[entry] = 0;
+				np->tx_ring[entry].frag[0].addr = 0;
+				np->tx_ring[entry].frag[0].length = 0;
+			}
+			spin_unlock(&np->lock);
+		} else {
+			spin_lock(&np->lock);
+			for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+				int entry = np->dirty_tx % TX_RING_SIZE;
+				struct sk_buff *skb;
+				if (!(np->tx_ring[entry].status & 0x00010000))
+					break;
+				skb = np->tx_skbuff[entry];
+				/* Free the original skb. */
+				pci_unmap_single(np->pci_dev,
+					np->tx_ring[entry].frag[0].addr,
+					skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq (np->tx_skbuff[entry]);
+				np->tx_skbuff[entry] = 0;
+				np->tx_ring[entry].frag[0].addr = 0;
+				np->tx_ring[entry].frag[0].length = 0;
+			}
+			spin_unlock(&np->lock);
 		}
-		spin_unlock(&np->lock);
+		
 		if (netif_queue_stopped(dev) &&
 			np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-			/* The ring is no longer full, clear tbusy. */
+			/* The ring is no longer full, clear busy flag. */
 			netif_wake_queue (dev);
 		}
-
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
 			netdev_error(dev, intr_status);
@@ -1223,8 +1283,7 @@
 	if (netif_msg_intr(np))
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
-	if (np->cur_tx - np->dirty_tx > 0 && tx_coalesce > 1)
-		writel(100, ioaddr + DownCounter);
+	writel(5000, ioaddr + DownCounter);
 
 }
 
@@ -1246,7 +1305,7 @@
 		if (--boguscnt < 0) {
 			goto not_done;
 		}
-		if (!(desc->status & DescOwn))
+		if (!(frame_status & DescOwn))
 			break;
 		pkt_len = frame_status & 0x1fff;	/* Chip omits the CRC. */
 		if (netif_msg_rx_status(np))
@@ -1555,6 +1614,7 @@
 	struct netdev_private *np = dev->priv;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
 	int rc;
+	int i;
 
 	if (!netif_running(dev))
 		return -EINVAL;
@@ -1567,6 +1627,28 @@
 		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
 		spin_unlock_irq(&np->lock);
 	}
+	switch (cmd) {
+		case SIOCDEVPRIVATE:
+		for (i=0; i<TX_RING_SIZE; i++) {
+			printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
+				np->tx_ring_dma + i*sizeof(*np->tx_ring),	
+				np->tx_ring[i].next_desc,
+				np->tx_ring[i].status,
+				(np->tx_ring[i].status >> 2) & 0xff,
+				np->tx_ring[i].frag[0].addr, 
+				np->tx_ring[i].frag[0].length);
+		}
+		printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", 
+			readl(dev->base_addr + TxListPtr), 
+			netif_queue_stopped(dev));
+		printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", 
+			np->cur_tx, np->cur_tx % TX_RING_SIZE,
+			np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
+		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+		printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
+			return 0;
+	}
+				
 
 	return rc;
 }
@@ -1595,6 +1677,10 @@
 	/* Stop the chip's Tx and Rx processes. */
 	writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
 
+	/* Wait and kill tasklet */
+	tasklet_kill(&np->rx_tasklet);
+	tasklet_kill(&np->tx_tasklet);
+
 #ifdef __i386__
 	if (netif_msg_hw(np)) {
 		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
diff -urN linux-2.4.20-rc1/drivers/net/tg3.c linux-2.4.20-rc2/drivers/net/tg3.c
--- linux-2.4.20-rc1/drivers/net/tg3.c	Fri Nov 15 10:08:28 2002
+++ linux-2.4.20-rc2/drivers/net/tg3.c	Fri Nov 15 10:08:47 2002
@@ -59,8 +59,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.1"
-#define DRV_MODULE_RELDATE	"Aug 30, 2002"
+#define DRV_MODULE_VERSION	"1.2"
+#define DRV_MODULE_RELDATE	"Nov 14, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -2373,13 +2373,28 @@
 	/* No BH disabling for tx_lock here.  We are running in BH disabled
 	 * context and TX reclaim runs via tp->poll inside of a software
 	 * interrupt.  Rejoice!
+	 *
+	 * Actually, things are not so simple.  If we are to take a hw
+	 * IRQ here, we can deadlock, consider:
+	 *
+	 *       CPU1		CPU2
+	 *   tg3_start_xmit
+	 *   take tp->tx_lock
+	 *			tg3_timer
+	 *			take tp->lock
+	 *   tg3_interrupt
+	 *   spin on tp->lock
+	 *			spin on tp->tx_lock
+	 *
+	 * So we really do need to disable interrupts when taking
+	 * tx_lock here.
 	 */
-	spin_lock(&tp->tx_lock);
+	spin_lock_irq(&tp->tx_lock);
 
 	/* This is a hard error, log it. */
 	if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
 		netif_stop_queue(dev);
-		spin_unlock(&tp->tx_lock);
+		spin_unlock_irq(&tp->tx_lock);
 		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
 		       dev->name);
 		return 1;
@@ -2520,7 +2535,7 @@
 		netif_stop_queue(dev);
 
 out_unlock:
-	spin_unlock(&tp->tx_lock);
+	spin_unlock_irq(&tp->tx_lock);
 
 	dev->trans_start = jiffies;
 
@@ -2538,13 +2553,28 @@
 	/* No BH disabling for tx_lock here.  We are running in BH disabled
 	 * context and TX reclaim runs via tp->poll inside of a software
 	 * interrupt.  Rejoice!
+	 *
+	 * Actually, things are not so simple.  If we are to take a hw
+	 * IRQ here, we can deadlock, consider:
+	 *
+	 *       CPU1		CPU2
+	 *   tg3_start_xmit
+	 *   take tp->tx_lock
+	 *			tg3_timer
+	 *			take tp->lock
+	 *   tg3_interrupt
+	 *   spin on tp->lock
+	 *			spin on tp->tx_lock
+	 *
+	 * So we really do need to disable interrupts when taking
+	 * tx_lock here.
 	 */
-	spin_lock(&tp->tx_lock);
+	spin_lock_irq(&tp->tx_lock);
 
 	/* This is a hard error, log it. */
 	if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
 		netif_stop_queue(dev);
-		spin_unlock(&tp->tx_lock);
+		spin_unlock_irq(&tp->tx_lock);
 		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
 		       dev->name);
 		return 1;
@@ -2635,7 +2665,7 @@
 	if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
 		netif_stop_queue(dev);
 
-	spin_unlock(&tp->tx_lock);
+	spin_unlock_irq(&tp->tx_lock);
 
 	dev->trans_start = jiffies;
 
@@ -2699,7 +2729,7 @@
 				 pci_unmap_addr(rxp, mapping),
 				 RX_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb(rxp->skb);
+		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
 #if TG3_MINI_RING_WORKS
@@ -2712,7 +2742,7 @@
 				 pci_unmap_addr(rxp, mapping),
 				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb(rxp->skb);
+		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
 #endif
@@ -2725,7 +2755,7 @@
 				 pci_unmap_addr(rxp, mapping),
 				 RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb(rxp->skb);
+		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
 
diff -urN linux-2.4.20-rc1/drivers/net/tg3.h linux-2.4.20-rc2/drivers/net/tg3.h
--- linux-2.4.20-rc1/drivers/net/tg3.h	Fri Nov 15 10:08:28 2002
+++ linux-2.4.20-rc2/drivers/net/tg3.h	Fri Nov 15 10:08:47 2002
@@ -1528,7 +1528,7 @@
 	u32				__cookie3;
 };
 
-#define TG3_HW_STATUS_SIZE		0x80
+#define TG3_HW_STATUS_SIZE		0x50
 struct tg3_hw_status {
 	u32				status;
 #define SD_STATUS_UPDATED		0x00000001
diff -urN linux-2.4.20-rc1/drivers/usb/hid-input.c linux-2.4.20-rc2/drivers/usb/hid-input.c
--- linux-2.4.20-rc1/drivers/usb/hid-input.c	Fri Nov 15 10:08:29 2002
+++ linux-2.4.20-rc2/drivers/usb/hid-input.c	Sun Nov 11 10:09:37 2001
@@ -271,7 +271,7 @@
 	set_bit(usage->type, input->evbit);
 
 	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
-		usage->code = find_next_zero_bit(bit, usage->code, max + 1);
+		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
 	}
 
 	if (usage->code > max) return;
diff -urN linux-2.4.20-rc1/drivers/video/fbcon.c linux-2.4.20-rc2/drivers/video/fbcon.c
--- linux-2.4.20-rc1/drivers/video/fbcon.c	Fri Nov 15 10:08:29 2002
+++ linux-2.4.20-rc2/drivers/video/fbcon.c	Fri Nov 15 10:08:51 2002
@@ -1571,10 +1571,6 @@
 
     if (blank < 0)	/* Entering graphics mode */
 	return 0;
-#ifdef CONFIG_PM
-    if (fbcon_sleeping)
-    	return 0;
-#endif /* CONFIG_PM */
 
     fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);
 
diff -urN linux-2.4.20-rc1/fs/buffer.c linux-2.4.20-rc2/fs/buffer.c
--- linux-2.4.20-rc1/fs/buffer.c	Fri Nov 15 10:08:29 2002
+++ linux-2.4.20-rc2/fs/buffer.c	Fri Nov 15 10:08:52 2002
@@ -749,6 +749,7 @@
 	unsigned long flags;
 	struct buffer_head *tmp;
 	struct page *page;
+	int fullup = 1;
 
 	mark_buffer_uptodate(bh, uptodate);
 
@@ -775,8 +776,11 @@
 	unlock_buffer(bh);
 	tmp = bh->b_this_page;
 	while (tmp != bh) {
-		if (buffer_async(tmp) && buffer_locked(tmp))
-			goto still_busy;
+		if (buffer_locked(tmp)) {
+			if (buffer_async(tmp))
+				goto still_busy;
+		} else if (!buffer_uptodate(tmp))
+			fullup = 0;
 		tmp = tmp->b_this_page;
 	}
 
@@ -784,10 +788,10 @@
 	spin_unlock_irqrestore(&page_uptodate_lock, flags);
 
 	/*
-	 * if none of the buffers had errors then we can set the
-	 * page uptodate:
+	 * If none of the buffers had errors and all were uptodate
+	 * then we can set the page uptodate:
 	 */
-	if (!PageError(page))
+	if (fullup && !PageError(page))
 		SetPageUptodate(page);
 
 	UnlockPage(page);
diff -urN linux-2.4.20-rc1/fs/ext2/dir.c linux-2.4.20-rc2/fs/ext2/dir.c
--- linux-2.4.20-rc1/fs/ext2/dir.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-rc2/fs/ext2/dir.c	Fri Nov 15 10:08:52 2002
@@ -390,6 +390,7 @@
 	UnlockPage(page);
 	ext2_put_page(page);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 	mark_inode_dirty(dir);
 }
 
@@ -456,6 +457,7 @@
 	ext2_set_de_type (de, inode);
 	err = ext2_commit_chunk(page, from, to);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 	mark_inode_dirty(dir);
 	/* OFFSET_CACHE */
 out_unlock:
@@ -498,6 +500,7 @@
 	UnlockPage(page);
 	ext2_put_page(page);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	inode->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
 	mark_inode_dirty(inode);
 	return err;
 }
diff -urN linux-2.4.20-rc1/fs/ext2/ialloc.c linux-2.4.20-rc2/fs/ext2/ialloc.c
--- linux-2.4.20-rc1/fs/ext2/ialloc.c	Mon Feb 25 11:38:08 2002
+++ linux-2.4.20-rc2/fs/ext2/ialloc.c	Fri Nov 15 10:08:52 2002
@@ -386,7 +386,7 @@
 	inode->i_blocks = 0;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->u.ext2_i.i_new_inode = 1;
-	inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
+	inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags & ~EXT2_BTREE_FL;
 	if (S_ISLNK(mode))
 		inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
 	inode->u.ext2_i.i_block_group = group;
diff -urN linux-2.4.20-rc1/fs/ncpfs/dir.c linux-2.4.20-rc2/fs/ncpfs/dir.c
--- linux-2.4.20-rc1/fs/ncpfs/dir.c	Fri Nov 15 10:08:29 2002
+++ linux-2.4.20-rc2/fs/ncpfs/dir.c	Fri Nov 15 10:08:52 2002
@@ -846,7 +846,7 @@
 	if (S_ISREG(mode) && 
 	    (server->m.flags & NCP_MOUNT_EXTRAS) && 
 	    (mode & S_IXUGO))
-		attributes |= aSYSTEM;
+		attributes |= aSYSTEM | aSHARED;
 	
 	result = ncp_open_create_file_or_subdir(server, dir, __name,
 				OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
diff -urN linux-2.4.20-rc1/include/math-emu/op-4.h linux-2.4.20-rc2/include/math-emu/op-4.h
--- linux-2.4.20-rc1/include/math-emu/op-4.h	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20-rc2/include/math-emu/op-4.h	Fri Nov 15 10:08:53 2002
@@ -513,58 +513,84 @@
   (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
 
 #ifndef __FP_FRAC_ADD_3
-#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
-  (r0 = x0 + y0,							\
-   r1 = x1 + y1 + (r0 < x0),						\
-   r2 = x2 + y2 + (r1 < x1))
+#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)		\
+  do {								\
+    int _c1, _c2;							\
+    r0 = x0 + y0;						\
+    _c1 = r0 < x0;						\
+    r1 = x1 + y1;						\
+    _c2 = r1 < x1;						\
+    r1 += _c1;							\
+    _c2 |= r1 < _c1;						\
+    r2 = x2 + y2 + _c2;						\
+  } while (0)
 #endif
 
 #ifndef __FP_FRAC_ADD_4
-#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
-  (r0 = x0 + y0,							\
-   r1 = x1 + y1 + (r0 < x0),						\
-   r2 = x2 + y2 + (r1 < x1),						\
-   r3 = x3 + y3 + (r2 < x2))
+#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)	\
+  do {								\
+    int _c1, _c2, _c3;						\
+    r0 = x0 + y0;						\
+    _c1 = r0 < x0;						\
+    r1 = x1 + y1;						\
+    _c2 = r1 < x1;						\
+    r1 += _c1;							\
+    _c2 |= r1 < _c1;						\
+    r2 = x2 + y2;						\
+    _c3 = r2 < x2;						\
+    r2 += _c2;							\
+    _c3 |= r2 < _c2;						\
+    r3 = x3 + y3 + _c3;						\
+  } while (0)
 #endif
 
 #ifndef __FP_FRAC_SUB_3
-#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)			\
-  (r0 = x0 - y0,							\
-   r1 = x1 - y1 - (r0 > x0),						\
-   r2 = x2 - y2 - (r1 > x1))
+#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)		\
+  do {								\
+    int _c1, _c2;							\
+    r0 = x0 - y0;						\
+    _c1 = r0 > x0;						\
+    r1 = x1 - y1;						\
+    _c2 = r1 > x1;						\
+    r1 -= _c1;							\
+    _c2 |= r1 > _c1;						\
+    r2 = x2 - y2 - _c2;						\
+  } while (0)
 #endif
 
 #ifndef __FP_FRAC_SUB_4
-#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)		\
-  (r0 = x0 - y0,							\
-   r1 = x1 - y1 - (r0 > x0),						\
-   r2 = x2 - y2 - (r1 > x1),						\
-   r3 = x3 - y3 - (r2 > x2))
+#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)	\
+  do {								\
+    int _c1, _c2, _c3;						\
+    r0 = x0 - y0;						\
+    _c1 = r0 > x0;						\
+    r1 = x1 - y1;						\
+    _c2 = r1 > x1;						\
+    r1 -= _c1;							\
+    _c2 |= r1 > _c1;						\
+    r2 = x2 - y2;						\
+    _c3 = r2 > x2;						\
+    r2 -= _c2;							\
+    _c3 |= r2 > _c2;						\
+    r3 = x3 - y3 - _c3;						\
+  } while (0)
 #endif
 
 #ifndef __FP_FRAC_DEC_3
 #define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0)				\
   do {									\
-    UWtype _t0, _t1;							\
-    _t0 = x0;								\
-    x0 -= y0;								\
-    _t1 = x1;								\
-    x1 -= y1 + (x0 > _t0);						\
-    x2 -= y2 + (x1 > _t1);						\
+    UWtype _t0, _t1, _t2;						\
+    _t0 = x0, _t1 = x1, _t2 = x2;					\
+    __FP_FRAC_SUB_3 (x2, x1, x0, _t2, _t1, _t0, y2, y1, y0);		\
   } while (0)
 #endif
 
 #ifndef __FP_FRAC_DEC_4
 #define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0)			\
   do {									\
-    UWtype _t0, _t1;							\
-    _t0 = x0;								\
-    x0 -= y0;								\
-    _t1 = x1;								\
-    x1 -= y1 + (x0 > _t0);						\
-    _t0 = x2;								\
-    x2 -= y2 + (x1 > _t1);						\
-    x3 -= y3 + (x2 > _t0);						\
+    UWtype _t0, _t1, _t2, _t3;						\
+    _t0 = x0, _t1 = x1, _t2 = x2, _t3 = x3;				\
+    __FP_FRAC_SUB_4 (x3,x2,x1,x0,_t3,_t2,_t1,_t0, y3,y2,y1,y0);		\
   } while (0)
 #endif
 
diff -urN linux-2.4.20-rc1/net/ipv4/tcp_input.c linux-2.4.20-rc2/net/ipv4/tcp_input.c
--- linux-2.4.20-rc1/net/ipv4/tcp_input.c	Fri Nov 15 10:08:30 2002
+++ linux-2.4.20-rc2/net/ipv4/tcp_input.c	Fri Nov 15 10:08:53 2002
@@ -3305,10 +3305,6 @@
 				__set_current_state(TASK_RUNNING);
 
 				if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) {
-					__skb_pull(skb, tcp_header_len);
-					tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
-					NET_INC_STATS_BH(TCPHPHitsToUser);
-					eaten = 1;
 					/* Predicted packet is in window by definition.
 					 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
 					 * Hence, check seq<=rcv_wup reduces to:
@@ -3318,6 +3314,11 @@
 					     TCPOLEN_TSTAMP_ALIGNED) &&
 					    tp->rcv_nxt == tp->rcv_wup)
 						tcp_store_ts_recent(tp);
+
+					__skb_pull(skb, tcp_header_len);
+					tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+					NET_INC_STATS_BH(TCPHPHitsToUser);
+					eaten = 1;
 				}
 			}
 			if (!eaten) {
diff -urN linux-2.4.20-rc1/net/sunrpc/xdr.c linux-2.4.20-rc2/net/sunrpc/xdr.c
--- linux-2.4.20-rc1/net/sunrpc/xdr.c	Fri Nov 15 10:08:30 2002
+++ linux-2.4.20-rc2/net/sunrpc/xdr.c	Fri Nov 15 10:08:53 2002
@@ -244,6 +244,11 @@
 		pglen -= base;
 		base  += xdr->page_base;
 		ppage += base >> PAGE_CACHE_SHIFT;
+		/* Note: The offset means that the length of the first
+		 * page is really (PAGE_CACHE_SIZE - (base & ~PAGE_CACHE_MASK)).
+		 * In order to avoid an extra test inside the loop,
+		 * we bump pglen here, and just subtract PAGE_CACHE_SIZE... */
+		pglen += base & ~PAGE_CACHE_MASK;
 	}
 	for (;;) {
 		flush_dcache_page(*ppage);
diff -urN linux-2.4.20-rc1/net/sunrpc/xprt.c linux-2.4.20-rc2/net/sunrpc/xprt.c
--- linux-2.4.20-rc1/net/sunrpc/xprt.c	Fri Nov 15 10:08:30 2002
+++ linux-2.4.20-rc2/net/sunrpc/xprt.c	Fri Nov 15 10:08:53 2002
@@ -949,8 +949,10 @@
 }
 
 /*
- * The following 2 routines allow a task to sleep while socket memory is
- * low.
+ * Called when more output buffer space is available for this socket.
+ * We try not to wake our writers until they can make "significant"
+ * progress, otherwise we'll waste resources thrashing sock_sendmsg
+ * with a bunch of small requests.
  */
 static void
 xprt_write_space(struct sock *sk)
@@ -964,8 +966,15 @@
 		return;
 
 	/* Wait until we have enough socket memory */
-	if (!sock_writeable(sk))
-		return;
+	if (xprt->stream) {
+		/* from net/ipv4/tcp.c:tcp_write_space */
+		if (tcp_wspace(sk) < tcp_min_write_space(sk))
+			return;
+	} else {
+		/* from net/core/sock.c:sock_def_write_space */
+		if (!sock_writeable(sk))
+			return;
+	}
 
 	if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))
 		return;
