Merge mainline to 2.5.4-pre3
diff --git a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt
index 25c7195..684f54e 100644
--- a/Documentation/networking/8139too.txt
+++ b/Documentation/networking/8139too.txt
@@ -96,7 +96,10 @@
 KTI KF-230TX
 KTI KF-230TX/2
 Lantech FastNet TX
+Ovislink Fast Ethernet
+Planet ENW-9504 (V.4) 10/100
 SMC EZNET 10/100
+UNEX NexNIC ND012C
 
 (please add your adapter model to this list)
 
@@ -181,11 +184,18 @@
 Change History
 --------------
 
+Version 0.9.23 - In progress
+
+* New, compile-time conditional for testing better RX reset
+* Only account specific RX errors if rx_status is !OK
+
+
 Version 0.9.22 - November 8, 2001
 
 * Additional retries before aborting Tx
 * Do not write other TxConfig bits when writing clear-abort bit.
 * Ack TxErr intr status after each Tx abort, too.
+* Fix oops in interface restart
 
 
 Version 0.9.21 - November 1, 2001
diff --git a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt
index a3ca9ff..04b1803 100644
--- a/Documentation/networking/dl2k.txt
+++ b/Documentation/networking/dl2k.txt
@@ -1,7 +1,7 @@
 
     D-Link DL2000-based Gigabit Ethernet Adapter Installation
     for Linux
-    Nov 12, 2001
+    Jan 02, 2002
 
 Contents
 ========
@@ -182,7 +182,7 @@
 mtu=packet_size			- Specifies the maximum packet size. default
 				  is 1500.
 
-media=xxxxxxxxx			- Specifies the media type the NIC operates at.
+media=media_type		- Specifies the media type the NIC operates at.
 				  autosense	Autosensing active media.
 				  10mbps_hd	10Mbps half duplex.
 				  10mbps_fd	10Mbps full duplex.
@@ -195,28 +195,41 @@
 				  2		10Mbps full duplex.
 				  3		100Mbps half duplex.
 				  4		100Mbps full duplex.
-				  5          	1000Mbps full duplex.
-				  6          	1000Mbps half duplex.
+				  5          	1000Mbps half duplex.
+				  6          	1000Mbps full duplex.
 
 				  By default, the NIC operates at autosense.
 				  Note that only 1000mbps_fd and 1000mbps_hd
 				  types are available for fiber adapter.
 
-vlan=x				- Specifies the VLAN ID. If vlan=0, the
+vlan=[0|1]			- Specifies the VLAN ID. If vlan=0, the
 				  Virtual Local Area Network (VLAN) function is
 				  disable.
 
-jumbo=x				- Specifies the jumbo frame support. If jumbo=1,
+jumbo=[0|1]			- Specifies the jumbo frame support. If jumbo=1,
 				  the NIC accept jumbo frames. By default, this
 				  function is disabled.
 				  Jumbo frame usually improve the performance
 				  int gigabit.
 				  
-int_count			- Rx frame count each interrupt.
-int_timeout			- Rx DMA wait time for an interrupt. Proper 
-				  values of int_count and int_timeout bring 
-				  a conspicuous performance in the fast machine. 
-				  Ex. int_count=5 and int_timeout=750 
+rx_coalesce=n			- Rx frame count each interrupt.
+rx_timeout=n			- Rx DMA wait time for an interrupt. Proper 
+				  values of rx_coalesce and rx_timeout bring 
+				  a conspicuous performance in the fast machine.
+				  Ex. rx_coalesce=5 and rx_timeout=750 
+
+tx_coalesce=n			- Tx transmit count each TxComp interrupt.
+				  Setting value larger than 1 will improve 
+				  performance, but this is possible to lower 
+				  stability in slow UP machines. By default, 
+				  tx_coalesce=1. (dl2k)
+				  
+tx_flow=[1|0]			- Specifies the Tx flow control. If tx_flow=1, 
+				  the Tx flow control enable.
+				  
+rx_flow=[1|0]			- Specifies the Rx flow control. If rx_flow=1, 
+				  the Rx flow control enable.
+
 
 Configuration Script Sample
 ===========================
diff --git a/Makefile b/Makefile
index cd0b434..f1c5436 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 4
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 94a3c1a..58c0ee0 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -436,8 +436,8 @@
 
 static kdev_t srm_console_device(struct console *c)
 {
-  /* Huh? */
-        return MKDEV(TTY_MAJOR, 64 + c->index);
+	/* Huh? */
+        return mk_kdev(TTY_MAJOR, 64 + c->index);
 }
 
 static int __init srm_console_setup(struct console *co, char *options)
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index ca766f2..1aa7a84 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -196,8 +196,7 @@
  */
 out_of_memory:
 	if (current->pid == 1) {
-		current->policy |= SCHED_YIELD;
-		schedule();
+		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
 	}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 27ca507..65bfc86 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -43,6 +43,8 @@
 #include <linux/config.h>
 #include <linux/sys.h>
 #include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
 #include <asm/segment.h>
 #include <asm/smp.h>
 
@@ -67,24 +69,6 @@
 NT_MASK		= 0x00004000
 VM_MASK		= 0x00020000
 
-/*
- * these are offsets into the task-struct.
- */
-state		=  0
-flags		=  4
-work		=  8
-need_resched	= work+0
-syscall_trace	= work+1
-sigpending	= work+2
-notify_resume	= work+3
-addr_limit	= 12
-exec_domain	= 16
-tsk_ptrace	= 24
-cpu		= 32
-
-ENOSYS = 38
-
-
 #define SAVE_ALL \
 	cld; \
 	pushl %es; \
@@ -131,10 +115,6 @@
 	.long 3b,6b;	\
 .previous
 
-#define GET_CURRENT(reg) \
-	movl $-8192, reg; \
-	andl %esp, reg
-
 ENTRY(lcall7)
 	pushfl			# We get a different stack layout with call gates,
 	pushl %eax		# which has to be cleaned up later..
@@ -147,8 +127,8 @@
 	movl %ecx,CS(%esp)	#
 	movl %esp,%ebx
 	pushl %ebx
-	andl $-8192,%ebx	# GET_CURRENT
-	movl exec_domain(%ebx),%edx	# Get the execution domain
+	andl $-8192,%ebx	# GET_THREAD_INFO
+	movl TI_EXEC_DOMAIN(%ebx),%edx	# Get the execution domain
 	movl 4(%edx),%edx	# Get the lcall7 handler for the domain
 	pushl $0x7
 	call *%edx
@@ -168,8 +148,8 @@
 	movl %ecx,CS(%esp)	#
 	movl %esp,%ebx
 	pushl %ebx
-	andl $-8192,%ebx	# GET_CURRENT
-	movl exec_domain(%ebx),%edx	# Get the execution domain
+	andl $-8192,%ebx	# GET_THREAD_INFO
+	movl TI_EXEC_DOMAIN(%ebx),%edx	# Get the execution domain
 	movl 4(%edx),%edx	# Get the lcall7 handler for the domain
 	pushl $0x27
 	call *%edx
@@ -182,7 +162,7 @@
 	pushl %ebx
 	call SYMBOL_NAME(schedule_tail)
 	addl $4, %esp
-	GET_CURRENT(%ebx)
+	GET_THREAD_INFO(%ebx)
 	jmp syscall_exit
 
 /*
@@ -195,17 +175,17 @@
 	# userspace resumption stub bypassing syscall exit tracing
 	ALIGN
 ENTRY(ret_from_intr)
-	GET_CURRENT(%ebx)
+	GET_THREAD_INFO(%ebx)
 ret_from_exception:
 	movl EFLAGS(%esp),%eax		# mix EFLAGS and CS
 	movb CS(%esp),%al
 	testl $(VM_MASK | 3),%eax
 	jz restore_all			# returning to kernel-space or vm86-space
 ENTRY(resume_userspace)
-	cli				# make sure need_resched and sigpending don't change
-					# between sampling and the iret
-	movl work(%ebx),%ecx
-	andl $0xffff00ff,%ecx		# current->work (ignoring syscall_trace)
+ 	cli				# make sure we don't miss an interrupt setting need_resched
+ 					# or sigpending between sampling and the iret
+	movl TI_FLAGS(%ebx),%ecx
+	andl $_TIF_WORK_MASK,%ecx	# is there any work to be done on int/excp return?
 	jne work_pending
 	jmp restore_all
 
@@ -214,19 +194,19 @@
 ENTRY(system_call)
 	pushl %eax			# save orig_eax
 	SAVE_ALL
-	GET_CURRENT(%ebx)
+	GET_THREAD_INFO(%ebx)
 	cmpl $(NR_syscalls),%eax
 	jae syscall_badsys
-	testb $0xff,syscall_trace(%ebx)	# system call tracing in operation
+	testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebx)	# system call tracing in operation
 	jnz syscall_trace_entry
-syscall_traced:
+syscall_call:
 	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
 	movl %eax,EAX(%esp)		# store the return value
 syscall_exit:
-	cli				# make sure need_resched and sigpending don't change
-					# between sampling and the iret
-	movl work(%ebx),%ecx
-	testl %ecx,%ecx			# current->work
+ 	cli				# make sure we don't miss an interrupt setting need_resched
+ 					# or sigpending between sampling and the iret
+	movl TI_FLAGS(%ebx),%ecx
+	testw $_TIF_ALLWORK_MASK,%cx	# current->work
 	jne syscall_exit_work
 restore_all:
 	RESTORE_ALL
@@ -234,16 +214,16 @@
 	# perform work that needs to be done immediately before resumption
 	ALIGN
 work_pending:
-	testb %cl,%cl			# current->work.need_resched
+	testb $_TIF_NEED_RESCHED,%cl
 	jz work_notifysig
 work_resched:
 	call SYMBOL_NAME(schedule)
-	cli				# make sure need_resched and sigpending don't change
-					# between sampling and the iret
-	movl work(%ebx),%ecx
-	andl $0xffff00ff,%ecx		# ignore the syscall trace counter
+ 	cli				# make sure we don't miss an interrupt setting need_resched
+ 					# or sigpending between sampling and the iret
+	movl TI_FLAGS(%ebx),%ecx
+	andl $_TIF_WORK_MASK,%ecx	# is there any work to be done other than syscall tracing?
 	jz restore_all
-	testb %cl,%cl			# current->work.need_resched
+	testb $_TIF_NEED_RESCHED,%cl
 	jnz work_resched
 
 work_notifysig:				# deal with pending signals and notify-resume requests
@@ -273,13 +253,13 @@
 	call SYMBOL_NAME(do_syscall_trace)
 	movl ORIG_EAX(%esp),%eax
 	cmpl $(NR_syscalls),%eax
-	jnae syscall_traced
+	jnae syscall_call
 	jmp syscall_exit
 
 	# perform syscall exit tracing
 	ALIGN
 syscall_exit_work:
-	testb %ch,%ch			# current->work.syscall_trace
+	testb $_TIF_SYSCALL_TRACE,%cl
 	jz work_pending
 	sti				# could let do_syscall_trace() call schedule() instead
 	movl %esp,%eax
@@ -319,7 +299,7 @@
 	movl $(__KERNEL_DS),%edx
 	movl %edx,%ds
 	movl %edx,%es
-	GET_CURRENT(%ebx)
+	GET_THREAD_INFO(%ebx)
 	call *%edi
 	addl $8,%esp
 	jmp ret_from_exception
@@ -337,7 +317,7 @@
 ENTRY(device_not_available)
 	pushl $-1		# mark this as an int
 	SAVE_ALL
-	GET_CURRENT(%ebx)
+	GET_THREAD_INFO(%ebx)
 	movl %cr0,%eax
 	testl $0x4,%eax			# EM (math emulation bit)
 	jne device_not_available_emulate
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index b52e143..02e1953 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -320,7 +320,7 @@
 	ret
 
 ENTRY(stack_start)
-	.long SYMBOL_NAME(init_task_union)+8192
+	.long SYMBOL_NAME(init_thread_union)+8192
 	.long __KERNEL_DS
 
 /* This is the default interrupt "handler" :-) */
diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
index 0a2973c..0732fed 100644
--- a/arch/i386/kernel/i387.c
+++ b/arch/i386/kernel/i387.c
@@ -52,7 +52,7 @@
 		asm volatile( "fnsave %0 ; fwait"
 			      : "=m" (tsk->thread.i387.fsave) );
 	}
-	tsk->flags &= ~PF_USEDFPU;
+	clear_thread_flag(TIF_USEDFPU);
 }
 
 void save_init_fpu( struct task_struct *tsk )
@@ -65,7 +65,7 @@
 {
 	struct task_struct *tsk = current;
 
-	if (tsk->flags & PF_USEDFPU) {
+	if (test_thread_flag(TIF_USEDFPU)) {
 		__save_init_fpu(tsk);
 		return;
 	}
diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
index c7ace3b..d127032 100644
--- a/arch/i386/kernel/init_task.c
+++ b/arch/i386/kernel/init_task.c
@@ -13,15 +13,22 @@
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
- * Initial task structure.
+ * Initial thread structure.
  *
  * We need to make sure that this is 8192-byte aligned due to the
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
-union task_union init_task_union 
+union thread_union init_thread_union 
 	__attribute__((__section__(".data.init_task"))) =
-		{ INIT_TASK(init_task_union.task) };
+		{ INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
 
 /*
  * per-CPU TSS segments. Threads are completely 'soft' on Linux,
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 75637e6..ec7b8a5 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -220,7 +220,7 @@
 			continue;
 		}
 		esp &= ~(THREAD_SIZE-1);
-		esp += sizeof(struct task_struct);
+		esp += sizeof(struct thread_info);
 		show_stack((void*)esp);
  	}
 	printk("\nCPU %d:",cpu);
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index a732379..f91e5a3 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -263,8 +263,9 @@
 {
 
 	/*
-	 * Since current-> is always on the stack, and we always switch
-	 * the stack NMI-atomically, it's safe to use smp_processor_id().
+	 * Since current_thread_info()-> is always on the stack, and we
+	 * always switch the stack NMI-atomically, it's safe to use
+	 * smp_processor_id().
 	 */
 	int sum, cpu = smp_processor_id();
 
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 50bd8e2..b955ff2 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -102,15 +102,21 @@
 	 * Deal with another CPU just having chosen a thread to
 	 * run here:
 	 */
-	oldval = xchg(&current->work.need_resched, -1);
+	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
 
-	if (!oldval)
+	if (!oldval) {
+		set_thread_flag(TIF_POLLING_NRFLAG);
 		asm volatile(
 			"2:"
-			"cmpb $-1, %0;"
+			"testl %0, %1;"
 			"rep; nop;"
 			"je 2b;"
-				: :"m" (current->work.need_resched));
+			: : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
+
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+	} else {
+		set_need_resched();
+	}
 }
 
 /*
@@ -576,7 +582,7 @@
 {
 	struct pt_regs * childregs;
 
-	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
+	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
 	struct_cpy(childregs, regs);
 	childregs->eax = 0;
 	childregs->esp = esp;
@@ -674,6 +680,8 @@
 				 *next = &next_p->thread;
 	struct tss_struct *tss = init_tss + smp_processor_id();
 
+	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
+
 	unlazy_fpu(prev_p);
 
 	/*
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 96466d3..a6573e3 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -278,16 +278,10 @@
 		if ((unsigned long) data > _NSIG)
 			break;
 		if (request == PTRACE_SYSCALL) {
-			if (!(child->ptrace & PT_SYSCALLTRACE)) {
-				child->ptrace |= PT_SYSCALLTRACE;
-				child->work.syscall_trace++;
-			}
+			set_thread_flag(TIF_SYSCALL_TRACE);
 		}
 		else {
-			if (child->ptrace & PT_SYSCALLTRACE) {
-				child->ptrace &= ~PT_SYSCALLTRACE;
-				child->work.syscall_trace--;
-			}
+			clear_thread_flag(TIF_SYSCALL_TRACE);
 		}
 		child->exit_code = data;
 	/* make sure the single step bit is not set. */
@@ -323,10 +317,7 @@
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			break;
-		if (child->ptrace & PT_SYSCALLTRACE) {
-			child->ptrace &= ~PT_SYSCALLTRACE;
-			child->work.syscall_trace--;
-		}
+		clear_thread_flag(TIF_SYSCALL_TRACE);
 		if ((child->ptrace & PT_DTRACE) == 0) {
 			/* Spurious delayed TF traps may occur */
 			child->ptrace |= PT_DTRACE;
@@ -444,7 +435,7 @@
 		break;
 	}
 out_tsk:
-	free_task_struct(child);
+	put_task_struct(child);
 out:
 	unlock_kernel();
 	return ret;
@@ -456,8 +447,9 @@
 __attribute__((regparm(3)))
 void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
-	if ((current->ptrace & (PT_PTRACED|PT_SYSCALLTRACE)) !=
-	    (PT_PTRACED|PT_SYSCALLTRACE))
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (current->ptrace & PT_PTRACED)
 		return;
 	/* the 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
@@ -476,15 +468,3 @@
 		current->exit_code = 0;
 	}
 }
-
-/* notification of userspace execution resumption
- * - triggered by current->work.notify_resume
- */
-__attribute__((regparm(3)))
-void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
-		      struct task_work work_pending)
-{
-	/* deal with pending signal delivery */
-	if (work_pending.sigpending)
-		do_signal(regs,oldset);
-}
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 66871bc..691cd19 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -2817,7 +2817,7 @@
 	/*
 	 * Force FPU initialization:
 	 */
-	current->flags &= ~PF_USEDFPU;
+	clear_thread_flag(TIF_USEDFPU);
 	current->used_math = 0;
 	stts();
 }
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index f004ea3..fabd3cf 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -394,10 +394,10 @@
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
-	err |= __put_user((current->exec_domain
-		           && current->exec_domain->signal_invmap
+	err |= __put_user((current_thread_info()->exec_domain
+		           && current_thread_info()->exec_domain->signal_invmap
 		           && sig < 32
-		           ? current->exec_domain->signal_invmap[sig]
+		           ? current_thread_info()->exec_domain->signal_invmap[sig]
 		           : sig),
 		          &frame->sig);
 	if (err)
@@ -464,10 +464,10 @@
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
-	err |= __put_user((current->exec_domain
-		    	   && current->exec_domain->signal_invmap
+	err |= __put_user((current_thread_info()->exec_domain
+		    	   && current_thread_info()->exec_domain->signal_invmap
 		    	   && sig < 32
-		    	   ? current->exec_domain->signal_invmap[sig]
+		    	   ? current_thread_info()->exec_domain->signal_invmap[sig]
 			   : sig),
 			  &frame->sig);
 	err |= __put_user(&frame->info, &frame->pinfo);
@@ -712,3 +712,16 @@
 	}
 	return 0;
 }
+
+/*
+ * notification of userspace execution resumption
+ * - triggered by current->work.notify_resume
+ */
+__attribute__((regparm(3)))
+void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+		      __u32 thread_info_flags)
+{
+	/* deal with pending signal delivery */
+	if (thread_info_flags & _TIF_SIGPENDING)
+		do_signal(regs,oldset);
+}
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index e8afcad..66417ce 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -818,7 +818,7 @@
 
 	/* So we see what's up   */
 	printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
-	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
+	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle->thread_info);
 
 	/*
 	 * This grunge runs the startup process for
@@ -1024,7 +1024,7 @@
 	map_cpu_to_boot_apicid(0, boot_cpu_apicid);
 
 	global_irq_holder = NO_PROC_ID;
-	current->cpu = 0;
+	current_thread_info()->cpu = 0;
 	smp_tune_scheduling();
 
 	/*
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 130c45e..ad68256 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -158,7 +158,7 @@
 	unsigned long esp = tsk->thread.esp;
 
 	/* User space on another CPU? */
-	if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
+	if ((esp ^ (unsigned long)tsk->thread_info) & (PAGE_MASK<<1))
 		return;
 	show_trace((unsigned long *)esp);
 }
@@ -208,8 +208,8 @@
 		regs->esi, regs->edi, regs->ebp, esp);
 	printk("ds: %04x   es: %04x   ss: %04x\n",
 		regs->xds & 0xffff, regs->xes & 0xffff, ss);
-	printk("Process %s (pid: %d, stackpage=%08lx)",
-		current->comm, current->pid, 4096+(unsigned long)current);
+	printk("Process %s (pid: %d, threadinfo=%p task=%p)",
+		current->comm, current->pid, current_thread_info(), current);
 	/*
 	 * When in-kernel, we also print out the stack and code at the
 	 * time of the fault..
@@ -720,7 +720,7 @@
 	} else {
 		init_fpu();
 	}
-	current->flags |= PF_USEDFPU;	/* So we fnsave on switch_to() */
+	set_thread_flag(TIF_USEDFPU);	/* So we fnsave on switch_to() */
 }
 
 #ifndef CONFIG_MATH_EMULATION
diff --git a/arch/i386/lib/getuser.S b/arch/i386/lib/getuser.S
index c244721..3814c24 100644
--- a/arch/i386/lib/getuser.S
+++ b/arch/i386/lib/getuser.S
@@ -8,6 +8,8 @@
  * return an error value in addition to the "real"
  * return value.
  */
+#include <asm/thread_info.h>
+
 
 /*
  * __get_user_X
@@ -21,15 +23,12 @@
  * as they get called from within inline assembly.
  */
 
-addr_limit = 12
-
 .text
 .align 4
 .globl __get_user_1
 __get_user_1:
-	movl %esp,%edx
-	andl $0xffffe000,%edx
-	cmpl addr_limit(%edx),%eax
+	GET_THREAD_INFO(%edx)
+	cmpl TI_ADDR_LIMIT(%edx),%eax
 	jae bad_get_user
 1:	movzbl (%eax),%edx
 	xorl %eax,%eax
@@ -39,10 +38,9 @@
 .globl __get_user_2
 __get_user_2:
 	addl $1,%eax
-	movl %esp,%edx
 	jc bad_get_user
-	andl $0xffffe000,%edx
-	cmpl addr_limit(%edx),%eax
+	GET_THREAD_INFO(%edx)
+	cmpl TI_ADDR_LIMIT(%edx),%eax
 	jae bad_get_user
 2:	movzwl -1(%eax),%edx
 	xorl %eax,%eax
@@ -52,10 +50,9 @@
 .globl __get_user_4
 __get_user_4:
 	addl $3,%eax
-	movl %esp,%edx
 	jc bad_get_user
-	andl $0xffffe000,%edx
-	cmpl addr_limit(%edx),%eax
+	GET_THREAD_INFO(%edx)
+	cmpl TI_ADDR_LIMIT(%edx),%eax
 	jae bad_get_user
 3:	movl -3(%eax),%edx
 	xorl %eax,%eax
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 307b498..832f396 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1133,7 +1133,6 @@
 	data8 sys_tkill
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall			// 1220
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index 7694828..3c06af9 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.51 2001-11-17 00:15:27 davem Exp $
+# $Id: Makefile,v 1.52 2002-02-09 19:49:31 davem Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -79,12 +79,8 @@
 	rm -f $(TOPDIR)/vmlinux.aout
 
 archmrproper:
-	rm -f $(TOPDIR)/include/asm-sparc64/asm_offsets.h
 
-archdep: check_asm
-
-check_asm: include/linux/version.h
-	$(MAKE) -C arch/sparc64/kernel check_asm
+archdep:
 
 tftpboot.img:
 	$(MAKE) -C arch/sparc64/boot tftpboot.img
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 8ec7b35..7cfcab0 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -494,6 +494,7 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_NEW_RX_RESET is not set
 CONFIG_SIS900=m
 CONFIG_EPIC100=m
 CONFIG_SUNDANCE=m
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 3140778..be72c99 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.69 2001-11-19 04:09:53 davem Exp $
+# $Id: Makefile,v 1.70 2002-02-09 19:49:30 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -56,118 +56,4 @@
   CMODEL_CFLAG := -m64 -mcmodel=medlow
 endif
 
-check_asm: dummy
-	@if [ ! -r $(HPATH)/asm/asm_offsets.h ] ; then \
-	  touch $(HPATH)/asm/asm_offsets.h ; \
-	fi
-	@echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
-	@echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
-	@echo -e "#define __ASM_OFFSETS_H__\n" >> asm_offsets.h
-	@echo -e "#include <linux/config.h>\n" >> asm_offsets.h
-	@echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h
-	@echo "#include <linux/config.h>" > tmp.c
-	@echo "#undef CONFIG_SMP" >> tmp.c
-	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
-	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
-	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
-	@echo "#include <linux/sched.h>" >> check_asm_data.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm_data.c
-	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
-	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
-	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
-	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
-	$(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c
-	@echo '};' >> check_asm.c
-	@echo 'int main(void) {' >> check_asm.c
-	@echo 'int i = 0;' >> check_asm.c
-	$(SH) ./check_asm.sh -printf task tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf mm tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf thread tmp.i check_asm.c
-	@echo 'return 0; }' >> check_asm.c
-	@rm -f tmp.[ci] check_asm_data.[cs]
-	$(HOSTCC) -o check_asm check_asm.c
-	./check_asm >> asm_offsets.h
-	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
-	@echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h
-	@echo "#include <linux/config.h>" > tmp.c
-	@echo "#undef CONFIG_SMP" >> tmp.c
-	@echo "#define CONFIG_SMP 1" >> tmp.c
-	@echo "#include <linux/sched.h>" >> tmp.c
-	$(CPP) $(CPPFLAGS) -P tmp.c -o tmp.i
-	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
-	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
-	@echo "#define CONFIG_SMP 1" >> check_asm_data.c
-	@echo "#include <linux/sched.h>" >> check_asm_data.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm_data.c
-	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
-	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
-	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
-	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
-	$(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c
-	@echo '};' >> check_asm.c
-	@echo 'int main(void) {' >> check_asm.c
-	@echo 'int i = 0;' >> check_asm.c
-	$(SH) ./check_asm.sh -printf task tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf mm tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf thread tmp.i check_asm.c
-	@echo 'return 0; }' >> check_asm.c
-	@rm -f tmp.[ci] check_asm_data.[cs]
-	$(HOSTCC) -o check_asm check_asm.c
-	./check_asm >> asm_offsets.h
-	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
-	@echo "#include <linux/sched.h>" > tmp.c
-	$(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
-	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
-	@echo "#include <linux/config.h>" >> check_asm_data.c
-	@echo "#undef CONFIG_SMP" >> check_asm_data.c
-	@echo "#define CONFIG_SMP 1" >> check_asm_data.c
-	@echo "#include <linux/sched.h>" >> check_asm_data.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm_data.c
-	$(SH) ./check_asm.sh -data task tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data mm tmp.i check_asm_data.c
-	$(SH) ./check_asm.sh -data thread tmp.i check_asm_data.c
-	@echo '};' >> check_asm_data.c
-	$(CC) $(CPPFLAGS) -DCONFIG_DEBUG_SPINLOCK $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm_data.s check_asm_data.c
-	@echo "/* Automatically generated. Do not edit. */" > check_asm.c
-	@echo 'extern int printf(const char *fmt, ...);' >>check_asm.c
-	@echo 'unsigned int check_asm_data[] = {' >> check_asm.c
-	$(SH) ./check_asm.sh -ints check_asm_data.s check_asm.c
-	@echo '};' >> check_asm.c
-	@echo 'int main(void) {' >> check_asm.c
-	@echo 'int i = 0;' >> check_asm.c
-	$(SH) ./check_asm.sh -printf task tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf mm tmp.i check_asm.c
-	$(SH) ./check_asm.sh -printf thread tmp.i check_asm.c
-	@echo 'return 0; }' >> check_asm.c
-	@rm -f tmp.[ci] check_asm_data.[cs]
-	$(HOSTCC) -o check_asm check_asm.c
-	./check_asm >> asm_offsets.h
-	@rm -f check_asm check_asm.c
-	@echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
-	@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
-	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
-	@if test -r $(HPATH)/asm/asm_offsets.h; then \
-	  if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
-	    echo $(HPATH)/asm/asm_offsets.h is unchanged; \
-	    rm -f asm_offsets.h; \
-	  else \
-	    mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
-	  fi; \
-	else \
-	  mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
-	fi
-
 include $(TOPDIR)/Rules.make
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index f05e57c..1feb6bd 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -314,7 +314,7 @@
 
 	current->mm->start_stack =
 		(unsigned long) create_aout32_tables((char *)bprm->p, bprm);
-	if (!(current->thread.flags & SPARC_FLAG_32BIT)) {
+	if (!(test_thread_flag(TIF_32BIT))) {
 		unsigned long pgd_cache;
 
 		pgd_cache = ((unsigned long)current->mm->pgd[0])<<11UL;
@@ -323,7 +323,7 @@
 				     : /* no outputs */
 				     : "r" (pgd_cache),
 				       "r" (TSB_REG), "i" (ASI_DMMU));
-		current->thread.flags |= SPARC_FLAG_32BIT;
+		set_thread_flag(TIF_32BIT);
 	}
 	start_thread32(regs, ex.a_entry, current->mm->start_stack);
 	if (current->ptrace & PT_PTRACED)
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index 6d9e291..5b742bc 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -149,7 +149,7 @@
 #ifdef CONFIG_BINFMT_ELF32_MODULE
 #define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
 #endif
-#define ELF_FLAGS_INIT	current->thread.flags |= SPARC_FLAG_32BIT
+#define ELF_FLAGS_INIT	set_thread_flag(TIF_32BIT)
 
 MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
 MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 4495a1b..285da21 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.143 2002-01-31 22:38:25 davem Exp $
+/* $Id: entry.S,v 1.144 2002-02-09 19:49:30 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -151,12 +151,12 @@
 	add		%g0, %g0, %g0
 	ba,a,pt		%xcc, rtrap_clr_l6
 
-1:	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5	! Load	Group
+1:	ldub		[%g6 + TI_FPSAVED], %g5					! Load	Group
 	wr		%g0, FPRS_FEF, %fprs					! LSU	Group+4bubbles
 	andcc		%g5, FPRS_FEF, %g0					! IEU1	Group
 	be,a,pt		%icc, 1f						! CTI
 	 clr		%g7							! IEU0
-	ldx		[%g6 + AOFF_task_thread + AOFF_thread_gsr], %g7		! Load	Group
+	ldx		[%g6 + TI_GSR], %g7					! Load	Group
 1:	andcc		%g5, FPRS_DL, %g0					! IEU1
 	bne,pn		%icc, 2f						! CTI
 	 fzero		%f0							! FPA
@@ -194,11 +194,11 @@
 	b,pt		%xcc, fpdis_exit2
 	 faddd		%f0, %f2, %f60
 1:	mov		SECONDARY_CONTEXT, %g3
-	add		%g6, AOFF_task_fpregs + 0x80, %g1
+	add		%g6, TI_FPREGS + 0x80, %g1
 	faddd		%f0, %f2, %f4
 	fmuld		%f0, %f2, %f6
 	ldxa		[%g3] ASI_DMMU, %g5
-	add		%g6, AOFF_task_fpregs + 0xc0, %g2
+	add		%g6, TI_FPREGS + 0xc0, %g2
 	stxa		%g0, [%g3] ASI_DMMU
 	membar		#Sync
 	faddd		%f0, %f2, %f8
@@ -223,10 +223,10 @@
 	mov		SECONDARY_CONTEXT, %g3
 	fzero		%f34
 	ldxa		[%g3] ASI_DMMU, %g5
-	add		%g6, AOFF_task_fpregs, %g1
+	add		%g6, TI_FPREGS, %g1
 	stxa		%g0, [%g3] ASI_DMMU
 	membar		#Sync
-	add		%g6, AOFF_task_fpregs + 0x40, %g2
+	add		%g6, TI_FPREGS + 0x40, %g2
 	faddd		%f32, %f34, %f36
 	fmuld		%f32, %f34, %f38
 	ldda		[%g1] ASI_BLK_S, %f0	! grrr, where is ASI_BLK_NUCLEUS 8-(
@@ -246,7 +246,7 @@
 	ba,pt		%xcc, fpdis_exit
 	 membar		#Sync
 3:	mov		SECONDARY_CONTEXT, %g3
-	add		%g6, AOFF_task_fpregs, %g1
+	add		%g6, TI_FPREGS, %g1
 	ldxa		[%g3] ASI_DMMU, %g5
 	mov		0x40, %g2
 	stxa		%g0, [%g3] ASI_DMMU
@@ -262,7 +262,7 @@
 	membar		#Sync
 fpdis_exit2:
 	wr		%g7, 0, %gsr
-	ldx		[%g6 + AOFF_task_thread + AOFF_thread_xfsr], %fsr
+	ldx		[%g6 + TI_XFSR], %fsr
 	rdpr		%tstate, %g3
 	or		%g3, %g4, %g3		! anal...
 	wrpr		%g3, %tstate
@@ -285,12 +285,12 @@
 	/* NOTE: Need to preserve %g7 until we fully commit
 	 *       to the fitos fixup.
 	 */
-	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
+	stx		%fsr, [%g6 + TI_XFSR]
 	rdpr		%tstate, %g3
 	andcc		%g3, TSTATE_PRIV, %g0
 	bne,pn		%xcc, do_fptrap_after_fsr
 	 nop
-	ldx		[%g6 + AOFF_task_thread + AOFF_thread_xfsr], %g3
+	ldx		[%g6 + TI_XFSR], %g3
 	srlx		%g3, 14, %g1
 	and		%g1, 7, %g1
 	cmp		%g1, 2			! Unfinished FP-OP
@@ -310,7 +310,7 @@
 	cmp		%g1, %g2
 	bne,pn		%xcc, do_fptrap_after_fsr
 	 nop
-	std		%f62, [%g6 + AOFF_task_fpregs + (62 * 4)]
+	std		%f62, [%g6 + TI_FPREGS + (62 * 4)]
 	sethi		%hi(fitos_table_1), %g1
 	and		%g3, 0x1f, %g2
 	or		%g1, %lo(fitos_table_1),  %g1
@@ -396,22 +396,22 @@
 	fdtos		%f62, %f31
 
 fitos_emul_fini:
-	ldd		[%g6 + AOFF_task_fpregs + (62 * 4)], %f62
+	ldd		[%g6 + TI_FPREGS + (62 * 4)], %f62
 	done
 
 	.globl		do_fptrap
 	.align		32
 do_fptrap:
-	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
+	stx		%fsr, [%g6 + TI_XFSR]
 do_fptrap_after_fsr:
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3
+	ldub		[%g6 + TI_FPSAVED], %g3
 	rd		%fprs, %g1
 	or		%g3, %g1, %g3
-	stb		%g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
+	stb		%g3, [%g6 + TI_FPSAVED]
 	rd		%gsr, %g3
-	stx		%g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr]
+	stx		%g3, [%g6 + TI_GSR]
 	mov		SECONDARY_CONTEXT, %g3
-	add		%g6, AOFF_task_fpregs, %g2
+	add		%g6, TI_FPREGS, %g2
 	ldxa		[%g3] ASI_DMMU, %g5
 	stxa		%g0, [%g3] ASI_DMMU
 	membar		#Sync
@@ -1384,8 +1384,8 @@
 		 add		%o7, 1f-.-4, %o7
 		nop
 		.align		32
-1:		ldub		[%curptr + AOFF_task_work + 1], %l5
-		andcc		%l5, 0xff, %g0
+1:		ldx		[%curptr + TI_FLAGS], %l5
+		andcc		%l5, _TIF_SYSCALL_TRACE, %g0
 		be,pt		%icc, rtrap
 		 clr		%l6
 		call		syscall_trace
@@ -1435,14 +1435,14 @@
 		/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in
 		 * %o7 for us.  Check performance counter stuff too.
 		 */
-		andn		%o7, SPARC_FLAG_NEWCHILD, %l0
+		andn		%o7, _TIF_NEWCHILD, %l0
 		mov		%g5, %o0	/* 'prev' */
 		call		schedule_tail
-		 stb		%l0, [%g6 + AOFF_task_thread + AOFF_thread_flags]
-		andcc		%l0, SPARC_FLAG_PERFCTR, %g0
+		 stx		%l0, [%g6 + TI_FLAGS]
+		andcc		%l0, _TIF_PERFCTR, %g0
 		be,pt		%icc, 1f
 		 nop
-		ldx		[%g6 + AOFF_task_thread + AOFF_thread_pcr_reg], %o7
+		ldx		[%g6 + TI_PCR], %o7
 		wr		%g0, %o7, %pcr
 
 		/* Blackbird errata workaround.  See commentary in
@@ -1465,7 +1465,7 @@
 		wrpr		%g0, 0x0, %otherwin
 		wrpr		%g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE), %pstate
 		ba,pt		%xcc, sys_exit
-		 stb		%g0, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
+		 stb		%g0, [%g6 + TI_WSAVED]
 
 linux_sparc_ni_syscall:
 	sethi		%hi(sys_ni_syscall), %l7
@@ -1510,11 +1510,11 @@
 	mov		%i4, %o4				! IEU1
 	lduw		[%l7 + %l4], %l7			! Load
 	srl		%i1, 0, %o1				! IEU0	Group
-	ldub		[%curptr + AOFF_task_work + 1], %l0	! Load
+	ldx		[%curptr + TI_FLAGS], %l0		! Load
 
 	mov		%i5, %o5				! IEU1
 	srl		%i2, 0, %o2				! IEU0	Group
-	andcc		%l0, 0xff, %g0				! IEU0	Group
+	andcc		%l0, _TIF_SYSCALL_TRACE, %g0		! IEU0	Group
 	bne,pn		%icc, linux_syscall_trace32		! CTI
 	 mov		%i0, %l5				! IEU1
 	call		%l7					! CTI	Group brk forced
@@ -1538,11 +1538,11 @@
 	mov		%i1, %o1				! IEU1
 	lduw		[%l7 + %l4], %l7			! Load
 4:	mov		%i2, %o2				! IEU0	Group
-	ldub		[%curptr + AOFF_task_work + 1], %l0	! Load
+	ldx		[%curptr + TI_FLAGS], %l0		! Load
 
 	mov		%i3, %o3				! IEU1
 	mov		%i4, %o4				! IEU0	Group
-	andcc		%l0, 0xff, %g0				! IEU1	Group+1 bubble
+	andcc		%l0, _TIF_SYSCALL_TRACE, %g0		! IEU1	Group+1 bubble
 	bne,pn		%icc, linux_syscall_trace		! CTI	Group
 	 mov		%i0, %l5				! IEU0
 2:	call		%l7					! CTI	Group brk forced
@@ -1565,7 +1565,7 @@
 	sllx		%g2, 32, %g2
 	bgeu,pn		%xcc, 1f
 
-	 andcc		%l0, 0xff, %l6	
+	 andcc		%l0, _TIF_SYSCALL_TRACE, %l6	
 	andn		%g3, %g2, %g3		/* System call success, clear Carry condition code. */
 	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
 	bne,pn		%icc, linux_syscall_trace2
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index db18772..70e07ef 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.45 2001-09-07 21:04:40 kanoj Exp $
+/* $Id: etrap.S,v 1.46 2002-02-09 19:49:30 davem Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -60,7 +60,7 @@
 		wrpr	%g0, 0, %canrestore					! Single	Group+4bubbles
 		sll	%g2, 3, %g2						! IEU0		Group
 		mov	1, %l5							! IEU1
-		stb	%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
+		stb	%l5, [%l6 + TI_FPDEPTH]					! Store
 
 		wrpr	%g3, 0, %otherwin					! Single	Group+4bubbles
 		wrpr	%g2, 0, %wstate						! Single	Group+4bubbles
@@ -98,11 +98,11 @@
 		nop
 		nop
 
-3:		ldub	[%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5	! Load		Group
-		add	%l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4	! IEU0
+3:		ldub	[%l6 + TI_FPDEPTH], %l5					! Load		Group
+		add	%l6, TI_FPSAVED + 1, %l4				! IEU0
 		srl	%l5, 1, %l3						! IEU0		Group
 		add	%l5, 2, %l5						! IEU1
-		stb	%l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth]	! Store
+		stb	%l5, [%l6 + TI_FPDEPTH]					! Store
 		ba,pt	%xcc, 2b						! CTI
 		 stb	%g0, [%l4 + %l3]					! Store		Group
 		nop
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 0bc9d83..e667289 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.86 2001-12-05 01:02:16 davem Exp $
+/* $Id: head.S,v 1.87 2002-02-09 19:49:31 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -10,7 +10,7 @@
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/errno.h>
-#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
 #include <asm/asi.h>
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
@@ -491,8 +491,8 @@
 	stw	%g2, [%g5 + %lo(tlb_type)]
 
 tlb_fixup_done:
-	sethi	%hi(init_task_union), %g6
-	or	%g6, %lo(init_task_union), %g6
+	sethi	%hi(init_thread_union), %g6
+	or	%g6, %lo(init_thread_union), %g6
 	mov	%sp, %l6
 	mov	%o4, %l7
 
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
index ae8150a..1def381 100644
--- a/arch/sparc64/kernel/init_task.c
+++ b/arch/sparc64/kernel/init_task.c
@@ -12,17 +12,25 @@
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /* .text section in head.S is aligned at 2 page boundry and this gets linked
- * right after that so that the init_task_union is aligned properly as well.
+ * right after that so that the init_thread_union is aligned properly as well.
  * We really don't need this special alignment like the Intel does, but
  * I do it anyways for completeness.
  */
 __asm__ (".text");
-union task_union init_task_union = { INIT_TASK(init_task_union.task) };
+union thread_union init_thread_union = { INIT_THREAD_INFO(init_task) };
 
 /*
- * This is to make the init_task+stack of the right size for >8k pagesize.
- * The definition of task_union in sched.h makes it 16k wide.
+ * This is to make the init_thread+stack be the right size for >8k pagesize.
+ * The definition of thread_union in sched.h makes it 16k wide.
  */
 #if PAGE_SHIFT != 13
-char init_task_stack[THREAD_SIZE - INIT_TASK_SIZE] = { 0 };
+char init_task_stack[THREAD_SIZE - INIT_THREAD_SIZE] = { 0 };
 #endif
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+__asm__(".data");
+struct task_struct init_task = INIT_TASK(init_task);
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S
index d070c9e..0f2cbe2 100644
--- a/arch/sparc64/kernel/itlb_base.S
+++ b/arch/sparc64/kernel/itlb_base.S
@@ -1,4 +1,4 @@
-/* $Id: itlb_base.S,v 1.11 2001-08-17 04:55:09 kanoj Exp $
+/* $Id: itlb_base.S,v 1.12 2002-02-09 19:49:30 davem Exp $
  * itlb_base.S:	Front end to ITLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -51,8 +51,8 @@
 	rdpr		%tpc, %g5			! And load faulting VA
 	mov		FAULT_CODE_ITLB, %g4		! It was read from ITLB
 sparc64_realfault_common:				! Called by TL0 dtlb_miss too
-	stb		%g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
-	stx		%g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
+	stb		%g4, [%g6 + TI_FAULT_CODE]
+	stx		%g5, [%g6 + TI_FAULT_ADDR]
 	ba,pt		%xcc, etrap			! Save state
 1:	 rd		%pc, %g7			! ...
 	nop
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 1a30ec0..a06f21b 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.130 2002-01-31 03:30:06 davem Exp $
+/*  $Id: process.c,v 1.131 2002-02-09 19:49:30 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -79,10 +79,13 @@
 #define unidle_me()		(cpu_data[smp_processor_id()].idle_volume = 0)
 int cpu_idle(void)
 {
+	set_thread_flag(TIF_POLLING_NRFLAG);
 	while(1) {
 		if (need_resched()) {
 			unidle_me();
+			clear_thread_flag(TIF_POLLING_NRFLAG);
 			schedule();
+			set_thread_flag(TIF_POLLING_NRFLAG);
 			check_pgt_cache();
 		}
 		idle_me_harder();
@@ -176,7 +179,7 @@
 	struct reg_window r_w;
 	mm_segment_t old_fs;
 
-	if ((regs->tstate & TSTATE_PRIV) || !(current->thread.flags & SPARC_FLAG_32BIT)) {
+	if ((regs->tstate & TSTATE_PRIV) || !(test_thread_flag(TIF_32BIT))) {
 		__asm__ __volatile__ ("flushw");
 		rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS);
 		if (!(regs->tstate & TSTATE_PRIV)) {
@@ -364,34 +367,28 @@
 	       regs->u_regs[15]);
 }
 
-void show_thread(struct thread_struct *thread)
+unsigned long thread_saved_pc(struct thread_info *ti)
 {
-	int i;
-
-#if 0
-	printk("kregs:             0x%016lx\n", (unsigned long)thread->kregs);
-	show_regs(thread->kregs);
-#endif	
-	printk("ksp:               0x%016lx\n", thread->ksp);
-
-	if (thread->w_saved) {
-		for (i = 0; i < NSWINS; i++) {
-			if (!thread->rwbuf_stkptrs[i])
-				continue;
-			printk("reg_window[%d]:\n", i);
-			printk("stack ptr:         0x%016lx\n", thread->rwbuf_stkptrs[i]);
+	unsigned long ret = 0xdeadbeefUL;
+	
+	if (ti && ti->ksp) {
+		unsigned long *sp;
+		sp = (unsigned long *)(ti->ksp + STACK_BIAS);
+		if (((unsigned long)sp & (sizeof(long) - 1)) == 0UL &&
+		    sp[14]) {
+			unsigned long *fp;
+			fp = (unsigned long *)(sp[14] + STACK_BIAS);
+			if (((unsigned long)fp & (sizeof(long) - 1)) == 0UL)
+				ret = fp[15];
 		}
-		printk("w_saved:           0x%04x\n", thread->w_saved);
 	}
-
-	printk("flags:             0x%08x\n", thread->flags);
-	printk("current_ds:        0x%x\n", thread->current_ds.seg);
+	return ret;
 }
 
 /* Free current thread data structures etc.. */
 void exit_thread(void)
 {
-	struct thread_struct *t = &current->thread;
+	struct thread_info *t = current_thread_info();
 
 	if (t->utraps) {
 		if (t->utraps[0] < 2)
@@ -400,22 +397,20 @@
 			t->utraps[0]--;
 	}
 
-	/* Turn off performance counters if on. */
-	if (t->flags & SPARC_FLAG_PERFCTR) {
+	if (test_and_clear_thread_flag(TIF_PERFCTR)) {
 		t->user_cntd0 = t->user_cntd1 = NULL;
 		t->pcr_reg = 0;
-		t->flags &= ~(SPARC_FLAG_PERFCTR);
 		write_pcr(0);
 	}
 }
 
 void flush_thread(void)
 {
-	struct thread_struct *t = &current->thread;
+	struct thread_info *t = current_thread_info();
 
-	if (current->mm) {
-		if (t->flags & SPARC_FLAG_32BIT) {
-			struct mm_struct *mm = current->mm;
+	if (t->task->mm) {
+		if (test_thread_flag(TIF_32BIT)) {
+			struct mm_struct *mm = t->task->mm;
 			pgd_t *pgd0 = &mm->pgd[0];
 			unsigned long pgd_cache;
 
@@ -434,24 +429,23 @@
 					       "i" (ASI_DMMU));
 		}
 	}
-	t->w_saved = 0;
+	set_thread_wsaved(0);
 
 	/* Turn off performance counters if on. */
-	if (t->flags & SPARC_FLAG_PERFCTR) {
+	if (test_and_clear_thread_flag(TIF_PERFCTR)) {
 		t->user_cntd0 = t->user_cntd1 = NULL;
 		t->pcr_reg = 0;
-		t->flags &= ~(SPARC_FLAG_PERFCTR);
 		write_pcr(0);
 	}
 
 	/* Clear FPU register state. */
 	t->fpsaved[0] = 0;
 	
-	if (t->current_ds.seg != ASI_AIUS)
+	if (get_thread_current_ds() != ASI_AIUS)
 		set_fs(USER_DS);
 
 	/* Init new signal delivery disposition. */
-	t->flags &= ~SPARC_FLAG_NEWSIGNALS;
+	clear_thread_flag(TIF_NEWSIGNALS);
 }
 
 /* It's a bit more tricky when 64-bit tasks are involved... */
@@ -459,7 +453,7 @@
 {
 	unsigned long fp, distance, rval;
 
-	if (!(current->thread.flags & SPARC_FLAG_32BIT)) {
+	if (!(test_thread_flag(TIF_32BIT))) {
 		csp += STACK_BIAS;
 		psp += STACK_BIAS;
 		__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
@@ -477,7 +471,7 @@
 	rval = (csp - distance);
 	if (copy_in_user(rval, psp, distance))
 		rval = 0;
-	else if (current->thread.flags & SPARC_FLAG_32BIT) {
+	else if (test_thread_flag(TIF_32BIT)) {
 		if (put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
 			rval = 0;
 	} else {
@@ -493,7 +487,7 @@
 
 /* Standard stuff. */
 static inline void shift_window_buffer(int first_win, int last_win,
-				       struct thread_struct *t)
+				       struct thread_info *t)
 {
 	int i;
 
@@ -506,15 +500,15 @@
 
 void synchronize_user_stack(void)
 {
-	struct thread_struct *t = &current->thread;
+	struct thread_info *t = current_thread_info();
 	unsigned long window;
 
 	flush_user_windows();
-	if ((window = t->w_saved) != 0) {
+	if ((window = get_thread_wsaved()) != 0) {
 		int winsize = REGWIN_SZ;
 		int bias = 0;
 
-		if (t->flags & SPARC_FLAG_32BIT)
+		if (test_thread_flag(TIF_32BIT))
 			winsize = REGWIN32_SZ;
 		else
 			bias = STACK_BIAS;
@@ -525,8 +519,8 @@
 			struct reg_window *rwin = &t->reg_window[window];
 
 			if (!copy_to_user((char *)sp, rwin, winsize)) {
-				shift_window_buffer(window, t->w_saved - 1, t);
-				t->w_saved--;
+				shift_window_buffer(window, get_thread_wsaved() - 1, t);
+				set_thread_wsaved(get_thread_wsaved() - 1);
 			}
 		} while (window--);
 	}
@@ -534,18 +528,18 @@
 
 void fault_in_user_windows(void)
 {
-	struct thread_struct *t = &current->thread;
+	struct thread_info *t = current_thread_info();
 	unsigned long window;
 	int winsize = REGWIN_SZ;
 	int bias = 0;
 
-	if (t->flags & SPARC_FLAG_32BIT)
+	if (test_thread_flag(TIF_32BIT))
 		winsize = REGWIN32_SZ;
 	else
 		bias = STACK_BIAS;
 
 	flush_user_windows();
-	window = t->w_saved;
+	window = get_thread_wsaved();
 
 	if (window != 0) {
 		window -= 1;
@@ -557,11 +551,11 @@
 				goto barf;
 		} while (window--);
 	}
-	t->w_saved = 0;
+	set_thread_wsaved(0);
 	return;
 
 barf:
-	t->w_saved = window + 1;
+	set_thread_wsaved(window + 1);
 	do_exit(SIGILL);
 }
 
@@ -581,21 +575,23 @@
 		unsigned long unused,
 		struct task_struct *p, struct pt_regs *regs)
 {
-	struct thread_struct *t = &p->thread;
+	struct thread_info *t = p->thread_info;
 	char *child_trap_frame;
 
 #ifdef CONFIG_DEBUG_SPINLOCK
-	t->smp_lock_count = 0;
-	t->smp_lock_pc = 0;
+	p->thread.smp_lock_count = 0;
+	p->thread.smp_lock_pc = 0;
 #endif
 
 	/* Calculate offset to stack_frame & pt_regs */
-	child_trap_frame = ((char *)p) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
+	child_trap_frame = ((char *)t) + (THREAD_SIZE - (TRACEREG_SZ+REGWIN_SZ));
 	memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
+
+	t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
+		_TIF_NEWCHILD |
+		(((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
 	t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
-	t->flags |= SPARC_FLAG_NEWCHILD;
 	t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
-	t->cwp = (regs->tstate + 1) & TSTATE_CWP;
 	t->fpsaved[0] = 0;
 
 	if (regs->tstate & TSTATE_PRIV) {
@@ -604,25 +600,25 @@
 		 * disable performance counters in the child because the
 		 * address space and protection realm are changing.
 		 */
-		if (t->flags & SPARC_FLAG_PERFCTR) {
+		if (t->flags & _TIF_PERFCTR) {
 			t->user_cntd0 = t->user_cntd1 = NULL;
 			t->pcr_reg = 0;
-			t->flags &= ~(SPARC_FLAG_PERFCTR);
+			t->flags &= ~_TIF_PERFCTR;
 		}
-		t->kregs->u_regs[UREG_FP] = p->thread.ksp;
-		t->current_ds = KERNEL_DS;
+		t->kregs->u_regs[UREG_FP] = t->ksp;
+		t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT);
 		flush_register_windows();
 		memcpy((void *)(t->ksp + STACK_BIAS),
 		       (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
 		       sizeof(struct reg_window));
-		t->kregs->u_regs[UREG_G6] = (unsigned long) p;
+		t->kregs->u_regs[UREG_G6] = (unsigned long) t;
 	} else {
-		if (t->flags & SPARC_FLAG_32BIT) {
+		if (t->flags & _TIF_32BIT) {
 			sp &= 0x00000000ffffffffUL;
 			regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
 		}
 		t->kregs->u_regs[UREG_FP] = sp;
-		t->current_ds = USER_DS;
+		t->flags |= ((long)ASI_AIUS << TI_FLAG_CURRENT_DS_SHIFT);
 		if (sp != regs->u_regs[UREG_FP]) {
 			unsigned long csp;
 
@@ -688,33 +684,10 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-#if 1
 	/* Only should be used for SunOS and ancient a.out
-	 * SparcLinux binaries...  Fixme some day when bored.
-	 * But for now at least plug the security hole :-)
+	 * SparcLinux binaries...  Not worth implementing.
 	 */
 	memset(dump, 0, sizeof(struct user));
-#else
-	unsigned long first_stack_page;
-	dump->magic = SUNOS_CORE_MAGIC;
-	dump->len = sizeof(struct user);
-	dump->regs.psr = regs->psr;
-	dump->regs.pc = regs->pc;
-	dump->regs.npc = regs->npc;
-	dump->regs.y = regs->y;
-	/* fuck me plenty */
-	memcpy(&dump->regs.regs[0], &regs->u_regs[1], (sizeof(unsigned long) * 15));
-	dump->u_tsize = (((unsigned long) current->mm->end_code) -
-		((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1);
-	dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1)));
-	dump->u_dsize -= dump->u_tsize;
-	dump->u_dsize &= ~(PAGE_SIZE - 1);
-	first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
-	dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
-	memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->thread.float_regs[0], (sizeof(unsigned long) * 32));
-	dump->fpu.fpstatus.fsr = current->thread.fsr;
-	dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
-#endif	
 }
 
 typedef struct {
@@ -735,10 +708,10 @@
  */
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 {
-	unsigned long *kfpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
-	unsigned long fprs = current->thread.fpsaved[0];
+	unsigned long *kfpregs = current_thread_info()->fpregs;
+	unsigned long fprs = current_thread_info()->fpsaved[0];
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs;
 
 		if (fprs & FPRS_DL)
@@ -752,7 +725,7 @@
 		memset(&fpregs32->pr_q[0], 0,
 		       (sizeof(unsigned int) * 64));
 		if (fprs & FPRS_FEF) {
-			fpregs32->pr_fsr = (unsigned int) current->thread.xfsr[0];
+			fpregs32->pr_fsr = (unsigned int) current_thread_info()->xfsr[0];
 			fpregs32->pr_en = 1;
 		} else {
 			fpregs32->pr_fsr = 0;
@@ -772,8 +745,8 @@
 			memset(&fpregs->pr_regs[16], 0,
 			       sizeof(unsigned int) * 32);
 		if(fprs & FPRS_FEF) {
-			fpregs->pr_fsr = current->thread.xfsr[0];
-			fpregs->pr_gsr = current->thread.gsr[0];
+			fpregs->pr_fsr = current_thread_info()->xfsr[0];
+			fpregs->pr_gsr = current_thread_info()->gsr[0];
 		} else {
 			fpregs->pr_fsr = fpregs->pr_gsr = 0;
 		}
@@ -806,8 +779,8 @@
 	putname(filename);
 	if (!error) {
 		fprs_write(0);
-		current->thread.xfsr[0] = 0;
-		current->thread.fpsaved[0] = 0;
+		current_thread_info()->xfsr[0] = 0;
+		current_thread_info()->fpsaved[0] = 0;
 		regs->tstate &= ~TSTATE_PEF;
 	}
 out:
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 6ccc596..08937d3 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -27,8 +27,6 @@
 #include <asm/visasm.h>
 #include <asm/spitfire.h>
 
-#define MAGIC_CONSTANT 0x80000000
-
 /* Returning from ptrace is a bit tricky because the syscall return
  * low level code assumes any value returned which is negative and
  * is a valid errno will mean setting the condition codes to indicate
@@ -53,7 +51,7 @@
 static inline void
 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
 {
-	if (current->thread.flags & SPARC_FLAG_32BIT) {
+	if (test_thread_flag(TIF_32BIT)) {
 		if (put_user(value, (unsigned int *)addr))
 			return pt_error_return(regs, EFAULT);
 	} else {
@@ -125,7 +123,7 @@
 	unsigned long addr2 = regs->u_regs[UREG_I4];
 	struct task_struct *child;
 
-	if (current->thread.flags & SPARC_FLAG_32BIT) {
+	if (test_thread_flag(TIF_32BIT)) {
 		addr &= 0xffffffffUL;
 		data &= 0xffffffffUL;
 		addr2 &= 0xffffffffUL;
@@ -201,7 +199,7 @@
 		goto out_tsk;
 	}
 
-	if (!(child->thread.flags & SPARC_FLAG_32BIT)	&&
+	if (!(test_thread_flag(TIF_32BIT))	&&
 	    ((request == PTRACE_READDATA64)		||
 	     (request == PTRACE_WRITEDATA64)		||
 	     (request == PTRACE_READTEXT64)		||
@@ -223,7 +221,7 @@
 		int res, copied;
 
 		res = -EIO;
-		if (current->thread.flags & SPARC_FLAG_32BIT) {
+		if (test_thread_flag(TIF_32BIT)) {
 			copied = access_process_vm(child, addr,
 						   &tmp32, sizeof(tmp32), 0);
 			tmp64 = (unsigned long) tmp32;
@@ -248,7 +246,7 @@
 		unsigned int tmp32;
 		int copied, res = -EIO;
 
-		if (current->thread.flags & SPARC_FLAG_32BIT) {
+		if (test_thread_flag(TIF_32BIT)) {
 			tmp32 = data;
 			copied = access_process_vm(child, addr,
 						   &tmp32, sizeof(tmp32), 1);
@@ -270,7 +268,7 @@
 
 	case PTRACE_GETREGS: {
 		struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
-		struct pt_regs *cregs = child->thread.kregs;
+		struct pt_regs *cregs = child->thread_info->kregs;
 		int rval;
 
 		if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
@@ -294,11 +292,11 @@
 
 	case PTRACE_GETREGS64: {
 		struct pt_regs *pregs = (struct pt_regs *) addr;
-		struct pt_regs *cregs = child->thread.kregs;
+		struct pt_regs *cregs = child->thread_info->kregs;
 		unsigned long tpc = cregs->tpc;
 		int rval;
 
-		if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
+		if ((child->thread_info->flags & _TIF_32BIT) != 0)
 			tpc &= 0xffffffff;
 		if (__put_user(cregs->tstate, (&pregs->tstate)) ||
 		    __put_user(tpc, (&pregs->tpc)) ||
@@ -321,7 +319,7 @@
 
 	case PTRACE_SETREGS: {
 		struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
-		struct pt_regs *cregs = child->thread.kregs;
+		struct pt_regs *cregs = child->thread_info->kregs;
 		unsigned int psr, pc, npc, y;
 		int i;
 
@@ -354,7 +352,7 @@
 
 	case PTRACE_SETREGS64: {
 		struct pt_regs *pregs = (struct pt_regs *) addr;
-		struct pt_regs *cregs = child->thread.kregs;
+		struct pt_regs *cregs = child->thread_info->kregs;
 		unsigned long tstate, tpc, tnpc, y;
 		int i;
 
@@ -368,7 +366,7 @@
 			pt_error_return(regs, EFAULT);
 			goto out_tsk;
 		}
-		if ((child->thread.flags & SPARC_FLAG_32BIT) != 0) {
+		if ((child->thread_info->flags & _TIF_32BIT) != 0) {
 			tpc &= 0xffffffff;
 			tnpc &= 0xffffffff;
 		}
@@ -402,11 +400,11 @@
 				unsigned int insn;
 			} fpq[16];
 		} *fps = (struct fps *) addr;
-		unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
+		unsigned long *fpregs = child->thread_info->fpregs;
 
 		if (copy_to_user(&fps->regs[0], fpregs,
 				 (32 * sizeof(unsigned int))) ||
-		    __put_user(child->thread.xfsr[0], (&fps->fsr)) ||
+		    __put_user(child->thread_info->xfsr[0], (&fps->fsr)) ||
 		    __put_user(0, (&fps->fpqd)) ||
 		    __put_user(0, (&fps->flags)) ||
 		    __put_user(0, (&fps->extra)) ||
@@ -423,11 +421,11 @@
 			unsigned int regs[64];
 			unsigned long fsr;
 		} *fps = (struct fps *) addr;
-		unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
+		unsigned long *fpregs = child->thread_info->fpregs;
 
 		if (copy_to_user(&fps->regs[0], fpregs,
 				 (64 * sizeof(unsigned int))) ||
-		    __put_user(child->thread.xfsr[0], (&fps->fsr))) {
+		    __put_user(child->thread_info->xfsr[0], (&fps->fsr))) {
 			pt_error_return(regs, EFAULT);
 			goto out_tsk;
 		}
@@ -447,7 +445,7 @@
 				unsigned int insn;
 			} fpq[16];
 		} *fps = (struct fps *) addr;
-		unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
+		unsigned long *fpregs = child->thread_info->fpregs;
 		unsigned fsr;
 
 		if (copy_from_user(fpregs, &fps->regs[0],
@@ -456,11 +454,11 @@
 			pt_error_return(regs, EFAULT);
 			goto out_tsk;
 		}
-		child->thread.xfsr[0] &= 0xffffffff00000000UL;
-		child->thread.xfsr[0] |= fsr;
-		if (!(child->thread.fpsaved[0] & FPRS_FEF))
-			child->thread.gsr[0] = 0;
-		child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
+		child->thread_info->xfsr[0] &= 0xffffffff00000000UL;
+		child->thread_info->xfsr[0] |= fsr;
+		if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
+			child->thread_info->gsr[0] = 0;
+		child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL);
 		pt_succ_return(regs, 0);
 		goto out_tsk;
 	}
@@ -470,17 +468,17 @@
 			unsigned int regs[64];
 			unsigned long fsr;
 		} *fps = (struct fps *) addr;
-		unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
+		unsigned long *fpregs = child->thread_info->fpregs;
 
 		if (copy_from_user(fpregs, &fps->regs[0],
 				   (64 * sizeof(unsigned int))) ||
-		    __get_user(child->thread.xfsr[0], (&fps->fsr))) {
+		    __get_user(child->thread_info->xfsr[0], (&fps->fsr))) {
 			pt_error_return(regs, EFAULT);
 			goto out_tsk;
 		}
-		if (!(child->thread.fpsaved[0] & FPRS_FEF))
-			child->thread.gsr[0] = 0;
-		child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
+		if (!(child->thread_info->fpsaved[0] & FPRS_FEF))
+			child->thread_info->gsr[0] = 0;
+		child->thread_info->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
 		pt_succ_return(regs, 0);
 		goto out_tsk;
 	}
@@ -523,7 +521,7 @@
 		if (addr != 1) {
 			unsigned long pc_mask = ~0UL;
 
-			if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
+			if ((child->thread_info->flags & _TIF_32BIT) != 0)
 				pc_mask = 0xffffffff;
 
 			if (addr & 3) {
@@ -531,27 +529,27 @@
 				goto out_tsk;
 			}
 #ifdef DEBUG_PTRACE
-			printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc);
+			printk ("Original: %016lx %016lx\n",
+				child->thread_info->kregs->tpc,
+				child->thread_info->kregs->tnpc);
 			printk ("Continuing with %016lx %016lx\n", addr, addr+4);
 #endif
-			child->thread.kregs->tpc = (addr & pc_mask);
-			child->thread.kregs->tnpc = ((addr + 4) & pc_mask);
+			child->thread_info->kregs->tpc = (addr & pc_mask);
+			child->thread_info->kregs->tnpc = ((addr + 4) & pc_mask);
 		}
 
 		if (request == PTRACE_SYSCALL) {
-			child->ptrace |= PT_SYSCALLTRACE;
-			child->work.syscall_trace++;
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		} else {
-			child->ptrace &= ~PT_SYSCALLTRACE;
-			child->work.syscall_trace--;
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		}
 
 		child->exit_code = data;
 #ifdef DEBUG_PTRACE
 		printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
 			child->pid, child->exit_code,
-			child->thread.kregs->tpc,
-			child->thread.kregs->tnpc);
+			child->thread_info->kregs->tpc,
+			child->thread_info->kregs->tnpc);
 		       
 #endif
 		wake_up_process(child);
@@ -614,7 +612,7 @@
 	}
 out_tsk:
 	if (child)
-		free_task_struct(child);
+		put_task_struct(child);
 out:
 	unlock_kernel();
 }
@@ -624,12 +622,12 @@
 #ifdef DEBUG_PTRACE
 	printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
 #endif
-	if ((current->ptrace & (PT_PTRACED|PT_SYSCALLTRACE))
-	    != (PT_PTRACED|PT_SYSCALLTRACE))
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
 		return;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
-	current->thread.flags ^= MAGIC_CONSTANT;
 	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index f014e4d..76b9b32 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.60 2002-01-31 03:30:06 davem Exp $
+/* $Id: rtrap.S,v 1.61 2002-02-09 19:49:31 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -42,18 +42,18 @@
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 		/* Redo sched+sig checks */
-		lduw			[%g6 + AOFF_task_work], %l0
-		srlx			%l0, 24, %o0
+		ldx			[%g6 + TI_FLAGS], %l0
+		andcc			%l0, _TIF_NEED_RESCHED, %g0
 
-		brz,pt			%o0, 1f
+		be,pt			%xcc, 1f
 		 nop
 		call			schedule
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		lduw			[%g6 + AOFF_task_work], %l0
+		ldx			[%g6 + TI_FLAGS], %l0
 
-1:		sllx			%l0, 48, %o0
-		brz,pt			%o0, __handle_user_windows_continue
+1:		andcc			%l0, (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING), %g0
+		be,pt			%xcc, __handle_user_windows_continue
 		 nop
 		clr			%o0
 		mov			%l5, %o2
@@ -78,7 +78,7 @@
 		call			update_perfctrs
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
+		ldub			[%g6 + TI_WSAVED], %o2
 		brz,pt			%o2, 1f
 		 nop
 		/* Redo userwin+sched+sig checks */
@@ -86,18 +86,18 @@
 
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		lduw			[%g6 + AOFF_task_work], %l0
-		srlx			%l0, 24, %o0
-		brz,pt			%o0, 1f
+		ldx			[%g6 + TI_FLAGS], %l0
+		andcc			%l0, _TIF_NEED_RESCHED, %g0
+		be,pt			%xcc, 1f
 
 		 nop
 		call			schedule
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
 		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		lduw			[%g6 + AOFF_task_work], %l0
-1:		sllx			%l0, 48, %o0
+		ldx			[%g6 + TI_FLAGS], %l0
+1:		andcc			%l0, (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING), %g0
 
-		brz,pt			%o0, __handle_perfctrs_continue
+		be,pt			%xcc, __handle_perfctrs_continue
 		 sethi			%hi(TSTATE_PEF), %o0
 		clr			%o0
 		mov			%l5, %o2
@@ -150,7 +150,7 @@
 		.align			64
 		.globl			rtrap_clr_l6, rtrap, irqsz_patchme
 rtrap_clr_l6:	clr			%l6
-rtrap:		lduw			[%g6 + AOFF_task_cpu], %l0
+rtrap:		ldub			[%g6 + TI_CPU], %l0
 		sethi			%hi(irq_stat), %l2	! &softirq_active
 		or			%l2, %lo(irq_stat), %l2	! &softirq_active
 irqsz_patchme:	sllx			%l0, 0, %l0
@@ -182,26 +182,33 @@
 		 */
 to_user:	wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 __handle_preemption_continue:
-		lduw			[%g6 + AOFF_task_work], %l0
-		srlx			%l0, 24, %o0
-		brnz,pn			%o0, __handle_preemption
-		 sllx			%l0, 48, %o0
-		brnz,pn			%o0, __handle_signal
+		ldx			[%g6 + TI_FLAGS], %l0
+		sethi			%hi(_TIF_USER_WORK_MASK), %o0
+		or			%o0, %lo(_TIF_USER_WORK_MASK), %o0
+		andcc			%l0, %o0, %g0
+		sethi			%hi(TSTATE_PEF), %o0
+		be,pt			%xcc, user_nowork
+		 andcc			%l1, %o0, %g0
+		andcc			%l0, _TIF_NEED_RESCHED, %g0
+		bne,pn			%xcc, __handle_preemption
+		 andcc			%l0, (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING), %g0
+		bne,pn			%xcc, __handle_signal
 __handle_signal_continue:
-		 ldub			[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
+		 ldub			[%g6 + TI_WSAVED], %o2
 		brnz,pn			%o2, __handle_user_windows
 		 nop
 __handle_user_windows_continue:
-		ldub			[%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
-		andcc			%l5, SPARC_FLAG_PERFCTR, %g0
+		ldx			[%g6 + TI_FLAGS], %l5
+		andcc			%l5, _TIF_PERFCTR, %g0
 		sethi			%hi(TSTATE_PEF), %o0
 		bne,pn			%xcc, __handle_perfctrs
 __handle_perfctrs_continue:
 		 andcc			%l1, %o0, %g0
 
 		/* This fpdepth clear is neccessary for non-syscall rtraps only */
+user_nowork:
 		bne,pn			%xcc, __handle_userfpu
-		 stb			%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
+		 stb			%g0, [%g6 + TI_FPDEPTH]
 __handle_userfpu_continue:
 
 rt_continue:	ldx			[%sp + PTREGS_OFF + PT_V9_G1], %g1
@@ -254,14 +261,14 @@
 
 kern_rtt:	restore
 		retry
-to_kernel:	ldub			[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
+to_kernel:	ldub			[%g6 + TI_FPDEPTH], %l5
 		brz,pt			%l5, rt_continue
 		 srl			%l5, 1, %o0
-		add			%g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6
+		add			%g6, TI_FPSAVED, %l6
 		ldub			[%l6 + %o0], %l2
 		sub			%l5, 2, %l5
 
-		add			%g6, AOFF_task_thread + AOFF_thread_gsr, %o1
+		add			%g6, TI_GSR, %o1
 		andcc			%l2, (FPRS_FEF|FPRS_DU), %g0
 		be,pt			%icc, 2f
 		 and			%l2, FPRS_DL, %l6
@@ -272,12 +279,12 @@
 
 		wr			%g5, FPRS_FEF, %fprs
 		ldx			[%o1 + %o5], %g5
-		add			%g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
+		add			%g6, TI_XFSR, %o1
 		membar			#StoreLoad | #LoadLoad
 		sll			%o0, 8, %o2
-		add			%g6, AOFF_task_fpregs, %o3
+		add			%g6, TI_FPREGS, %o3
 		brz,pn			%l6, 1f
-		 add			%g6, AOFF_task_fpregs+0x40, %o4
+		 add			%g6, TI_FPREGS+0x40, %o4
 
 		ldda			[%o3 + %o2] ASI_BLK_P, %f0
 		ldda			[%o4 + %o2] ASI_BLK_P, %f16
@@ -290,20 +297,20 @@
 
 1:		membar			#Sync
 		ldx			[%o1 + %o5], %fsr
-2:		stb			%l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
+2:		stb			%l5, [%g6 + TI_FPDEPTH]
 		ba,pt			%xcc, rt_continue
 		 nop
 5:		wr			%g0, FPRS_FEF, %fprs
 		membar			#StoreLoad | #LoadLoad
 		sll			%o0, 8, %o2
 
-		add			%g6, AOFF_task_fpregs+0x80, %o3
-		add			%g6, AOFF_task_fpregs+0xc0, %o4
+		add			%g6, TI_FPREGS+0x80, %o3
+		add			%g6, TI_FPREGS+0xc0, %o4
 		ldda			[%o3 + %o2] ASI_BLK_P, %f32
 		ldda			[%o4 + %o2] ASI_BLK_P, %f48
 		membar			#Sync
 		wr			%g0, FPRS_DU, %fprs
 		ba,pt			%xcc, rt_continue
-		 stb			%l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
+		 stb			%l5, [%g6 + TI_FPDEPTH]
 
 #undef PTREGS_OFF
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index ba31e8a..3d6477b 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.71 2001-11-13 00:49:28 davem Exp $
+/*  $Id: setup.c,v 1.72 2002-02-09 19:49:30 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -536,7 +536,7 @@
 	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);	
 #endif
 
-	init_task.thread.kregs = &fake_swapper_regs;
+	init_task.thread_info->kregs = &fake_swapper_regs;
 
 #ifdef CONFIG_IP_PNP
 	if (!ic_set_manually) {
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 85b3fd6..9aae454 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.59 2002-02-08 03:57:14 davem Exp $
+/*  $Id: signal.c,v 1.60 2002-02-09 19:49:31 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -76,7 +76,6 @@
 asmlinkage void sparc64_set_context(struct pt_regs *regs)
 {
 	struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
-	struct thread_struct *tp = &current->thread;
 	mc_gregset_t *grp;
 	unsigned long pc, npc, tstate;
 	unsigned long fp, i7;
@@ -84,16 +83,16 @@
 	int err;
 
 	flush_user_windows();
-	if(tp->w_saved						||
-	   (((unsigned long)ucp) & (sizeof(unsigned long)-1))	||
-	   (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
+	if (get_thread_wsaved()					||
+	    (((unsigned long)ucp) & (sizeof(unsigned long)-1))	||
+	    (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
 		goto do_sigsegv;
 	grp  = &ucp->uc_mcontext.mc_gregs;
 	err  = __get_user(pc, &((*grp)[MC_PC]));
 	err |= __get_user(npc, &((*grp)[MC_NPC]));
-	if(err || ((pc | npc) & 3))
+	if (err || ((pc | npc) & 3))
 		goto do_sigsegv;
-	if(regs->u_regs[UREG_I1]) {
+	if (regs->u_regs[UREG_I1]) {
 		sigset_t set;
 
 		if (_NSIG_WORDS == 1) {
@@ -109,7 +108,7 @@
 		recalc_sigpending(current);
 		spin_unlock_irq(&current->sigmask_lock);
 	}
-	if ((tp->flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		pc &= 0xffffffff;
 		npc &= 0xffffffff;
 	}
@@ -143,8 +142,8 @@
 	      (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7])));
 
 	err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
-	if(fenab) {
-		unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
+	if (fenab) {
+		unsigned long *fpregs = current_thread_info()->fpregs;
 		unsigned long fprs;
 		
 		fprs_write(0);
@@ -157,9 +156,9 @@
 			err |= copy_from_user(fpregs+16,
 			 ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
 			 (sizeof(unsigned int) * 32));
-		err |= __get_user(current->thread.xfsr[0],
+		err |= __get_user(current_thread_info()->xfsr[0],
 				  &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
-		err |= __get_user(current->thread.gsr[0],
+		err |= __get_user(current_thread_info()->gsr[0],
 				  &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
 		regs->tstate &= ~TSTATE_PEF;
 	}
@@ -174,7 +173,6 @@
 asmlinkage void sparc64_get_context(struct pt_regs *regs)
 {
 	struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
-	struct thread_struct *tp = &current->thread;
 	mc_gregset_t *grp;
 	mcontext_t *mcp;
 	unsigned long fp, i7;
@@ -182,20 +180,20 @@
 	int err;
 
 	synchronize_user_stack();
-	if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
+	if (get_thread_wsaved() || clear_user(ucp, sizeof(*ucp)))
 		goto do_sigsegv;
 
 #if 1
 	fenab = 0; /* IMO get_context is like any other system call, thus modifies FPU state -jj */
 #else
-	fenab = (current->thread.fpsaved[0] & FPRS_FEF);
+	fenab = (current_thread_info()->fpsaved[0] & FPRS_FEF);
 #endif
 		
 	mcp = &ucp->uc_mcontext;
 	grp = &mcp->mc_gregs;
 
 	/* Skip over the trap instruction, first. */
-	if ((tp->flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc   = (regs->tnpc & 0xffffffff);
 		regs->tnpc  = (regs->tnpc + 4) & 0xffffffff;
 	} else {
@@ -238,11 +236,11 @@
 	err |= __put_user(i7, &(mcp->mc_i7));
 
 	err |= __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab));
-	if(fenab) {
-		unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
+	if (fenab) {
+		unsigned long *fpregs = current_thread_info()->fpregs;
 		unsigned long fprs;
 		
-		fprs = current->thread.fpsaved[0];
+		fprs = current_thread_info()->fpsaved[0];
 		if (fprs & FPRS_DL)
 			err |= copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
 					    (sizeof(unsigned int) * 32));
@@ -250,8 +248,8 @@
 			err |= copy_to_user(
                           ((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
 			  (sizeof(unsigned int) * 32));
-		err |= __put_user(current->thread.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
-		err |= __put_user(current->thread.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
+		err |= __put_user(current_thread_info()->xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
+		err |= __put_user(current_thread_info()->gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
 		err |= __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
 	}
 	if (err)
@@ -284,7 +282,7 @@
 	sigset_t saveset;
 
 #ifdef CONFIG_SPARC32_COMPAT
-	if (current->thread.flags & SPARC_FLAG_32BIT) {
+	if (test_thread_flag(TIF_32BIT)) {
 		extern asmlinkage void _sigpause32_common(old_sigset_t32,
 							  struct pt_regs *);
 		_sigpause32_common(set, regs);
@@ -298,7 +296,7 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc = (regs->tnpc & 0xffffffff);
 		regs->tnpc = (regs->tnpc + 4) & 0xffffffff;
 	} else {
@@ -358,7 +356,7 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc = (regs->tnpc & 0xffffffff);
 		regs->tnpc = (regs->tnpc + 4) & 0xffffffff;
 	} else {
@@ -388,7 +386,7 @@
 static inline int
 restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
-	unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
+	unsigned long *fpregs = current_thread_info()->fpregs;
 	unsigned long fprs;
 	int err;
 
@@ -401,9 +399,9 @@
 	if (fprs & FPRS_DU)
 		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
 		       	       (sizeof(unsigned int) * 32));
-	err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr);
-	err |= __get_user(current->thread.gsr[0], &fpu->si_gsr);
-	current->thread.fpsaved[0] |= fprs;
+	err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+	err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+	current_thread_info()->fpsaved[0] |= fprs;
 	return err;
 }
 
@@ -426,7 +424,7 @@
 
 	err = get_user(tpc, &sf->regs.tpc);
 	err |= __get_user(tnpc, &sf->regs.tnpc);
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		tpc &= 0xffffffff;
 		tnpc &= 0xffffffff;
 	}
@@ -483,15 +481,15 @@
 	unsigned long fprs;
 	int err = 0;
 	
-	fprs = current->thread.fpsaved[0];
+	fprs = current_thread_info()->fpsaved[0];
 	if (fprs & FPRS_DL)
 		err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
 				    (sizeof(unsigned int) * 32));
 	if (fprs & FPRS_DU)
 		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
 				    (sizeof(unsigned int) * 32));
-	err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr);
-	err |= __put_user(current->thread.gsr[0], &fpu->si_gsr);
+	err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+	err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
 	err |= __put_user(fprs, &fpu->si_fprs);
 
 	return err;
@@ -524,7 +522,7 @@
 	save_and_clear_fpu();
 	
 	sigframe_size = RT_ALIGNEDSZ;
-	if (!(current->thread.fpsaved[0] & FPRS_FEF))
+	if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 
 	sf = (struct rt_signal_frame *)get_sigframe(ka, regs, sigframe_size);
@@ -532,7 +530,7 @@
 	if (invalid_frame_pointer (sf, sigframe_size))
 		goto sigill;
 
-	if (current->thread.w_saved != 0) {
+	if (get_thread_wsaved() != 0) {
 #ifdef DEBUG_SIGNALS
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
@@ -543,7 +541,7 @@
 	/* 2. Save the current process state */
 	err = copy_to_user(&sf->regs, regs, sizeof (*regs));
 
-	if (current->thread.fpsaved[0] & FPRS_FEF) {
+	if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
 		err |= save_fpu_state(regs, &sf->fpu_state);
 		err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
 	} else {
@@ -578,7 +576,7 @@
 	/* 5. signal handler */
 	regs->tpc = (unsigned long) ka->sa.sa_handler;
 	regs->tnpc = (regs->tpc + 4);
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -597,9 +595,9 @@
 				 sigset_t *oldset, struct pt_regs *regs)
 {
 	setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
-	if(ka->sa.sa_flags & SA_ONESHOT)
+	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
-	if(!(ka->sa.sa_flags & SA_NOMASK)) {
+	if (!(ka->sa.sa_flags & SA_NOMASK)) {
 		spin_lock_irq(&current->sigmask_lock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 		sigaddset(&current->blocked,signr);
@@ -611,14 +609,14 @@
 static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
 				     struct sigaction *sa)
 {
-	switch(regs->u_regs[UREG_I0]) {
+	switch (regs->u_regs[UREG_I0]) {
 		case ERESTARTNOHAND:
 		no_system_call_restart:
 			regs->u_regs[UREG_I0] = EINTR;
 			regs->tstate |= (TSTATE_ICARRY|TSTATE_XCARRY);
 			break;
 		case ERESTARTSYS:
-			if(!(sa->sa_flags & SA_RESTART))
+			if (!(sa->sa_flags & SA_RESTART))
 				goto no_system_call_restart;
 		/* fallthrough */
 		case ERESTARTNOINTR:
@@ -699,7 +697,7 @@
 		oldset = &current->blocked;
 
 #ifdef CONFIG_SPARC32_COMPAT
-	if (current->thread.flags & SPARC_FLAG_32BIT) {
+	if (test_thread_flag(TIF_32BIT)) {
 		extern int do_signal32(sigset_t *, struct pt_regs *,
 				       unsigned long, int);
 		return do_signal32(oldset, regs, orig_i0, restart_syscall);
@@ -741,8 +739,8 @@
 		
 		ka = &current->sig->action[signr-1];
 		
-		if(ka->sa.sa_handler == SIG_IGN) {
-			if(signr != SIGCHLD)
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
 				continue;
 
                         /* sys_wait4() grabs the master kernel lock, so
@@ -750,16 +748,16 @@
                          * threaded and would not be that difficult to
                          * do anyways.
                          */
-                        while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+                        while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
                                 ;
 			continue;
 		}
-		if(ka->sa.sa_handler == SIG_DFL) {
+		if (ka->sa.sa_handler == SIG_DFL) {
 			unsigned long exit_code = signr;
 			
-			if(current->pid == 1)
+			if (current->pid == 1)
 				continue;
-			switch(signr) {
+			switch (signr) {
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
@@ -772,8 +770,8 @@
 					continue;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
-				     SA_NOCLDSTOP))
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
+				      SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
@@ -792,8 +790,8 @@
 					struct reg_window *rw = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 					unsigned long ins[8];
                                                 
-					while(rw &&
-					      !(((unsigned long) rw) & 0x3)) {
+					while (rw &&
+					       !(((unsigned long) rw) & 0x3)) {
 					        copy_from_user(ins, &rw->ins[0], sizeof(ins));
 						printk("Caller[%016lx](%016lx,%016lx,%016lx,%016lx,%016lx,%016lx)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
 						rw = (struct reg_window *)(unsigned long)(ins[6] + STACK_BIAS);
@@ -811,15 +809,15 @@
 				/* NOT REACHED */
 			}
 		}
-		if(restart_syscall)
+		if (restart_syscall)
 			syscall_restart(orig_i0, regs, &ka->sa);
 		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
 	}
-	if(restart_syscall &&
-	   (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
-	    regs->u_regs[UREG_I0] == ERESTARTSYS ||
-	    regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+	if (restart_syscall &&
+	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+	     regs->u_regs[UREG_I0] == ERESTARTSYS ||
+	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
 		/* replay the system call when we are done */
 		regs->u_regs[UREG_I0] = orig_i0;
 		regs->tpc -= 4;
@@ -830,12 +828,8 @@
 
 void do_notify_resume(sigset_t *oldset, struct pt_regs *regs,
 		      unsigned long orig_i0, int restart_syscall,
-		      unsigned int work_pending)
+		      unsigned long thread_info_flags)
 {
-	/* We don't pass in the task_work struct as a struct because
-	 * GCC always bounces that onto the stack due to the
-	 * ABI calling conventions.
-	 */
-	if (work_pending & 0x0000ff00)
+	if (thread_info_flags & _TIF_SIGPENDING)
 		do_signal(oldset, regs, orig_i0, restart_syscall);
 }
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 0549a6d..ed0b8dc 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.73 2002-02-08 03:57:14 davem Exp $
+/*  $Id: signal32.c,v 1.74 2002-02-09 19:49:30 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -156,7 +156,7 @@
 	
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -211,7 +211,7 @@
 	
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -237,7 +237,7 @@
 
 static inline int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
-	unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
+	unsigned long *fpregs = current_thread_info()->fpregs;
 	unsigned long fprs;
 	int err;
 	
@@ -248,9 +248,9 @@
 		err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
 	if (fprs & FPRS_DU)
 		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
-	err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr);
-	err |= __get_user(current->thread.gsr[0], &fpu->si_gsr);
-	current->thread.fpsaved[0] |= fprs;
+	err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+	err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+	current_thread_info()->fpsaved[0] |= fprs;
 	return err;
 }
 
@@ -277,7 +277,7 @@
 	if ((pc | npc) & 3)
 		goto segv;
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		pc &= 0xffffffff;
 		npc &= 0xffffffff;
 	}
@@ -335,20 +335,20 @@
 	int err;
 
 	synchronize_user_stack();
-	if (current->thread.flags & SPARC_FLAG_NEWSIGNALS)
+	if (test_thread_flag(TIF_NEWSIGNALS))
 		return do_new_sigreturn32(regs);
 
 	scptr = (struct sigcontext32 *)
 		(regs->u_regs[UREG_I0] & 0x00000000ffffffffUL);
 	/* Check sanity of the user arg. */
-	if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
-	   (((unsigned long) scptr) & 3))
+	if (verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
+	    (((unsigned long) scptr) & 3))
 		goto segv;
 
 	err = __get_user(pc, &scptr->sigc_pc);
 	err |= __get_user(npc, &scptr->sigc_npc);
 
-	if((pc | npc) & 3)
+	if ((pc | npc) & 3)
 		goto segv; /* Nice try. */
 
 	err |= __get_user(seta[0], &scptr->sigc_mask);
@@ -368,7 +368,7 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 	
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		pc &= 0xffffffff;
 		npc &= 0xffffffff;
 	}
@@ -415,7 +415,7 @@
 	if ((pc | npc) & 3)
 		goto segv;
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		pc &= 0xffffffff;
 		npc &= 0xffffffff;
 	}
@@ -510,7 +510,7 @@
 #endif	
 	unsigned psr;
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		pc &= 0xffffffff;
 		npc &= 0xffffffff;
 	}
@@ -555,20 +555,20 @@
 	err |= __put_user(pc, &sc->sigc_pc);
 	err |= __put_user(npc, &sc->sigc_npc);
 	psr = tstate_to_psr (regs->tstate);
-	if(current->thread.fpsaved[0] & FPRS_FEF)
+	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sc->sigc_psr);
 	err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
 	err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
-	err |= __put_user(current->thread.w_saved, &sc->sigc_oswins);
+	err |= __put_user(get_thread_wsaved(), &sc->sigc_oswins);
 #if 0
 /* w_saved is not currently used... */
-	if(current->thread.w_saved)
-		for(window = 0; window < current->thread.w_saved; window++) {
+	if (get_thread_wsaved())
+		for (window = 0; window < get_thread_wsaved(); window++) {
 			sc->sigc_spbuf[window] =
-				(char *)current->thread.rwbuf_stkptrs[window];
+				(char *) current_thread_info()->rwbuf_stkptrs[window];
 			err |= copy_to_user(&sc->sigc_wbuf[window],
-					    &current->thread.reg_window[window],
+					    &current_thread_info()->reg_window[window],
 					    sizeof(struct reg_window));
 		}
 	else
@@ -577,7 +577,7 @@
 				    (u32 *)(regs->u_regs[UREG_FP]),
 				    sizeof(struct reg_window32));
 		       
-	current->thread.w_saved = 0; /* So process is allowed to execute. */
+	set_thread_wsaved(0); /* So process is allowed to execute. */
 	err |= __put_user(signr, &sframep->sig_num);
 	sig_address = NULL;
 	sig_code = 0;
@@ -641,7 +641,7 @@
 	regs->u_regs[UREG_FP] = (unsigned long) sframep;
 	regs->tpc = (unsigned long) sa->sa_handler;
 	regs->tnpc = (regs->tpc + 4);
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -654,19 +654,19 @@
 
 static inline int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
-	unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
+	unsigned long *fpregs = current_thread_info()->fpregs;
 	unsigned long fprs;
 	int err = 0;
 	
-	fprs = current->thread.fpsaved[0];
+	fprs = current_thread_info()->fpsaved[0];
 	if (fprs & FPRS_DL)
 		err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
 				    (sizeof(unsigned int) * 32));
 	if (fprs & FPRS_DU)
 		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
 				    (sizeof(unsigned int) * 32));
-	err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr);
-	err |= __put_user(current->thread.gsr[0], &fpu->si_gsr);
+	err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+	err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
 	err |= __put_user(fprs, &fpu->si_fprs);
 
 	return err;
@@ -686,7 +686,7 @@
 	save_and_clear_fpu();
 	
 	sigframe_size = NF_ALIGNEDSZ;
-	if (!(current->thread.fpsaved[0] & FPRS_FEF))
+	if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 
 	sf = (struct new_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
@@ -699,7 +699,7 @@
 		goto sigill;
 	}
 
-	if (current->thread.w_saved != 0) {
+	if (get_thread_wsaved() != 0) {
 #ifdef DEBUG_SIGNALS
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
@@ -708,7 +708,7 @@
 	}
 
 	/* 2. Save the current process state */
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -716,7 +716,7 @@
 	err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
 	err |= __put_user(regs->y, &sf->info.si_regs.y);
 	psr = tstate_to_psr (regs->tstate);
-	if(current->thread.fpsaved[0] & FPRS_FEF)
+	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sf->info.si_regs.psr);
 	for (i = 0; i < 16; i++)
@@ -762,7 +762,7 @@
 	/* 4. signal handler */
 	regs->tpc = (unsigned long) ka->sa.sa_handler;
 	regs->tnpc = (regs->tpc + 4);
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -781,10 +781,10 @@
 	
 		err  = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
 		err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
-		if(err)
+		if (err)
 			goto sigsegv;
 
-		if(pte_present(*ptep)) {
+		if (pte_present(*ptep)) {
 			unsigned long page = (unsigned long) page_address(pte_page(*ptep));
 
 			__asm__ __volatile__(
@@ -857,14 +857,14 @@
 		err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
 	
 	/* Store registers */
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
 	err |= __put_user(regs->tpc, &((*gr) [SVR4_PC]));
 	err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
 	psr = tstate_to_psr (regs->tstate);
-	if(current->thread.fpsaved[0] & FPRS_FEF)
+	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &((*gr) [SVR4_PSR]));
 	err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
@@ -886,7 +886,7 @@
 	err |= __put_user((u32)(long)gw, &mc->gwin);
 	    
 	/* 2. Number of windows to restore at setcontext (): */
-	err |= __put_user(current->thread.w_saved, &gw->count);
+	err |= __put_user(get_thread_wsaved(), &gw->count);
 
 	/* 3. Save each valid window
 	 *    Currently, it makes a copy of the windows from the kernel copy.
@@ -900,18 +900,18 @@
 	 *    to flush the user windows.
 	 */
 #if 0	 
-	for(window = 0; window < current->thread.w_saved; window++) {
-		err |= __put_user((int *) &(gw->win [window]),
-				  (int **)gw->winptr +window );
-		err |= copy_to_user(&gw->win [window],
-				    &current->thread.reg_window [window],
+	for (window = 0; window < get_thread_wsaved(); window++) {
+		err |= __put_user((int *) &(gw->win[window]),
+				  (int **) gw->winptr + window);
+		err |= copy_to_user(&gw->win[window],
+				    &current_thread_info()->reg_window[window],
 				    sizeof (svr4_rwindow_t));
-		err |= __put_user(0, (int *)gw->winptr + window);
+		err |= __put_user(0, (int *) gw->winptr + window);
 	}
 #endif	
 
 	/* 4. We just pay attention to the gw->count field on setcontext */
-	current->thread.w_saved = 0; /* So process is allowed to execute. */
+	set_thread_wsaved(0); /* So process is allowed to execute. */
 
 	/* Setup the signal information.  Solaris expects a bunch of
 	 * information to be passed to the signal handler, we don't provide
@@ -925,7 +925,7 @@
 	regs->u_regs[UREG_FP] = (unsigned long) sfp;
 	regs->tpc = (unsigned long) sa->sa_handler;
 	regs->tnpc = (regs->tpc + 4);
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -966,8 +966,10 @@
 	synchronize_user_stack();
 	save_and_clear_fpu();
 	
-	if (current->thread.w_saved){
-		printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->thread.w_saved);
+	if (get_thread_wsaved()) {
+#ifdef DEBUG_SIGNALS
+		printk ("Uh oh, w_saved is not zero (%d)\n", (int) get_thread_wsaved());
+#endif
 		do_exit (SIGSEGV);
 	}
 	err = clear_user(uc, sizeof (*uc));
@@ -986,7 +988,7 @@
 		err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
 
 	/* Store registers */
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -996,7 +998,7 @@
 	err |= __put_user(0, &uc->mcontext.greg [SVR4_PSR]);
 #else
 	i = tstate_to_psr(regs->tstate) & ~PSR_EF;		   
-	if (current->thread.fpsaved[0] & FPRS_FEF)
+	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
 		i |= PSR_EF;
 	err |= __put_user(i, &uc->mcontext.greg [SVR4_PSR]);
 #endif
@@ -1023,7 +1025,6 @@
 /* Set the context for a svr4 application, this is Solaris way to sigreturn */
 asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
 {
-	struct thread_struct *tp = &current->thread;
 	svr4_gregset_t  *gr;
 	u32 pc, npc, psr;
 	sigset_t set;
@@ -1036,8 +1037,10 @@
 	 */
 	flush_user_windows();
 	
-	if (tp->w_saved){
-		printk ("Uh oh, w_saved is: 0x%x\n", tp->w_saved);
+	if (get_thread_wsaved()) {
+#ifdef DEBUG_SIGNALS	
+		printk ("Uh oh, w_saved is: 0x%x\n", get_thread_wsaved());
+#endif
 		goto sigsegv;
 	}
 	if (((unsigned long) c) & 3){
@@ -1045,7 +1048,7 @@
 		goto sigsegv;
 	}
 
-	if(!__access_ok((unsigned long)c, sizeof(*c))) {
+	if (!__access_ok((unsigned long)c, sizeof(*c))) {
 		/* Miguel, add nice debugging msg _here_. ;-) */
 		goto sigsegv;
 	}
@@ -1054,7 +1057,7 @@
 	gr = &c->mcontext.greg;
 	err = __get_user(pc, &((*gr)[SVR4_PC]));
 	err |= __get_user(npc, &((*gr)[SVR4_NPC]));
-	if((pc | npc) & 3) {
+	if ((pc | npc) & 3) {
 #ifdef DEBUG_SIGNALS	
 	        printk ("setcontext, PC or nPC were bogus\n");
 #endif
@@ -1087,7 +1090,7 @@
 	spin_unlock_irq(&current->sigmask_lock);
 	regs->tpc = pc;
 	regs->tnpc = npc | 1;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1096,7 +1099,7 @@
 	regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
 	regs->tstate |= psr_to_tstate_icc(psr);
 #if 0	
-	if(psr & PSR_EF)
+	if (psr & PSR_EF)
 		regs->tstate |= TSTATE_PEF;
 #endif
 	/* Restore g[1..7] and o[0..7] registers */
@@ -1104,7 +1107,7 @@
 		err |= __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
 	for (i = 0; i < 8; i++)
 		err |= __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
-	if(err)
+	if (err)
 		goto sigsegv;
 
 	return -EINTR;
@@ -1127,7 +1130,7 @@
 	save_and_clear_fpu();
 	
 	sigframe_size = RT_ALIGNEDSZ;
-	if (!(current->thread.fpsaved[0] & FPRS_FEF))
+	if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
 		sigframe_size -= sizeof(__siginfo_fpu_t);
 
 	sf = (struct rt_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
@@ -1140,7 +1143,7 @@
 		goto sigill;
 	}
 
-	if (current->thread.w_saved != 0) {
+	if (get_thread_wsaved() != 0) {
 #ifdef DEBUG_SIGNALS
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
@@ -1149,7 +1152,7 @@
 	}
 
 	/* 2. Save the current process state */
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1157,7 +1160,7 @@
 	err |= __put_user(regs->tnpc, &sf->regs.npc);
 	err |= __put_user(regs->y, &sf->regs.y);
 	psr = tstate_to_psr (regs->tstate);
-	if(current->thread.fpsaved[0] & FPRS_FEF)
+	if (current_thread_info()->fpsaved[0] & FPRS_FEF)
 		psr |= PSR_EF;
 	err |= __put_user(psr, &sf->regs.psr);
 	for (i = 0; i < 16; i++)
@@ -1208,7 +1211,7 @@
 	/* 4. signal handler */
 	regs->tpc = (unsigned long) ka->sa.sa_handler;
 	regs->tnpc = (regs->tpc + 4);
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1233,7 +1236,7 @@
 		if (err)
 			goto sigsegv;
 
-		if(pte_present(*ptep)) {
+		if (pte_present(*ptep)) {
 			unsigned long page = (unsigned long) page_address(pte_page(*ptep));
 
 			__asm__ __volatile__(
@@ -1256,19 +1259,19 @@
 				   sigset_t *oldset, struct pt_regs *regs,
 				   int svr4_signal)
 {
-	if(svr4_signal)
+	if (svr4_signal)
 		setup_svr4_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset);
 	else {
 		if (ka->sa.sa_flags & SA_SIGINFO)
 			setup_rt_frame32(ka, regs, signr, oldset, info);
-		else if (current->thread.flags & SPARC_FLAG_NEWSIGNALS)
+		else if (test_thread_flag(TIF_NEWSIGNALS))
 			new_setup_frame32(ka, regs, signr, oldset);
 		else
 			setup_frame32(&ka->sa, regs, signr, oldset, info);
 	}
-	if(ka->sa.sa_flags & SA_ONESHOT)
+	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
-	if(!(ka->sa.sa_flags & SA_NOMASK)) {
+	if (!(ka->sa.sa_flags & SA_NOMASK)) {
 		spin_lock_irq(&current->sigmask_lock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 		sigaddset(&current->blocked,signr);
@@ -1280,14 +1283,14 @@
 static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
 				     struct sigaction *sa)
 {
-	switch(regs->u_regs[UREG_I0]) {
+	switch (regs->u_regs[UREG_I0]) {
 		case ERESTARTNOHAND:
 		no_system_call_restart:
 			regs->u_regs[UREG_I0] = EINTR;
 			regs->tstate |= TSTATE_ICARRY;
 			break;
 		case ERESTARTSYS:
-			if(!(sa->sa_flags & SA_RESTART))
+			if (!(sa->sa_flags & SA_RESTART))
 				goto no_system_call_restart;
 		/* fallthrough */
 		case ERESTARTNOINTR:
@@ -1402,8 +1405,8 @@
 		
 		ka = &current->sig->action[signr-1];
 		
-		if(ka->sa.sa_handler == SIG_IGN) {
-			if(signr != SIGCHLD)
+		if (ka->sa.sa_handler == SIG_IGN) {
+			if (signr != SIGCHLD)
 				continue;
 
 			/* sys_wait4() grabs the master kernel lock, so
@@ -1411,16 +1414,16 @@
 			 * threaded and would not be that difficult to
 			 * do anyways.
 			 */
-			while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
 				;
 			continue;
 		}
-		if(ka->sa.sa_handler == SIG_DFL) {
+		if (ka->sa.sa_handler == SIG_DFL) {
 			unsigned long exit_code = signr;
 			
-			if(current->pid == 1)
+			if (current->pid == 1)
 				continue;
-			switch(signr) {
+			switch (signr) {
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
@@ -1433,8 +1436,8 @@
 					continue;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
-				     SA_NOCLDSTOP))
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
+				      SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
@@ -1457,15 +1460,15 @@
 					extern void sparc_ultra_dump_dtlb(void);
 					sparc_ultra_dump_dtlb();
 					sparc_ultra_dump_itlb();
-				} while(0);
+				} while (0);
 #endif
 #ifdef DEBUG_SIGNALS_TRACE
 				{
 					struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff);
 					unsigned int ins[8];
 
-					while(rw &&
-					      !(((unsigned long) rw) & 0x3)) {
+					while (rw &&
+					       !(((unsigned long) rw) & 0x3)) {
 						copy_from_user(ins, &rw->ins[0], sizeof(ins));
 						printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
 						rw = (struct reg_window32 *)(unsigned long)ins[6];
@@ -1483,15 +1486,15 @@
 				/* NOT REACHED */
 			}
 		}
-		if(restart_syscall)
+		if (restart_syscall)
 			syscall_restart32(orig_i0, regs, &ka->sa);
 		handle_signal32(signr, ka, &info, oldset, regs, svr4_signal);
 		return 1;
 	}
-	if(restart_syscall &&
-	   (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
-	    regs->u_regs[UREG_I0] == ERESTARTSYS ||
-	    regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+	if (restart_syscall &&
+	    (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+	     regs->u_regs[UREG_I0] == ERESTARTSYS ||
+	     regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
 		/* replay the system call when we are done */
 		regs->u_regs[UREG_I0] = orig_i0;
 		regs->tpc -= 4;
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 988b6a9..218b9d3 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -212,7 +212,7 @@
 	/* Clear this or we will die instantly when we
 	 * schedule back to this idler...
 	 */
-	current->thread.flags &= ~(SPARC_FLAG_NEWCHILD);
+	clear_thread_flag(TIF_NEWCHILD);
 
 	/* Attach to the address space of init_task. */
 	atomic_inc(&init_mm.mm_count);
@@ -236,7 +236,7 @@
  * 32-bits (I think) so to be safe we have it read the pointer
  * contained here so we work on >4GB machines. -DaveM
  */
-static struct task_struct *cpu_new_task = NULL;
+static struct thread_info *cpu_new_thread = NULL;
 
 static void smp_tune_scheduling(void);
 
@@ -261,7 +261,7 @@
 			goto ignorecpu;
 		if (cpu_present_map & (1UL << i)) {
 			unsigned long entry = (unsigned long)(&sparc64_cpu_startup);
-			unsigned long cookie = (unsigned long)(&cpu_new_task);
+			unsigned long cookie = (unsigned long)(&cpu_new_thread);
 			struct task_struct *p;
 			int timeout;
 			int no;
@@ -280,7 +280,7 @@
 			for (no = 0; no < linux_num_cpus; no++)
 				if (linux_cpus[no].mid == i)
 					break;
-			cpu_new_task = p;
+			cpu_new_thread = p->thread_info;
 			prom_startcpu(linux_cpus[no].prom_node,
 				      entry, cookie);
 			for (timeout = 0; timeout < 5000000; timeout++) {
@@ -305,7 +305,7 @@
 			__cpu_number_map[i] = -1;
 		}
 	}
-	cpu_new_task = NULL;
+	cpu_new_thread = NULL;
 	if (cpucount == 0) {
 		if (max_cpus != 1)
 			printk("Error: only one processor found.\n");
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 7e833f1..f810ab8 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.120 2001-12-21 04:56:15 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.121 2002-02-09 19:49:31 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -80,6 +80,11 @@
 extern void tl0_solaris(void);
 extern void sys_sigsuspend(void);
 extern int sys_getppid(void);
+extern int sys_getpid(void);
+extern int sys_geteuid(void);
+extern int sys_getuid(void);
+extern int sys_getegid(void);
+extern int sys_getgid(void);
 extern int svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
 extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs);
 extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
@@ -307,6 +312,11 @@
 EXPORT_SYMBOL(tl0_solaris);
 EXPORT_SYMBOL(sys_sigsuspend);
 EXPORT_SYMBOL(sys_getppid);
+EXPORT_SYMBOL(sys_getpid);
+EXPORT_SYMBOL(sys_geteuid);
+EXPORT_SYMBOL(sys_getuid);
+EXPORT_SYMBOL(sys_getegid);
+EXPORT_SYMBOL(sys_getgid);
 EXPORT_SYMBOL(svr4_getcontext);
 EXPORT_SYMBOL(svr4_setcontext);
 EXPORT_SYMBOL(prom_cpu_nodes);
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 90852ef..7ef96cc 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.56 2001-12-21 04:56:15 davem Exp $
+/* $Id: sys_sparc.c,v 1.57 2002-02-09 19:49:30 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -59,7 +59,7 @@
 		return addr;
 	}
 
-	if (current->thread.flags & SPARC_FLAG_32BIT)
+	if (test_thread_flag(TIF_32BIT))
 		task_size = 0xf0000000UL;
 	if (len > task_size || len > -PAGE_OFFSET)
 		return -ENOMEM;
@@ -140,7 +140,7 @@
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
 	/* People could try to be nasty and use ta 0x6d in 32bit programs */
-	if ((current->thread.flags & SPARC_FLAG_32BIT) &&
+	if (test_thread_flag(TIF_32BIT) &&
 	    brk >= 0xf0000000UL)
 		return current->mm->brk;
 
@@ -289,7 +289,7 @@
 	len = PAGE_ALIGN(len);
 	retval = -EINVAL;
 
-	if (current->thread.flags & SPARC_FLAG_32BIT) {
+	if (test_thread_flag(TIF_32BIT)) {
 		if (len > 0xf0000000UL ||
 		    ((flags & MAP_FIXED) && addr > 0xf0000000UL - len))
 			goto out_putf;
@@ -334,7 +334,7 @@
 {
 	struct vm_area_struct *vma;
 	unsigned long ret = -EINVAL;
-	if (current->thread.flags & SPARC_FLAG_32BIT)
+	if (test_thread_flag(TIF_32BIT))
 		goto out;
 	if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET)
 		goto out;
@@ -401,7 +401,7 @@
 {
 	siginfo_t info;
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -454,7 +454,7 @@
 
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -474,7 +474,7 @@
 
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -494,11 +494,11 @@
 		return -EINVAL;
 	if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
 		if (old_p) {
-			if (!current->thread.utraps) {
+			if (!current_thread_info()->utraps) {
 				if (put_user(NULL, old_p))
 					return -EFAULT;
 			} else {
-				if (put_user((utrap_handler_t)(current->thread.utraps[type]), old_p))
+				if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p))
 					return -EFAULT;
 			}
 		}
@@ -508,39 +508,39 @@
 		}
 		return 0;
 	}
-	if (!current->thread.utraps) {
-		current->thread.utraps =
+	if (!current_thread_info()->utraps) {
+		current_thread_info()->utraps =
 			kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
-		if (!current->thread.utraps) return -ENOMEM;
-		current->thread.utraps[0] = 1;
-		memset(current->thread.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
+		if (!current_thread_info()->utraps) return -ENOMEM;
+		current_thread_info()->utraps[0] = 1;
+		memset(current_thread_info()->utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
 	} else {
-		if ((utrap_handler_t)current->thread.utraps[type] != new_p &&
-		    current->thread.utraps[0] > 1) {
-			long *p = current->thread.utraps;
+		if ((utrap_handler_t)current_thread_info()->utraps[type] != new_p &&
+		    current_thread_info()->utraps[0] > 1) {
+			long *p = current_thread_info()->utraps;
 
-			current->thread.utraps =
+			current_thread_info()->utraps =
 				kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long),
 					GFP_KERNEL);
-			if (!current->thread.utraps) {
-				current->thread.utraps = p;
+			if (!current_thread_info()->utraps) {
+				current_thread_info()->utraps = p;
 				return -ENOMEM;
 			}
 			p[0]--;
-			current->thread.utraps[0] = 1;
-			memcpy(current->thread.utraps+1, p+1,
+			current_thread_info()->utraps[0] = 1;
+			memcpy(current_thread_info()->utraps+1, p+1,
 			       UT_TRAP_INSTRUCTION_31*sizeof(long));
 		}
 	}
 	if (old_p) {
-		if (put_user((utrap_handler_t)(current->thread.utraps[type]), old_p))
+		if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p))
 			return -EFAULT;
 	}
 	if (old_d) {
 		if (put_user(NULL, old_d))
 			return -EFAULT;
 	}
-	current->thread.utraps[type] = (long)new_p;
+	current_thread_info()->utraps[type] = (long)new_p;
 
 	return 0;
 }
@@ -589,10 +589,10 @@
 	unsigned long pic, tmp;
 
 	read_pic(pic);
-	tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
-	__put_user(tmp, current->thread.user_cntd0);
-	tmp = (current->thread.kernel_cntd1 += (pic >> 32));
-	__put_user(tmp, current->thread.user_cntd1);
+	tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic);
+	__put_user(tmp, current_thread_info()->user_cntd0);
+	tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32));
+	__put_user(tmp, current_thread_info()->user_cntd1);
 	reset_pic();
 }
 
@@ -603,24 +603,24 @@
 
 	switch(opcode) {
 	case PERFCTR_ON:
-		current->thread.pcr_reg = arg2;
-		current->thread.user_cntd0 = (u64 *) arg0;
-		current->thread.user_cntd1 = (u64 *) arg1;
-		current->thread.kernel_cntd0 =
-			current->thread.kernel_cntd1 = 0;
+		current_thread_info()->pcr_reg = arg2;
+		current_thread_info()->user_cntd0 = (u64 *) arg0;
+		current_thread_info()->user_cntd1 = (u64 *) arg1;
+		current_thread_info()->kernel_cntd0 =
+			current_thread_info()->kernel_cntd1 = 0;
 		write_pcr(arg2);
 		reset_pic();
-		current->thread.flags |= SPARC_FLAG_PERFCTR;
+		set_thread_flag(TIF_PERFCTR);
 		break;
 
 	case PERFCTR_OFF:
 		err = -EINVAL;
-		if ((current->thread.flags & SPARC_FLAG_PERFCTR) != 0) {
-			current->thread.user_cntd0 =
-				current->thread.user_cntd1 = NULL;
-			current->thread.pcr_reg = 0;
+		if (test_thread_flag(TIF_PERFCTR)) {
+			current_thread_info()->user_cntd0 =
+				current_thread_info()->user_cntd1 = NULL;
+			current_thread_info()->pcr_reg = 0;
 			write_pcr(0);
-			current->thread.flags &= ~(SPARC_FLAG_PERFCTR);
+			clear_thread_flag(TIF_PERFCTR);
 			err = 0;
 		}
 		break;
@@ -628,50 +628,50 @@
 	case PERFCTR_READ: {
 		unsigned long pic, tmp;
 
-		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
+		if (!test_thread_flag(TIF_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
 		read_pic(pic);
-		tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
-		err |= __put_user(tmp, current->thread.user_cntd0);
-		tmp = (current->thread.kernel_cntd1 += (pic >> 32));
-		err |= __put_user(tmp, current->thread.user_cntd1);
+		tmp = (current_thread_info()->kernel_cntd0 += (unsigned int)pic);
+		err |= __put_user(tmp, current_thread_info()->user_cntd0);
+		tmp = (current_thread_info()->kernel_cntd1 += (pic >> 32));
+		err |= __put_user(tmp, current_thread_info()->user_cntd1);
 		reset_pic();
 		break;
 	}
 
 	case PERFCTR_CLRPIC:
-		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
+		if (!test_thread_flag(TIF_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
-		current->thread.kernel_cntd0 =
-			current->thread.kernel_cntd1 = 0;
+		current_thread_info()->kernel_cntd0 =
+			current_thread_info()->kernel_cntd1 = 0;
 		reset_pic();
 		break;
 
 	case PERFCTR_SETPCR: {
 		u64 *user_pcr = (u64 *)arg0;
-		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
+		if (!test_thread_flag(TIF_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
-		err |= __get_user(current->thread.pcr_reg, user_pcr);
-		write_pcr(current->thread.pcr_reg);
-		current->thread.kernel_cntd0 =
-			current->thread.kernel_cntd1 = 0;
+		err |= __get_user(current_thread_info()->pcr_reg, user_pcr);
+		write_pcr(current_thread_info()->pcr_reg);
+		current_thread_info()->kernel_cntd0 =
+			current_thread_info()->kernel_cntd1 = 0;
 		reset_pic();
 		break;
 	}
 
 	case PERFCTR_GETPCR: {
 		u64 *user_pcr = (u64 *)arg0;
-		if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
+		if (!test_thread_flag(TIF_PERFCTR)) {
 			err = -EINVAL;
 			break;
 		}
-		err |= __put_user(current->thread.pcr_reg, user_pcr);
+		err |= __put_user(current_thread_info()->pcr_reg, user_pcr);
 		break;
 	}
 
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 4444547..b5a876d 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.183 2002-02-08 03:57:14 davem Exp $
+/* $Id: sys_sparc32.c,v 1.184 2002-02-09 19:49:31 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -2726,8 +2726,8 @@
         struct k_sigaction new_ka, old_ka;
         int ret;
 
-	if(sig < 0) {
-		current->thread.flags |= SPARC_FLAG_NEWSIGNALS;
+	if (sig < 0) {
+		set_thread_flag(TIF_NEWSIGNALS);
 		sig = -sig;
 	}
 
@@ -2771,7 +2771,7 @@
 	/* All tasks which use RT signals (effectively) use
 	 * new style signals.
 	 */
-	current->thread.flags |= SPARC_FLAG_NEWSIGNALS;
+	set_thread_flag(TIF_NEWSIGNALS);
 
         if (act) {
 		new_ka.ka_restorer = restorer;
@@ -2994,8 +2994,8 @@
 
 	if(!error) {
 		fprs_write(0);
-		current->thread.xfsr[0] = 0;
-		current->thread.fpsaved[0] = 0;
+		current_thread_info()->xfsr[0] = 0;
+		current_thread_info()->fpsaved[0] = 0;
 		regs->tstate &= ~TSTATE_PEF;
 	}
 out:
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index a9aec14..c0f90d3 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.63 2002-02-08 03:57:14 davem Exp $
+/* $Id: sys_sunos32.c,v 1.64 2002-02-09 19:49:31 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -455,8 +455,8 @@
 	siginfo_t info;
 	static int cnt;
 
-	regs = current->thread.kregs;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	regs = current_thread_info()->kregs;
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1046,7 +1046,7 @@
 		if(!kmbuf)
 			break;
 		sp = (struct sparc_stackf32 *)
-			(current->thread.kregs->u_regs[UREG_FP] & 0xffffffffUL);
+			(current_thread_info()->kregs->u_regs[UREG_FP] & 0xffffffffUL);
 		if(get_user(arg5, &sp->xxargs[0])) {
 			rval = -EFAULT;
 			kfree(kmbuf);
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 58b1229..b920d55 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.25 2002-01-11 08:45:38 davem Exp $
+/* $Id: trampoline.S,v 1.26 2002-02-09 19:49:30 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -14,7 +14,7 @@
 #include <asm/pgtable.h>
 #include <asm/spitfire.h>
 #include <asm/processor.h>
-#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
 
 	.data
 	.align	8
@@ -262,7 +262,7 @@
 	wrpr		%o1, PSTATE_IG, %pstate
 
 	/* Get our UPA MID. */
-	lduw		[%o2 + AOFF_task_cpu], %g1
+	ldub		[%o2 + TI_CPU], %g1
 	sethi		%hi(cpu_data), %g5
 	or		%g5, %lo(cpu_data), %g5
 
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index a89fcd4..3f8e7ab 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.84 2002-01-30 01:39:56 davem Exp $
+/* $Id: traps.c,v 1.85 2002-02-09 19:49:31 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -51,7 +51,7 @@
 		sprintf(buffer, "Kernel bad sw trap %lx", lvl);
 		die_if_kernel (buffer, regs);
 	}
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -89,7 +89,7 @@
 		       sfsr, sfar);
 		die_if_kernel("Iax", regs);
 	}
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1311,14 +1311,14 @@
 
 void do_fpe_common(struct pt_regs *regs)
 {
-	if(regs->tstate & TSTATE_PRIV) {
+	if (regs->tstate & TSTATE_PRIV) {
 		regs->tpc = regs->tnpc;
 		regs->tnpc += 4;
 	} else {
-		unsigned long fsr = current->thread.xfsr[0];
+		unsigned long fsr = current_thread_info()->xfsr[0];
 		siginfo_t info;
 
-		if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+		if (test_thread_flag(TIF_32BIT)) {
 			regs->tpc &= 0xffffffff;
 			regs->tnpc &= 0xffffffff;
 		}
@@ -1355,7 +1355,7 @@
 	struct fpustate *f = FPUSTATE;
 	int ret = 0;
 
-	switch ((current->thread.xfsr[0] & 0x1c000)) {
+	switch ((current_thread_info()->xfsr[0] & 0x1c000)) {
 	case (2 << 14): /* unfinished_FPop */
 	case (3 << 14): /* unimplemented_FPop */
 		ret = do_mathemu(regs, f);
@@ -1370,9 +1370,9 @@
 {
 	siginfo_t info;
 
-	if(regs->tstate & TSTATE_PRIV)
+	if (regs->tstate & TSTATE_PRIV)
 		die_if_kernel("Penguin overflow trap from kernel mode", regs);
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1388,7 +1388,7 @@
 {
 	siginfo_t info;
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1404,11 +1404,11 @@
 {
 	int i;
 
-	if((((unsigned long) pc) & 3))
+	if ((((unsigned long) pc) & 3))
 		return;
 
 	printk("Instruction DUMP:");
-	for(i = -3; i < 6; i++)
+	for (i = -3; i < 6; i++)
 		printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
 	printk("\n");
 }
@@ -1418,14 +1418,14 @@
 	int i;
 	unsigned int buf[9];
 	
-	if((((unsigned long) pc) & 3))
+	if ((((unsigned long) pc) & 3))
 		return;
 		
-	if(copy_from_user(buf, pc - 3, sizeof(buf)))
+	if (copy_from_user(buf, pc - 3, sizeof(buf)))
 		return;
 
 	printk("Instruction DUMP:");
-	for(i = 0; i < 9; i++)
+	for (i = 0; i < 9; i++)
 		printk("%c%08x%c",i==3?' ':'<',buf[i],i==3?' ':'>');
 	printk("\n");
 }
@@ -1433,18 +1433,18 @@
 void show_trace_task(struct task_struct *tsk)
 {
 	unsigned long pc, fp;
-	unsigned long task_base = (unsigned long)tsk;
+	unsigned long thread_base = (unsigned long) tsk->thread_info;
 	struct reg_window *rw;
 	int count = 0;
 
 	if (!tsk)
 		return;
 
-	fp = tsk->thread.ksp + STACK_BIAS;
+	fp = tsk->thread_info->ksp + STACK_BIAS;
 	do {
 		/* Bogus frame pointer? */
-		if (fp < (task_base + sizeof(struct task_struct)) ||
-		    fp >= (task_base + THREAD_SIZE))
+		if (fp < (thread_base + sizeof(struct thread_info)) ||
+		    fp >= (thread_base + THREAD_SIZE))
 			break;
 		rw = (struct reg_window *)fp;
 		pc = rw->ins[7];
@@ -1471,7 +1471,7 @@
 	printk("%s(%d): %s\n", current->comm, current->pid, str);
 	__asm__ __volatile__("flushw");
 	__show_regs(regs);
-	if(regs->tstate & TSTATE_PRIV) {
+	if (regs->tstate & TSTATE_PRIV) {
 		struct reg_window *rw = (struct reg_window *)
 			(regs->u_regs[UREG_FP] + STACK_BIAS);
 
@@ -1479,12 +1479,12 @@
 		 * find some badly aligned kernel stack.
 		 */
 		lastrw = (struct reg_window *)current;
-		while(rw					&&
-		      count++ < 30				&&
-		      rw >= lastrw				&&
-		      (char *) rw < ((char *) current)
-		        + sizeof (union task_union) 		&&
-		      !(((unsigned long) rw) & 0x7)) {
+		while (rw					&&
+		       count++ < 30				&&
+		       rw >= lastrw				&&
+		       (char *) rw < ((char *) current)
+		       + sizeof (union thread_union) 		&&
+		       !(((unsigned long) rw) & 0x7)) {
 			printk("Caller[%016lx]\n", rw->ins[7]);
 			lastrw = rw;
 			rw = (struct reg_window *)
@@ -1492,7 +1492,7 @@
 		}
 		instruction_dump ((unsigned int *) regs->tpc);
 	} else {
-		if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+		if (test_thread_flag(TIF_32BIT)) {
 			regs->tpc &= 0xffffffff;
 			regs->tnpc &= 0xffffffff;
 		}
@@ -1502,7 +1502,7 @@
 	smp_report_regs();
 #endif
                                                 	
-	if(regs->tstate & TSTATE_PRIV)
+	if (regs->tstate & TSTATE_PRIV)
 		do_exit(SIGKILL);
 	do_exit(SIGSEGV);
 }
@@ -1517,9 +1517,9 @@
 	u32 insn;
 	siginfo_t info;
 
-	if(tstate & TSTATE_PRIV)
+	if (tstate & TSTATE_PRIV)
 		die_if_kernel("Kernel illegal instruction", regs);
-	if(current->thread.flags & SPARC_FLAG_32BIT)
+	if (test_thread_flag(TIF_32BIT))
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ {
@@ -1542,7 +1542,7 @@
 {
 	siginfo_t info;
 
-	if(regs->tstate & TSTATE_PRIV) {
+	if (regs->tstate & TSTATE_PRIV) {
 		extern void kernel_unaligned_trap(struct pt_regs *regs,
 						  unsigned int insn, 
 						  unsigned long sfar, unsigned long sfsr);
@@ -1561,7 +1561,7 @@
 {
 	siginfo_t info;
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -1669,15 +1669,41 @@
 	regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate);
 	regs->tpc   = regs->tnpc;
 	regs->tnpc += 4;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
 }
 
+extern void thread_info_offsets_are_bolixed_dave(void);
+
 /* Only invoked on boot processor. */
 void trap_init(void)
 {
+	/* Compile time sanity check. */
+	if (TI_TASK != offsetof(struct thread_info, task) ||
+	    TI_FLAGS != offsetof(struct thread_info, flags) ||
+	    TI_CPU != offsetof(struct thread_info, cpu) ||
+	    TI_FPSAVED != offsetof(struct thread_info, fpsaved) ||
+	    TI_KSP != offsetof(struct thread_info, ksp) ||
+	    TI_FAULT_ADDR != offsetof(struct thread_info, fault_address) ||
+	    TI_KREGS != offsetof(struct thread_info, kregs) ||
+	    TI_UTRAPS != offsetof(struct thread_info, utraps) ||
+	    TI_EXEC_DOMAIN != offsetof(struct thread_info, exec_domain) ||
+	    TI_REG_WINDOW != offsetof(struct thread_info, reg_window) ||
+	    TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) ||
+	    TI_GSR != offsetof(struct thread_info, gsr) ||
+	    TI_XFSR != offsetof(struct thread_info, xfsr) ||
+	    TI_USER_CNTD0 != offsetof(struct thread_info, user_cntd0) ||
+	    TI_USER_CNTD1 != offsetof(struct thread_info, user_cntd1) ||
+	    TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) ||
+	    TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) ||
+	    TI_PCR != offsetof(struct thread_info, pcr_reg) ||
+	    TI_CEE_STUFF != offsetof(struct thread_info, cee_stuff) ||
+	    TI_FPREGS != offsetof(struct thread_info, fpregs) ||
+	    (TI_FPREGS & (64 - 1)))
+		thread_info_offsets_are_bolixed_dave();
+
 	/* Attach to the address space of init_task.  On SMP we
 	 * do this in smp.c:smp_callin for other cpus.
 	 */
@@ -1685,6 +1711,6 @@
 	current->active_mm = &init_mm;
 
 #ifdef CONFIG_SMP
-	current->cpu = hard_smp_processor_id();
+	current_thread_info()->cpu = hard_smp_processor_id();
 #endif
 }
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 3e15753..4e97540 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.37 2002-01-23 11:27:32 davem Exp $
+/* $Id: ttable.S,v 1.38 2002-02-09 19:49:30 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
  *
  * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
@@ -211,20 +211,20 @@
 tl1_paw:	TRAPTL1(do_paw_tl1)
 tl1_vaw:	TRAPTL1(do_vaw_tl1)
 
-		/* The grotty trick to save %g1 into current->thread.kernel_cntd0
+		/* The grotty trick to save %g1 into current->thread.cee_stuff
 		 * is because when we take this trap we could be interrupting trap
-		 * code already using the trap alternate global registers.  It is
-		 * better to corrupt a performance counter than corrupt trap register
-		 * state.  We cross our fingers and pray that this store/load does
+		 * code already using the trap alternate global registers.
+		 *
+		 * We cross our fingers and pray that this store/load does
 		 * not cause yet another CEE trap.
 		 */
 tl1_cee:	membar	#Sync
-		stx	%g1, [%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0]
+		stx	%g1, [%g6 + TI_CEE_STUFF]
 		ldxa	[%g0] ASI_AFSR, %g1
 		membar	#Sync
 		stxa	%g1, [%g0] ASI_AFSR
 		membar	#Sync
-		ldx	[%g6 + AOFF_task_thread + AOFF_thread_kernel_cntd0], %g1
+		ldx	[%g6 + TI_CEE_STUFF], %g1
 		retry
 
 tl1_iamiss:	BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67)
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index b6b5785..ec02076 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.23 2001-04-09 04:29:03 davem Exp $
+/* $Id: unaligned.c,v 1.24 2002-02-09 19:49:31 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -42,7 +42,7 @@
 {
 	unsigned long tmp = (insn >> 21) & 1;
 
-	if(!tmp)
+	if (!tmp)
 		return load;
 	else {
 		switch ((insn>>19)&0xf) {
@@ -63,15 +63,15 @@
 	if (tmp == 11 || tmp == 14) /* ldx/stx */
 		return 8;
 	tmp &= 3;
-	if(!tmp)
+	if (!tmp)
 		return 4;
-	else if(tmp == 3)
+	else if (tmp == 3)
 		return 16;	/* ldd/std - Although it is actually 8 */
-	else if(tmp == 2)
+	else if (tmp == 2)
 		return 2;
 	else {
 		printk("Impossible unaligned trap. insn=%08x\n", insn);
-		die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs);
+		die_if_kernel("Byte sized unaligned access?!?!", current_thread_info()->kregs);
 	}
 }
 
@@ -95,8 +95,8 @@
 static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
 				       unsigned int rd, int from_kernel)
 {
-	if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
-		if(from_kernel != 0)
+	if (rs2 >= 16 || rs1 >= 16 || rd >= 16) {
+		if (from_kernel != 0)
 			__asm__ __volatile__("flushw");
 		else
 			flushw_user();
@@ -112,13 +112,13 @@
 {
 	unsigned long value;
 	
-	if(reg < 16)
+	if (reg < 16)
 		return (!reg ? 0 : regs->u_regs[reg]);
 	if (regs->tstate & TSTATE_PRIV) {
 		struct reg_window *win;
 		win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 		value = win->locals[reg - 16];
-	} else if (current->thread.flags & SPARC_FLAG_32BIT) {
+	} else if (test_thread_flag(TIF_32BIT)) {
 		struct reg_window32 *win32;
 		win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 		get_user(value, &win32->locals[reg - 16]);
@@ -132,13 +132,13 @@
 
 static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
 {
-	if(reg < 16)
+	if (reg < 16)
 		return &regs->u_regs[reg];
 	if (regs->tstate & TSTATE_PRIV) {
 		struct reg_window *win;
 		win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 		return &win->locals[reg - 16];
-	} else if (current->thread.flags & SPARC_FLAG_32BIT) {
+	} else if (test_thread_flag(TIF_32BIT)) {
 		struct reg_window32 *win32;
 		win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 		return (unsigned long *)&win32->locals[reg - 16];
@@ -156,7 +156,7 @@
 	unsigned int rs2 = insn & 0x1f;
 	int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
 
-	if(insn & 0x2000) {
+	if (insn & 0x2000) {
 		maybe_flush_windows(rs1, 0, rd, from_kernel);
 		return (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
 	} else {
@@ -335,7 +335,7 @@
 {
 	regs->tpc   = regs->tnpc;
 	regs->tnpc += 4;
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
 	}
@@ -360,7 +360,7 @@
 
 	if (!fixup) {
 		unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f));
-        	if(address < PAGE_SIZE) {
+        	if (address < PAGE_SIZE) {
                 	printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
         	} else
                 	printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
@@ -387,7 +387,7 @@
 	enum direction dir = decode_direction(insn);
 	int size = decode_access_size(insn);
 
-	if(!ok_for_kernel(insn) || dir == both) {
+	if (!ok_for_kernel(insn) || dir == both) {
 		printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n",
 		       regs->tpc);
 		unaligned_panic("Kernel does fpu/atomic unaligned load/store.", regs);
@@ -408,7 +408,7 @@
 		printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n",
 		       regs->tpc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]);
 #endif
-		switch(dir) {
+		switch (dir) {
 		case load:
 			do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
 					size, (unsigned long *) addr,
@@ -459,11 +459,11 @@
 		ret += popc_helper[value & 0xf];
 		value >>= 4;
 	}
-	if(rd < 16) {
+	if (rd < 16) {
 		if (rd)
 			regs->u_regs[rd] = ret;
 	} else {
-		if (current->thread.flags & SPARC_FLAG_32BIT) {
+		if (test_thread_flag(TIF_32BIT)) {
 			struct reg_window32 *win32;
 			win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 			put_user(ret, &win32->locals[rd - 16]);
@@ -490,9 +490,9 @@
 	int flag = (freg < 32) ? FPRS_DL : FPRS_DU;
 
 	save_and_clear_fpu();
-	current->thread.xfsr[0] &= ~0x1c000;
+	current_thread_info()->xfsr[0] &= ~0x1c000;
 	if (freg & 3) {
-		current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+		current_thread_info()->xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 		do_fpother(regs);
 		return 0;
 	}
@@ -500,7 +500,7 @@
 		/* STQ */
 		u64 first = 0, second = 0;
 		
-		if (current->thread.fpsaved[0] & flag) {
+		if (current_thread_info()->fpsaved[0] & flag) {
 			first = *(u64 *)&f->regs[freg];
 			second = *(u64 *)&f->regs[freg+2];
 		}
@@ -575,18 +575,18 @@
 				break;
 			}
 		}
-		if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
-			current->thread.fpsaved[0] = FPRS_FEF;
-			current->thread.gsr[0] = 0;
+		if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) {
+			current_thread_info()->fpsaved[0] = FPRS_FEF;
+			current_thread_info()->gsr[0] = 0;
 		}
-		if (!(current->thread.fpsaved[0] & flag)) {
+		if (!(current_thread_info()->fpsaved[0] & flag)) {
 			if (freg < 32)
 				memset(f->regs, 0, 32*sizeof(u32));
 			else
 				memset(f->regs+32, 0, 32*sizeof(u32));
 		}
 		memcpy(f->regs + freg, data, size * 4);
-		current->thread.fpsaved[0] |= flag;
+		current_thread_info()->fpsaved[0] |= flag;
 	}
 	advance(regs);
 	return 1;
@@ -604,7 +604,7 @@
 		reg[0] = 0;
 		if ((insn & 0x780000) == 0x180000)
 			reg[1] = 0;
-	} else if (current->thread.flags & SPARC_FLAG_32BIT) {
+	} else if (test_thread_flag(TIF_32BIT)) {
 		put_user(0, (int *)reg);
 		if ((insn & 0x780000) == 0x180000)
 			put_user(0, ((int *)reg) + 1);
@@ -627,9 +627,9 @@
 	int flag;
 	struct fpustate *f = FPUSTATE;
 
-	if(tstate & TSTATE_PRIV)
+	if (tstate & TSTATE_PRIV)
 		die_if_kernel("lddfmna from kernel", regs);
-	if(current->thread.flags & SPARC_FLAG_32BIT)
+	if (test_thread_flag(TIF_32BIT))
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		asi = sfsr >> 16;
@@ -649,18 +649,18 @@
 		if (asi & 0x8) /* Little */
 			value = __swab64p(&value);
 		flag = (freg < 32) ? FPRS_DL : FPRS_DU;
-		if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
-			current->thread.fpsaved[0] = FPRS_FEF;
-			current->thread.gsr[0] = 0;
+		if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) {
+			current_thread_info()->fpsaved[0] = FPRS_FEF;
+			current_thread_info()->gsr[0] = 0;
 		}
-		if (!(current->thread.fpsaved[0] & flag)) {
+		if (!(current_thread_info()->fpsaved[0] & flag)) {
 			if (freg < 32)
 				memset(f->regs, 0, 32*sizeof(u32));
 			else
 				memset(f->regs+32, 0, 32*sizeof(u32));
 		}
 		*(u64 *)(f->regs + freg) = value;
-		current->thread.fpsaved[0] |= flag;
+		current_thread_info()->fpsaved[0] |= flag;
 	} else {
 daex:		data_access_exception(regs);
 		return;
@@ -679,9 +679,9 @@
 	int flag;
 	struct fpustate *f = FPUSTATE;
 
-	if(tstate & TSTATE_PRIV)
+	if (tstate & TSTATE_PRIV)
 		die_if_kernel("stdfmna from kernel", regs);
-	if(current->thread.flags & SPARC_FLAG_32BIT)
+	if (test_thread_flag(TIF_32BIT))
 		pc = (u32)pc;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
@@ -692,7 +692,7 @@
 		    (asi < ASI_P))
 			goto daex;
 		save_and_clear_fpu();
-		if (current->thread.fpsaved[0] & flag)
+		if (current_thread_info()->fpsaved[0] & flag)
 			value = *(u64 *)&f->regs[freg];
 		switch (asi) {
 		case ASI_P:
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index a802601..0257337 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.29 2000-03-26 09:13:48 davem Exp $
+/* $Id: winfixup.S,v 1.30 2002-02-09 19:49:30 davem Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -11,7 +11,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/spitfire.h>
-#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
 
 	.text
 	.align	32
@@ -69,8 +69,8 @@
 	mov		%g6, %o7			! Get current.
 
 	andn		%l1, PSTATE_MM, %l1		! We want to be in RMO
-	stb		%g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
-	stx		%g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
+	stb		%g4, [%g6 + TI_FAULT_CODE]
+	stx		%g5, [%g6 + TI_FAULT_ADDR]
 	wrpr		%g0, 0x0, %tl			! Out of trap levels.
 	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
 	sethi		%uhi(PAGE_OFFSET), %g4		! Prepare page_offset global reg
@@ -94,56 +94,56 @@
 	 * do not touch %g7 or %g2 so we handle the two cases fine.
 	 */
 spill_fixup:
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
-	andcc		%g1, SPARC_FLAG_32BIT, %g0
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
+	ldx		[%g6 + TI_FLAGS], %g1
+	andcc		%g1, _TIF_32BIT, %g0
+	ldub		[%g6 + TI_WSAVED], %g1
 
 	sll		%g1, 3, %g3
 	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
+	stx		%sp, [%g3 + TI_RWIN_SPTRS]
 	sll		%g1, 7, %g3
 	bne,pt		%xcc, 1f
 	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
-	stx		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+	stx		%l0, [%g3 + TI_REG_WINDOW + 0x00]
+	stx		%l1, [%g3 + TI_REG_WINDOW + 0x08]
 
-	stx		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
-	stx		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
-	stx		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
-	stx		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
-	stx		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
-	stx		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
-	stx		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
-	stx		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
+	stx		%l2, [%g3 + TI_REG_WINDOW + 0x10]
+	stx		%l3, [%g3 + TI_REG_WINDOW + 0x18]
+	stx		%l4, [%g3 + TI_REG_WINDOW + 0x20]
+	stx		%l5, [%g3 + TI_REG_WINDOW + 0x28]
+	stx		%l6, [%g3 + TI_REG_WINDOW + 0x30]
+	stx		%l7, [%g3 + TI_REG_WINDOW + 0x38]
+	stx		%i0, [%g3 + TI_REG_WINDOW + 0x40]
+	stx		%i1, [%g3 + TI_REG_WINDOW + 0x48]
 
-	stx		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
-	stx		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
-	stx		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
-	stx		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
-	stx		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
+	stx		%i2, [%g3 + TI_REG_WINDOW + 0x50]
+	stx		%i3, [%g3 + TI_REG_WINDOW + 0x58]
+	stx		%i4, [%g3 + TI_REG_WINDOW + 0x60]
+	stx		%i5, [%g3 + TI_REG_WINDOW + 0x68]
+	stx		%i6, [%g3 + TI_REG_WINDOW + 0x70]
 	b,pt		%xcc, 2f
-	 stx		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
-1:	stw		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+	 stx		%i7, [%g3 + TI_REG_WINDOW + 0x78]
+1:	stw		%l0, [%g3 + TI_REG_WINDOW + 0x00]
 
-	stw		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x04]
-	stw		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
-	stw		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x0c]
-	stw		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
-	stw		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x14]
-	stw		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
-	stw		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x1c]
-	stw		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+	stw		%l1, [%g3 + TI_REG_WINDOW + 0x04]
+	stw		%l2, [%g3 + TI_REG_WINDOW + 0x08]
+	stw		%l3, [%g3 + TI_REG_WINDOW + 0x0c]
+	stw		%l4, [%g3 + TI_REG_WINDOW + 0x10]
+	stw		%l5, [%g3 + TI_REG_WINDOW + 0x14]
+	stw		%l6, [%g3 + TI_REG_WINDOW + 0x18]
+	stw		%l7, [%g3 + TI_REG_WINDOW + 0x1c]
+	stw		%i0, [%g3 + TI_REG_WINDOW + 0x20]
 
-	stw		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x24]
-	stw		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
-	stw		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x2c]
-	stw		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
-	stw		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x34]
-	stw		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
-	stw		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x3c]
+	stw		%i1, [%g3 + TI_REG_WINDOW + 0x24]
+	stw		%i2, [%g3 + TI_REG_WINDOW + 0x28]
+	stw		%i3, [%g3 + TI_REG_WINDOW + 0x2c]
+	stw		%i4, [%g3 + TI_REG_WINDOW + 0x30]
+	stw		%i5, [%g3 + TI_REG_WINDOW + 0x34]
+	stw		%i6, [%g3 + TI_REG_WINDOW + 0x38]
+	stw		%i7, [%g3 + TI_REG_WINDOW + 0x3c]
 2:	add		%g1, 1, %g1
 
-	stb		%g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
+	stb		%g1, [%g6 + TI_WSAVED]
 	rdpr		%tstate, %g1
 	andcc		%g1, TSTATE_PRIV, %g0
 	saved
@@ -153,8 +153,8 @@
 	retry
 
 window_scheisse_from_user_common:
-	stb		%g4, [%g6 + AOFF_task_thread + AOFF_thread_fault_code]
-	stx		%g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
+	stb		%g4, [%g6 + TI_FAULT_CODE]
+	stx		%g5, [%g6 + TI_FAULT_ADDR]
 	wrpr		%g1, %cwp
 	ba,pt		%xcc, etrap
 	 rd		%pc, %g7
@@ -204,47 +204,47 @@
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
 spill_fixup_mna:
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
-	andcc		%g1, SPARC_FLAG_32BIT, %g0
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
+	ldx		[%g6 + TI_FLAGS], %g1
+	andcc		%g1, _TIF_32BIT, %g0
+	ldub		[%g6 + TI_WSAVED], %g1
 	sll		%g1, 3, %g3
 	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
+	stx		%sp, [%g3 + TI_RWIN_SPTRS]
 
 	sll		%g1, 7, %g3
 	bne,pt		%xcc, 1f
 	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
-	stx		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
-	stx		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
-	stx		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
-	stx		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+	stx		%l0, [%g3 + TI_REG_WINDOW + 0x00]
+	stx		%l1, [%g3 + TI_REG_WINDOW + 0x08]
+	stx		%l2, [%g3 + TI_REG_WINDOW + 0x10]
+	stx		%l3, [%g3 + TI_REG_WINDOW + 0x18]
+	stx		%l4, [%g3 + TI_REG_WINDOW + 0x20]
 
-	stx		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
-	stx		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
-	stx		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
-	stx		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
-	stx		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
-	stx		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
-	stx		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
-	stx		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+	stx		%l5, [%g3 + TI_REG_WINDOW + 0x28]
+	stx		%l6, [%g3 + TI_REG_WINDOW + 0x30]
+	stx		%l7, [%g3 + TI_REG_WINDOW + 0x38]
+	stx		%i0, [%g3 + TI_REG_WINDOW + 0x40]
+	stx		%i1, [%g3 + TI_REG_WINDOW + 0x48]
+	stx		%i2, [%g3 + TI_REG_WINDOW + 0x50]
+	stx		%i3, [%g3 + TI_REG_WINDOW + 0x58]
+	stx		%i4, [%g3 + TI_REG_WINDOW + 0x60]
 
-	stx		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
-	stx		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
-	stx		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
+	stx		%i5, [%g3 + TI_REG_WINDOW + 0x68]
+	stx		%i6, [%g3 + TI_REG_WINDOW + 0x70]
+	stx		%i7, [%g3 + TI_REG_WINDOW + 0x78]
 	b,pt		%xcc, 2f
 	 add		%g1, 1, %g1
-1:	std		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
-	std		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
-	std		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+1:	std		%l0, [%g3 + TI_REG_WINDOW + 0x00]
+	std		%l2, [%g3 + TI_REG_WINDOW + 0x08]
+	std		%l4, [%g3 + TI_REG_WINDOW + 0x10]
 
-	std		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
-	std		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
-	std		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
-	std		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
-	std		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+	std		%l6, [%g3 + TI_REG_WINDOW + 0x18]
+	std		%i0, [%g3 + TI_REG_WINDOW + 0x20]
+	std		%i2, [%g3 + TI_REG_WINDOW + 0x28]
+	std		%i4, [%g3 + TI_REG_WINDOW + 0x30]
+	std		%i6, [%g3 + TI_REG_WINDOW + 0x38]
 	add		%g1, 1, %g1
-2:	stb		%g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
+2:	stb		%g1, [%g6 + TI_WSAVED]
 	rdpr		%tstate, %g1
 
 	andcc		%g1, TSTATE_PRIV, %g0
@@ -311,47 +311,47 @@
 	b,pt		%xcc, rtrap
 	 nop						! yes, the nop is correct
 spill_fixup_dax:
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
-	andcc		%g1, SPARC_FLAG_32BIT, %g0
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
+	ldx		[%g6 + TI_FLAGS], %g1
+	andcc		%g1, _TIF_32BIT, %g0
+	ldub		[%g6 + TI_WSAVED], %g1
 	sll		%g1, 3, %g3
 	add		%g6, %g3, %g3
-	stx		%sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
+	stx		%sp, [%g3 + TI_RWIN_SPTRS]
 
 	sll		%g1, 7, %g3
 	bne,pt		%xcc, 1f
 	 add		%g6, %g3, %g3
-	stx		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
-	stx		%l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
-	stx		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
-	stx		%l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
-	stx		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+	stx		%l0, [%g3 + TI_REG_WINDOW + 0x00]
+	stx		%l1, [%g3 + TI_REG_WINDOW + 0x08]
+	stx		%l2, [%g3 + TI_REG_WINDOW + 0x10]
+	stx		%l3, [%g3 + TI_REG_WINDOW + 0x18]
+	stx		%l4, [%g3 + TI_REG_WINDOW + 0x20]
 
-	stx		%l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
-	stx		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
-	stx		%l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
-	stx		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
-	stx		%i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
-	stx		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
-	stx		%i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
-	stx		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+	stx		%l5, [%g3 + TI_REG_WINDOW + 0x28]
+	stx		%l6, [%g3 + TI_REG_WINDOW + 0x30]
+	stx		%l7, [%g3 + TI_REG_WINDOW + 0x38]
+	stx		%i0, [%g3 + TI_REG_WINDOW + 0x40]
+	stx		%i1, [%g3 + TI_REG_WINDOW + 0x48]
+	stx		%i2, [%g3 + TI_REG_WINDOW + 0x50]
+	stx		%i3, [%g3 + TI_REG_WINDOW + 0x58]
+	stx		%i4, [%g3 + TI_REG_WINDOW + 0x60]
 
-	stx		%i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
-	stx		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
-	stx		%i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
+	stx		%i5, [%g3 + TI_REG_WINDOW + 0x68]
+	stx		%i6, [%g3 + TI_REG_WINDOW + 0x70]
+	stx		%i7, [%g3 + TI_REG_WINDOW + 0x78]
 	b,pt		%xcc, 2f
 	 add		%g1, 1, %g1
-1:	std		%l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
-	std		%l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
-	std		%l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+1:	std		%l0, [%g3 + TI_REG_WINDOW + 0x00]
+	std		%l2, [%g3 + TI_REG_WINDOW + 0x08]
+	std		%l4, [%g3 + TI_REG_WINDOW + 0x10]
 
-	std		%l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
-	std		%i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
-	std		%i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
-	std		%i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
-	std		%i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+	std		%l6, [%g3 + TI_REG_WINDOW + 0x18]
+	std		%i0, [%g3 + TI_REG_WINDOW + 0x20]
+	std		%i2, [%g3 + TI_REG_WINDOW + 0x28]
+	std		%i4, [%g3 + TI_REG_WINDOW + 0x30]
+	std		%i6, [%g3 + TI_REG_WINDOW + 0x38]
 	add		%g1, 1, %g1
-2:	stb		%g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
+2:	stb		%g1, [%g6 + TI_WSAVED]
 	rdpr		%tstate, %g1
 
 	andcc		%g1, TSTATE_PRIV, %g0
diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
index c64b7d4..300ca24 100644
--- a/arch/sparc64/lib/VIScopy.S
+++ b/arch/sparc64/lib/VIScopy.S
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.26 2001-09-27 04:36:24 kanoj Exp $
+/* $Id: VIScopy.S,v 1.27 2002-02-09 19:49:30 davem Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -26,24 +26,24 @@
 #ifdef __KERNEL__
 
 #include <asm/visasm.h>
-#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
 
-#define FPU_CLEAN_RETL								\
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1;	\
-	VISExit									\
-	clr		%o0;							\
-	retl;									\
+#define FPU_CLEAN_RETL					\
+	ldub		[%g6 + TI_CURRENT_DS], %o1;	\
+	VISExit						\
+	clr		%o0;				\
+	retl;						\
 	 wr		%o1, %g0, %asi;
-#define FPU_RETL								\
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1;	\
-	VISExit									\
-	clr		%o0;							\
-	retl;									\
+#define FPU_RETL					\
+	ldub		[%g6 + TI_CURRENT_DS], %o1;	\
+	VISExit						\
+	clr		%o0;				\
+	retl;						\
 	 wr		%o1, %g0, %asi;
-#define NORMAL_RETL								\
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1;	\
-	clr		%o0;							\
-	retl;									\
+#define NORMAL_RETL					\
+	ldub		[%g6 + TI_CURRENT_DS], %o1;	\
+	clr		%o0;				\
+	retl;						\
 	 wr		%o1, %g0, %asi;
 #define EX(x,y,a,b) 				\
 98: 	x,y;					\
@@ -1032,7 +1032,7 @@
 		/* If this is copy_from_user(), zero out the rest of the
 		 * kernel buffer.
 		 */
-		ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o4
+		ldub		[%g6 + TI_CURRENT_DS], %o4
 		andcc		asi_src, 0x1, %g0
 		be,pt		%icc, 1f
 		 VISExit
diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S
index a1b369e..70651ed 100644
--- a/arch/sparc64/lib/VIScsum.S
+++ b/arch/sparc64/lib/VIScsum.S
@@ -1,4 +1,4 @@
-/* $Id: VIScsum.S,v 1.6 2000-02-20 23:21:39 davem Exp $
+/* $Id: VIScsum.S,v 1.7 2002-02-09 19:49:30 davem Exp $
  * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -28,7 +28,7 @@
 #include <asm/head.h>
 #include <asm/asi.h>
 #include <asm/visasm.h>
-#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
 #else
 #define ASI_BLK_P	0xf0
 #define FRPS_FEF	0x04
@@ -342,7 +342,7 @@
 	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
 	END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
 #ifdef __KERNEL__
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g7
+	ldub		[%g6 + TI_CURRENT_DS], %g7
 #endif
 	and		%o1, 0x3f, %o1		/*  IEU0	Group		*/
 #ifdef __KERNEL__
diff --git a/arch/sparc64/lib/VISsave.S b/arch/sparc64/lib/VISsave.S
index d65e5da..b95beb5 100644
--- a/arch/sparc64/lib/VISsave.S
+++ b/arch/sparc64/lib/VISsave.S
@@ -1,4 +1,4 @@
-/* $Id: VISsave.S,v 1.5 2001-03-08 22:08:51 davem Exp $
+/* $Id: VISsave.S,v 1.6 2002-02-09 19:49:30 davem Exp $
  * VISsave.S: Code for saving FPU register state for
  *            VIS routines. One should not call this directly,
  *            but use macros provided in <asm/visasm.h>.
@@ -10,6 +10,7 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/visasm.h>
+#include <asm/thread_info.h>
 
 	.text
 	.globl		VISenter, VISenterhalf
@@ -19,45 +20,45 @@
 
 	.align		32
 VISenter:
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %g1
+	ldub		[%g6 + TI_FPDEPTH], %g1
 	brnz,a,pn	%g1, 1f
 	 cmp		%g1, 1
-	stb		%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
-	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
+	stb		%g0, [%g6 + TI_FPSAVED]
+	stx		%fsr, [%g6 + TI_XFSR]
 9:	jmpl		%g7 + %g0, %g0
 	 nop
 1:	bne,pn		%icc, 2f
 
 	 srl		%g1, 1, %g1
-vis1:	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3
-	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
+vis1:	ldub		[%g6 + TI_FPSAVED], %g3
+	stx		%fsr, [%g6 + TI_XFSR]
 	or		%g3, %o5, %g3
-	stb		%g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
+	stb		%g3, [%g6 + TI_FPSAVED]
 	rd		%gsr, %g3
 	clr		%g1
 	ba,pt		%xcc, 3f
 
-	 stx		%g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr]
+	 stx		%g3, [%g6 + TI_GSR]
 2:	add		%g6, %g1, %g3
 	cmp		%o5, FPRS_DU
 	be,pn		%icc, 6f
 	 sll		%g1, 3, %g1
-	stb		%o5, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved]
+	stb		%o5, [%g3 + TI_FPSAVED]
 	rd		%gsr, %g2
 	add		%g6, %g1, %g3
-	stx		%g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr]
+	stx		%g2, [%g3 + TI_GSR]
 
 	add		%g6, %g1, %g2
-	stx		%fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr]
+	stx		%fsr, [%g2 + TI_XFSR]
 	sll		%g1, 5, %g1
 3:	andcc		%o5, FPRS_DL|FPRS_DU, %g0
 	be,pn		%icc, 9b
-	 add		%g6, AOFF_task_fpregs, %g2
+	 add		%g6, TI_FPREGS, %g2
 	andcc		%o5, FPRS_DL, %g0
 	membar		#StoreStore | #LoadStore
 
 	be,pn		%icc, 4f
-	 add		%g6, AOFF_task_fpregs+0x40, %g3
+	 add		%g6, TI_FPREGS+0x40, %g3
 	stda		%f0, [%g2 + %g1] ASI_BLK_P
 	stda		%f16, [%g3 + %g1] ASI_BLK_P
 	andcc		%o5, FPRS_DU, %g0
@@ -70,13 +71,13 @@
 	jmpl		%g7 + %g0, %g0
 	 nop
 
-6:	ldub		[%g3 + AOFF_task_thread + AOFF_thread_fpsaved], %o5
+6:	ldub		[%g3 + TI_FPSAVED], %o5
 	or		%o5, FPRS_DU, %o5
-	add		%g6, AOFF_task_fpregs+0x80, %g2
-	stb		%o5, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved]
+	add		%g6, TI_FPREGS+0x80, %g2
+	stb		%o5, [%g3 + TI_FPSAVED]
 
 	sll		%g1, 5, %g1
-	add		%g6, AOFF_task_fpregs+0xc0, %g3
+	add		%g6, TI_FPREGS+0xc0, %g3
 	wr		%g0, FPRS_FEF, %fprs
 	membar		#StoreStore | #LoadStore
 	stda		%f32, [%g2 + %g1] ASI_BLK_P
@@ -88,11 +89,11 @@
 
 	.align		32
 VISenterhalf:
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %g1
+	ldub		[%g6 + TI_FPDEPTH], %g1
 	brnz,a,pn	%g1, 1f
 	 cmp		%g1, 1
-	stb		%g0, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
-	stx		%fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
+	stb		%g0, [%g6 + TI_FPSAVED]
+	stx		%fsr, [%g6 + TI_XFSR]
 	clr		%o5
 	jmpl		%g7 + %g0, %g0
 	 wr		%g0, FPRS_FEF, %fprs
@@ -104,20 +105,20 @@
 2:	addcc		%g6, %g1, %g3
 	sll		%g1, 3, %g1
 	andn		%o5, FPRS_DU, %g2
-	stb		%g2, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved]
+	stb		%g2, [%g3 + TI_FPSAVED]
 
 	rd		%gsr, %g2
 	add		%g6, %g1, %g3
-	stx		%g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr]
+	stx		%g2, [%g3 + TI_GSR]
 	add		%g6, %g1, %g2
-	stx		%fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr]
+	stx		%fsr, [%g2 + TI_XFSR]
 	sll		%g1, 5, %g1
 3:	andcc		%o5, FPRS_DL, %g0
 	be,pn		%icc, 4f
-	 add		%g6, AOFF_task_fpregs, %g2
+	 add		%g6, TI_FPREGS, %g2
 
 	membar		#StoreStore | #LoadStore
-	add		%g6, AOFF_task_fpregs+0x40, %g3
+	add		%g6, TI_FPREGS+0x40, %g3
 	stda		%f0, [%g2 + %g1] ASI_BLK_P
 	stda		%f16, [%g3 + %g1] ASI_BLK_P
 	membar		#Sync
diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S
index 5903c09..a3d8bf7 100644
--- a/arch/sparc64/lib/blockops.S
+++ b/arch/sparc64/lib/blockops.S
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.41 2001-12-05 06:05:35 davem Exp $
+/* $Id: blockops.S,v 1.42 2002-02-09 19:49:30 davem Exp $
  * blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com)
@@ -7,9 +7,9 @@
 
 #include "VIS.h"
 #include <asm/visasm.h>
+#include <asm/thread_info.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/asm_offsets.h>
 
 #define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7)	\
 	fmovd	%reg0, %f48; 	fmovd	%reg1, %f50;		\
@@ -61,7 +61,7 @@
 	 * so we do not risk a multiple TLB match condition later when
 	 * restoring those entries.
 	 */
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_use_blkcommit], %g3
+	ldx		[%g6 + TI_FLAGS], %g3
 
 	/* Spitfire Errata #32 workaround */
 	mov		0x8, %o4
@@ -100,7 +100,7 @@
 	stxa		%g2, [%o3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
 
-	cmp		%g3, 0
+	andcc		%g3, _TIF_BLKCOMMIT, %g0
 	bne,pn		%xcc, copy_page_using_blkcommit
 	 nop
 
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
index 4e962ed..f87faa5 100644
--- a/arch/sparc64/lib/checksum.S
+++ b/arch/sparc64/lib/checksum.S
@@ -18,7 +18,7 @@
 #include <asm/ptrace.h>
 #include <asm/asi.h>
 #include <asm/page.h>
-#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
 
 	/* The problem with the "add with carry" instructions on Ultra
 	 * are two fold.  Firstly, they cannot pair with jack shit,
@@ -498,7 +498,7 @@
 	.globl	cpc_handler
 cpc_handler:
 	ldx	[%sp + 0x7ff + 128], %g1
-	ldub	[%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g3
+	ldub	[%g6 + TI_CURRENT_DS], %g3
 	sub	%g0, EFAULT, %g2
 	brnz,a,pt %g1, 1f
 	 st	%g2, [%g1]
diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c
index 4528ed9..f2855a1 100644
--- a/arch/sparc64/math-emu/math.c
+++ b/arch/sparc64/math-emu/math.c
@@ -1,4 +1,4 @@
-/* $Id: math.c,v 1.11 1999-12-20 05:02:25 davem Exp $
+/* $Id: math.c,v 1.12 2002-02-09 19:49:31 davem Exp $
  * arch/sparc64/math-emu/math.c
  *
  * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
@@ -90,25 +90,25 @@
  */
 static inline int record_exception(struct pt_regs *regs, int eflag)
 {
-	u64 fsr = current->thread.xfsr[0];
+	u64 fsr = current_thread_info()->xfsr[0];
 	int would_trap;
 
 	/* Determine if this exception would have generated a trap. */
 	would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL;
 
 	/* If trapping, we only want to signal one bit. */
-	if(would_trap != 0) {
+	if (would_trap != 0) {
 		eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
-		if((eflag & (eflag - 1)) != 0) {
-			if(eflag & FP_EX_INVALID)
+		if ((eflag & (eflag - 1)) != 0) {
+			if (eflag & FP_EX_INVALID)
 				eflag = FP_EX_INVALID;
-			else if(eflag & FP_EX_OVERFLOW)
+			else if (eflag & FP_EX_OVERFLOW)
 				eflag = FP_EX_OVERFLOW;
-			else if(eflag & FP_EX_UNDERFLOW)
+			else if (eflag & FP_EX_UNDERFLOW)
 				eflag = FP_EX_UNDERFLOW;
-			else if(eflag & FP_EX_DIVZERO)
+			else if (eflag & FP_EX_DIVZERO)
 				eflag = FP_EX_DIVZERO;
-			else if(eflag & FP_EX_INEXACT)
+			else if (eflag & FP_EX_INEXACT)
 				eflag = FP_EX_INEXACT;
 		}
 	}
@@ -128,19 +128,19 @@
 	 *    CEXC just generated is OR'd into the
 	 *    existing value of AEXC.
 	 */
-	if(would_trap == 0)
+	if (would_trap == 0)
 		fsr |= ((long)eflag << FSR_AEXC_SHIFT);
 
 	/* If trapping, indicate fault trap type IEEE. */
-	if(would_trap != 0)
+	if (would_trap != 0)
 		fsr |= (1UL << 14);
 
-	current->thread.xfsr[0] = fsr;
+	current_thread_info()->xfsr[0] = fsr;
 
 	/* If we will not trap, advance the program counter over
 	 * the instruction being handled.
 	 */
-	if(would_trap == 0) {
+	if (would_trap == 0) {
 		regs->tpc = regs->tnpc;
 		regs->tnpc += 4;
 	}
@@ -174,10 +174,10 @@
 	int IR;
 	long XR, xfsr;
 
-	if(tstate & TSTATE_PRIV)
+	if (tstate & TSTATE_PRIV)
 		die_if_kernel("FPQuad from kernel", regs);
-	if(current->thread.flags & SPARC_FLAG_32BIT)
-		pc = (u32)pc;
+	if (test_thread_flag(TIF_32BIT))
+		pc &= 0xffffffff;
 	if (get_user(insn, (u32 *)pc) != -EFAULT) {
 		if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
 			switch ((insn >> 5) & 0x1ff) {
@@ -231,9 +231,9 @@
 			case FMOVQ3:
 				/* fmovq %fccX, %fY, %fZ */
 				if (!((insn >> 11) & 3))
-					XR = current->thread.xfsr[0] >> 10;
+					XR = current_thread_info()->xfsr[0] >> 10;
 				else
-					XR = current->thread.xfsr[0] >> (30 + ((insn >> 10) & 0x6));
+					XR = current_thread_info()->xfsr[0] >> (30 + ((insn >> 10) & 0x6));
 				XR &= 3;
 				IR = 0;
 				switch ((insn >> 14) & 0x7) {
@@ -282,7 +282,7 @@
 					XR = 0;
 				else if (freg < 16)
 					XR = regs->u_regs[freg];
-				else if (current->thread.flags & SPARC_FLAG_32BIT) {
+				else if (test_thread_flag(TIF_32BIT)) {
 					struct reg_window32 *win32;
 					flushw_user ();
 					win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
@@ -305,7 +305,7 @@
 			}
 			if (IR == 0) {
 				/* The fmov test was false. Do a nop instead */
-				current->thread.xfsr[0] &= ~(FSR_CEXC_MASK);
+				current_thread_info()->xfsr[0] &= ~(FSR_CEXC_MASK);
 				regs->tpc = regs->tnpc;
 				regs->tnpc += 4;
 				return 1;
@@ -319,20 +319,20 @@
 	if (type) {
 		argp rs1 = NULL, rs2 = NULL, rd = NULL;
 		
-		freg = (current->thread.xfsr[0] >> 14) & 0xf;
+		freg = (current_thread_info()->xfsr[0] >> 14) & 0xf;
 		if (freg != (type >> 9))
 			goto err;
-		current->thread.xfsr[0] &= ~0x1c000;
+		current_thread_info()->xfsr[0] &= ~0x1c000;
 		freg = ((insn >> 14) & 0x1f);
 		switch (type & 0x3) {
 		case 3: if (freg & 2) {
-				current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+				current_thread_info()->xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
 		case 1: rs1 = (argp)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
-			if (!(current->thread.fpsaved[0] & flags))
+			if (!(current_thread_info()->fpsaved[0] & flags))
 				rs1 = (argp)&zero;
 			break;
 		}
@@ -344,13 +344,13 @@
 		freg = (insn & 0x1f);
 		switch ((type >> 3) & 0x3) {
 		case 3: if (freg & 2) {
-				current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+				current_thread_info()->xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
 		case 1: rs2 = (argp)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
-			if (!(current->thread.fpsaved[0] & flags))
+			if (!(current_thread_info()->fpsaved[0] & flags))
 				rs2 = (argp)&zero;
 			break;
 		}
@@ -362,23 +362,23 @@
 		freg = ((insn >> 25) & 0x1f);
 		switch ((type >> 6) & 0x3) {
 		case 3: if (freg & 2) {
-				current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+				current_thread_info()->xfsr[0] |= (6 << 14) /* invalid_fp_register */;
 				goto err;
 			}
 		case 2: freg = ((freg & 1) << 5) | (freg & 0x1e);
 		case 1: rd = (argp)&f->regs[freg];
 			flags = (freg < 32) ? FPRS_DL : FPRS_DU; 
-			if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
-				current->thread.fpsaved[0] = FPRS_FEF;
-				current->thread.gsr[0] = 0;
+			if (!(current_thread_info()->fpsaved[0] & FPRS_FEF)) {
+				current_thread_info()->fpsaved[0] = FPRS_FEF;
+				current_thread_info()->gsr[0] = 0;
 			}
-			if (!(current->thread.fpsaved[0] & flags)) {
+			if (!(current_thread_info()->fpsaved[0] & flags)) {
 				if (freg < 32)
 					memset(f->regs, 0, 32*sizeof(u32));
 				else
 					memset(f->regs+32, 0, 32*sizeof(u32));
 			}
-			current->thread.fpsaved[0] |= flags;
+			current_thread_info()->fpsaved[0] |= flags;
 			break;
 		}
 		switch ((insn >> 5) & 0x1ff) {
@@ -439,7 +439,7 @@
 		}
 		if (!FP_INHIBIT_RESULTS) {
 			switch ((type >> 6) & 0x7) {
-			case 0: xfsr = current->thread.xfsr[0];
+			case 0: xfsr = current_thread_info()->xfsr[0];
 				if (XR == -1) XR = 2;
 				switch (freg & 3) {
 				/* fcc0, 1, 2, 3 */
@@ -448,7 +448,7 @@
 				case 2: xfsr &= ~0xc00000000UL; xfsr |= (XR << 34); break;
 				case 3: xfsr &= ~0x3000000000UL; xfsr |= (XR << 36); break;
 				}
-				current->thread.xfsr[0] = xfsr;
+				current_thread_info()->xfsr[0] = xfsr;
 				break;
 			case 1: rd->s = IR; break;
 			case 2: rd->d = XR; break;
@@ -458,11 +458,11 @@
 			}
 		}
 
-		if(_fex != 0)
+		if (_fex != 0)
 			return record_exception(regs, _fex);
 
 		/* Success and no exceptions detected. */
-		current->thread.xfsr[0] &= ~(FSR_CEXC_MASK);
+		current_thread_info()->xfsr[0] &= ~(FSR_CEXC_MASK);
 		regs->tpc = regs->tnpc;
 		regs->tnpc += 4;
 		return 1;
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index ad8fb1b..1052498 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.58 2001-09-01 00:11:16 kanoj Exp $
+/* $Id: fault.c,v 1.59 2002-02-09 19:49:31 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -287,8 +287,8 @@
 	unsigned long address;
 
 	si_code = SEGV_MAPERR;
-	fault_code = current->thread.fault_code;
-	address = current->thread.fault_address;
+	fault_code = get_thread_fault_code();
+	address = current_thread_info()->fault_address;
 
 	if ((fault_code & FAULT_CODE_ITLB) &&
 	    (fault_code & FAULT_CODE_DTLB))
@@ -301,7 +301,7 @@
 	if (in_interrupt() || !mm)
 		goto intr_or_no_mm;
 
-	if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		address &= 0xffffffff;
 	}
@@ -358,7 +358,7 @@
 		if (tlb_type == spitfire &&
 		    (vma->vm_flags & VM_EXEC) != 0 &&
 		    vma->vm_file != NULL)
-			current->thread.use_blkcommit = 1;
+			set_thread_flag(TIF_BLKCOMMIT);
 	} else {
 		/* Allow reads even for write-only mappings */
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
@@ -426,7 +426,7 @@
 
 fault_done:
 	/* These values are no longer needed, clear them. */
-	current->thread.fault_code = 0;
-	current->thread.use_blkcommit = 0;
-	current->thread.fault_address = 0;
+	set_thread_fault_code(0);
+	clear_thread_flag(TIF_BLKCOMMIT);
+	current_thread_info()->fault_address = 0;
 }
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index beef48f..fe80462 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.208 2001-12-21 04:56:15 davem Exp $
+/*  $Id: init.c,v 1.209 2002-02-09 19:49:31 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -111,8 +111,6 @@
         return freed;
 }
 
-extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
 #ifdef CONFIG_DEBUG_DCFLUSH
 atomic_t dcpage_flushes = ATOMIC_INIT(0);
 #ifdef CONFIG_SMP
@@ -181,6 +179,8 @@
 			     : "g5", "g7");
 }
 
+extern void __update_mmu_cache(unsigned long mmu_context_hw, unsigned long address, pte_t pte, int code);
+
 void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 	struct page *page = pte_page(pte);
@@ -201,7 +201,9 @@
 
 		clear_dcache_dirty_cpu(page, cpu);
 	}
-	__update_mmu_cache(vma, address, pte);
+	if (get_thread_fault_code())
+		__update_mmu_cache(vma->vm_mm->context & TAG_CONTEXT_BITS,
+				   address, pte, get_thread_fault_code());
 }
 
 void flush_dcache_page(struct page *page)
@@ -706,7 +708,7 @@
 	int i;
 
 	if (!enter)
-		set_fs(current->thread.current_ds);
+		set_fs((mm_segment_t) { get_thread_current_ds() });
 
 	if (!prom_ditlb_set)
 		return;
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 6c9a963..948a3b4 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.71 2002-01-23 11:27:36 davem Exp $
+/* $Id: ultra.S,v 1.72 2002-02-09 19:49:31 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -391,8 +391,8 @@
 	rdpr		%pstate, %g7
 	wrpr		%g7, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g1
-	stxa		%o0, [%g1] ASI_DMMU
-	stxa		%o1, [%g0] ASI_DTLB_DATA_IN
+	stxa		%o5, [%g1] ASI_DMMU
+	stxa		%o2, [%g0] ASI_DTLB_DATA_IN
 	flush		%g6
 	retl
 	 wrpr		%g7, %pstate
@@ -400,28 +400,20 @@
 	rdpr		%pstate, %g7
 	wrpr		%g7, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g1
-	stxa		%o0, [%g1] ASI_IMMU
-	stxa		%o1, [%g0] ASI_ITLB_DATA_IN
+	stxa		%o5, [%g1] ASI_IMMU
+	stxa		%o2, [%g0] ASI_ITLB_DATA_IN
 	flush		%g6
 	retl
 	 wrpr		%g7, %pstate
 
 	.globl		__update_mmu_cache
-__update_mmu_cache:	/* %o0=vma, %o1=address, %o2=pte */
-	ldub		[%g6 + AOFF_task_thread + AOFF_thread_fault_code], %o3
+__update_mmu_cache:	/* %o0=hw_context, %o1=address, %o2=pte, %o3=fault_code */
 	srlx		%o1, PAGE_SHIFT, %o1
-	ldx		[%o0 + 0x0], %o4		/* XXX vma->vm_mm */
-	brz,pn		%o3, 1f
-	 sllx		%o1, PAGE_SHIFT, %o0
-	ldx		[%o4 + AOFF_mm_context], %o5
 	andcc		%o3, FAULT_CODE_DTLB, %g0
-	mov		%o2, %o1
-	and		%o5, TAG_CONTEXT_BITS, %o5
+	sllx		%o1, PAGE_SHIFT, %o5
 	bne,pt		%xcc, __prefill_dtlb
-	 or		%o0, %o5, %o0
+	 or		%o5, %o0, %o5
 	ba,a,pt		%xcc, __prefill_itlb
-1:	retl
-	 nop
 
 #ifdef CONFIG_SMP
 	/* These are all called by the slaves of a cross call, at
diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S
index 3fcf072..8b880f6 100644
--- a/arch/sparc64/solaris/entry64.S
+++ b/arch/sparc64/solaris/entry64.S
@@ -1,4 +1,4 @@
-/* $Id: entry64.S,v 1.6 2000-01-12 02:59:26 davem Exp $
+/* $Id: entry64.S,v 1.7 2002-02-09 19:49:31 davem Exp $
  * entry64.S:  Solaris syscall emulation entry point.
  *
  * Copyright (C) 1996,1997,1998 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
@@ -68,9 +68,11 @@
 
 	/* Solaris system calls enter here... */
 	.align	32
-	.globl	solaris_sparc_syscall
+	.globl	solaris_sparc_syscall, entry64_personality_patch
 solaris_sparc_syscall:
-	ldub		[%g6 + AOFF_task_personality + ASIZ_task_personality - 1], %l0
+	ldx		[%g6 + TI_TASK], %l0
+entry64_personality_patch:
+	ldub		[%l0 + 0x0], %l0
 	cmp		%g1, 255
 	bg,pn		%icc, solaris_unimplemented
 	 srl		%g1, 0, %g1
@@ -83,7 +85,7 @@
 1:	 srl		%i0, 0, %o0
 	lduw		[%l7 + %l4], %l3
 	srl		%i1, 0, %o1
-	ldx		[%g6 + AOFF_task_flags], %l5
+	ldx		[%g6 + TI_FLAGS], %l5
 	cmp		%l3, NR_SYSCALLS
 	bleu,a,pn	%xcc, linux_syscall_for_solaris
 	 sethi		%hi(sys_call_table32), %l6
@@ -93,21 +95,21 @@
 10:	srl		%i2, 0, %o2
 	mov		%i5, %o5
 	andn		%l3, 3, %l7
-	andcc		%l5, 0x20, %g0				
+	andcc		%l5, _TIF_SYSCALL_TRACE, %g0				
 	bne,pn		%icc, solaris_syscall_trace		
 	 mov		%i0, %l5
 2:	call		%l7
 	 srl		%i3, 0, %o3
 ret_from_solaris:
 	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
-	ldx		[%g6 + AOFF_task_flags], %l6
+	ldx		[%g6 + TI_FLAGS], %l6
 	sra		%o0, 0, %o0
 	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
 	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
 	cmp		%o0, -ENOIOCTLCMD
 	sllx		%g2, 32, %g2
 	bgeu,pn		%xcc, 1f
-	 andcc		%l6, 0x20, %l6	
+	 andcc		%l6, _TIF_SYSCALL_TRACE, %l6	
 
 	/* System call success, clear Carry condition code. */
 	andn		%g3, %g2, %g3
@@ -175,25 +177,30 @@
 
 	.globl		solaris_getpid
 solaris_getpid:
-	call		sys_getppid	/* This is tricky, so don't do it in assembly */
+	call		sys_getppid
 	 nop
-	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	call		sys_getpid
+	 stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
 	b,pt		%xcc, ret_from_solaris
-	 lduw		[%g6 + AOFF_task_pid], %o0
+	 nop
 
 	.globl	solaris_getuid
 solaris_getuid:
-	lduw		[%g6 + AOFF_task_euid], %o1
-	lduw		[%g6 + AOFF_task_uid], %o0
-	b,pt		%xcc, ret_from_solaris
+	call		sys_geteuid
+	 nop
+	call		sys_getuid
 	 stx		%o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	b,pt		%xcc, ret_from_solaris
+	 nop
 
 	.globl	solaris_getgid
 solaris_getgid:
-	lduw		[%g6 + AOFF_task_egid], %o1
-	lduw		[%g6 + AOFF_task_gid], %o0
-	b,pt		%xcc, ret_from_solaris
+	call		sys_getegid
+	 nop
+	call		sys_getgid
 	 stx		%o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	b,pt		%xcc, ret_from_solaris
+	 nop
 
 	.globl		solaris_unimplemented
 solaris_unimplemented:
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 427de75..49da3c7 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.35 2002-01-08 16:00:21 davem Exp $
+/* $Id: misc.c,v 1.36 2002-02-09 19:49:31 davem Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -739,6 +739,8 @@
 extern u32 solaris_syscall[];
 extern void cleanup_socksys(void);
 
+extern u32 entry64_personality_patch;
+
 int init_module(void)
 {
 	int ret;
@@ -750,6 +752,11 @@
 		return ret;
 	}
 	update_ttable(solaris_sparc_syscall);
+	entry64_personality_patch |=
+		(offsetof(struct task_struct, personality) +
+		 (sizeof(unsigned long) - 1));
+	__asm__ __volatile__("membar #StoreStore; flush %0"
+			     : : "r" (&entry64_personality_patch));
 	return 0;
 }
 
diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c
index 9d1fdf0..2e1d2a6 100644
--- a/drivers/block/blkpg.c
+++ b/drivers/block/blkpg.c
@@ -280,7 +280,8 @@
 
 			if (cmd == BLKGETSIZE)
 				return put_user((unsigned long)ullval, (unsigned long *)arg);
-			return put_user(ullval, (u64 *)arg);
+			else
+				return put_user((u64)ullval << 9 , (u64 *)arg);
 #if 0
 		case BLKRRPART: /* Re-read partition tables */
 			if (!capable(CAP_SYS_ADMIN)) 
diff --git a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
index 27e2039..1088215 100644
--- a/drivers/hotplug/pci_hotplug_core.c
+++ b/drivers/hotplug/pci_hotplug_core.c
@@ -414,7 +414,7 @@
 	}
 
 	spin_unlock (&mount_lock);
-	mnt = kern_mount (&pcihpfs_fs_type);
+	mnt = kern_mount (&pcihpfs_type);
 	if (IS_ERR(mnt)) {
 		err ("could not mount the fs...erroring out!\n");
 		return -ENODEV;
@@ -1114,7 +1114,7 @@
 	spin_lock_init(&list_lock);
 
 	dbg("registering filesystem.\n");
-	result = register_filesystem(&pcihpfs_fs_type);
+	result = register_filesystem(&pcihpfs_type);
 	if (result) {
 		err("register_filesystem failed with %d\n", result);
 		goto exit;
@@ -1128,7 +1128,7 @@
 
 static void __exit pci_hotplug_exit (void)
 {
-	unregister_filesystem(&pcihpfs_fs_type);
+	unregister_filesystem(&pcihpfs_type);
 }
 
 module_init(pci_hotplug_init);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index baf5048..27e3aeb 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -192,11 +192,6 @@
 	sectors = rq->nr_sectors;
 	if (sectors == 256)
 		sectors = 0;
-	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
-		sectors = drive->mult_count;
-		if (sectors > rq->current_nr_sectors)
-			sectors = rq->current_nr_sectors;
-	}
 
 	taskfile.sector_count	= sectors;
 	taskfile.sector_number	= sect;
@@ -241,11 +236,6 @@
 	sectors = rq->nr_sectors;
 	if (sectors == 256)
 		sectors = 0;
-	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
-		sectors = drive->mult_count;
-		if (sectors > rq->current_nr_sectors)
-			sectors = rq->current_nr_sectors;
-	}
 
 	memset(&taskfile, 0, sizeof(task_struct_t));
 	memset(&hobfile, 0, sizeof(hob_struct_t));
@@ -300,13 +290,8 @@
 	memset(&hobfile, 0, sizeof(hob_struct_t));
 
 	sectors = rq->nr_sectors;
-	if (sectors == 256)
+	if (sectors == 65536)
 		sectors = 0;
-	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
-		sectors = drive->mult_count;
-		if (sectors > rq->current_nr_sectors)
-			sectors = rq->current_nr_sectors;
-	}
 
 	taskfile.sector_count	= sectors;
 	hobfile.sector_count	= sectors >> 8;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index daae0cf..f7714ba 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -255,6 +255,7 @@
 	return 1;		/* drive ready: *might* be interrupting */
 }
 
+ide_startstop_t bio_mulout_intr (ide_drive_t *drive);
 ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
 {
 	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
@@ -263,7 +264,7 @@
 	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
 
 	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (task->handler != task_mulout_intr) {
+	if (task->handler != task_mulout_intr && task->handler != bio_mulout_intr) {
 		if (IDE_CONTROL_REG)
 			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
 		SELECT_MASK(HWIF(drive), drive, 0);
@@ -313,7 +314,7 @@
 	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
 
 	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (*handler != task_mulout_intr) {
+	if (*handler != task_mulout_intr && handler != bio_mulout_intr) {
 		if (IDE_CONTROL_REG)
 			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
 		SELECT_MASK(HWIF(drive), drive, 0);
@@ -936,15 +937,12 @@
 	char *pBuf		= NULL;
 	unsigned long flags;
 
-	if (!rq->current_nr_sectors) { 
-		printk("task_out_intr: should not trigger\n");
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat))
 		return ide_error(drive, "task_out_intr", stat);
-	}
+
+	if (!rq->current_nr_sectors)
+		if (!ide_end_request(1, HWGROUP(drive)))
+			return ide_stopped;
 
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
@@ -958,16 +956,8 @@
 		rq->current_nr_sectors--;
 	}
 
-	if (rq->current_nr_sectors <= 0) {
-		if (ide_end_request(1, HWGROUP(drive))) {
-			ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
-			return ide_started;
-		}
-	} else {
-		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-	return ide_stopped;
+	ide_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
+	return ide_started;
 }
 
 /*
@@ -1061,14 +1051,132 @@
 	return ide_started;
 }
 
+ide_startstop_t pre_bio_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+	/*
+	 * assign private copy for multi-write
+	 */
+	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
+		return startstop;
+
+	/*
+	 * (ks/hs): Stuff the first sector(s)
+	 * by implicitly calling the handler
+	 */
+	if (!(drive_is_ready(drive))) {
+		int i;
+		/*
+		 * (ks/hs): FIXME: Replace hard-coded
+		 *               100, error handling?
+		 */
+		for (i=0; i<100; i++) {
+			if (drive_is_ready(drive))
+				break;
+		}
+	}
+
+	return args->handler(drive);
+}
+
+
+ide_startstop_t bio_mulout_intr (ide_drive_t *drive)
+{
+#ifdef ALTSTAT_SCREW_UP
+	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
+#else
+	byte stat		= GET_STAT();
+#endif /* ALTSTAT_SCREW_UP */
+
+	byte io_32bit		= drive->io_32bit;
+	struct request *rq	= &HWGROUP(drive)->wrq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	int mcount		= drive->mult_count;
+	ide_startstop_t startstop;
+
+	/*
+	 * (ks/hs): Handle last IRQ on multi-sector transfer,
+	 * occurs after all data was sent in this chunk
+	 */
+	if (!rq->nr_sectors) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			startstop = ide_error(drive, "bio_mulout_intr", stat);
+			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+			return startstop;
+		}
+
+		__ide_end_request(HWGROUP(drive), 1, rq->hard_nr_sectors);
+		HWGROUP(drive)->wrq.bio = NULL;
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & (ERR_STAT | DRQ_STAT)) {
+			startstop = ide_error(drive, "bio_mulout_intr", stat);
+			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+			return startstop;
+		}
+
+		/* no data yet, so wait for another interrupt */
+		if (hwgroup->handler == NULL)
+			ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
+
+		return ide_started;
+	}
+
+	do {
+  		char *buffer;
+  		int nsect = rq->current_nr_sectors;
+		unsigned long flags;
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bio after this? */
+		if (!rq->current_nr_sectors) {
+			/* remember to fix this up /jens */
+			struct bio *bio = rq->bio->bi_next;
+
+			/* end early early we ran out of requests */
+			if (!bio) {
+				mcount = 0;
+			} else {
+				rq->bio = bio;
+				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
+		ide_unmap_buffer(buffer, &flags);
+	} while (mcount);
+
+	drive->io_32bit = io_32bit;
+	rq->errors = 0;
+	if (hwgroup->handler == NULL)
+		ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
+
+	return ide_started;
+}
+
 /* Called by internal to feature out type of command being called */
 ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
 				/* IDE_DRIVE_TASK_RAW_WRITE */
-		case CFA_WRITE_MULTI_WO_ERASE:
-		case WIN_MULTWRITE:
-		case WIN_MULTWRITE_EXT:
 				/* IDE_DRIVE_TASK_OUT */
 		case WIN_WRITE:
 		case WIN_WRITE_EXT:
@@ -1077,7 +1185,10 @@
 		case CFA_WRITE_SECT_WO_ERASE:
 		case WIN_DOWNLOAD_MICROCODE:
 			return &pre_task_out_intr;
-				/* IDE_DRIVE_TASK_OUT */
+		case CFA_WRITE_MULTI_WO_ERASE:
+		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
+			return &pre_bio_out_intr;
 		case WIN_SMART:
 			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
 				return &pre_task_out_intr;
@@ -1120,7 +1231,7 @@
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
-			return &task_mulout_intr;
+			return &bio_mulout_intr;
 		case WIN_SMART:
 			switch(taskfile->feature) {
 				case SMART_READ_VALUES:
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 4fa77c9..413002f 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -1,11 +1,9 @@
 /*
- * $Id: evdev.c,v 1.27 2001/05/28 09:06:44 vojtech Exp $
+ * $Id: evdev.c,v 1.42 2002/01/02 11:59:56 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Event char devices, giving access to raw input device events.
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -24,8 +22,8 @@
  * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #define EVDEV_MINOR_BASE	64
@@ -42,7 +40,9 @@
 struct evdev {
 	int exist;
 	int open;
+	int open_for_write;
 	int minor;
+	char name[16];
 	struct input_handle handle;
 	wait_queue_head_t wait;
 	devfs_handle_t devfs;
@@ -89,6 +89,11 @@
 	return retval < 0 ? retval : 0;
 }
 
+static int evdev_flush(struct file * file)
+{
+	return input_flush_device(&((struct evdev_list*)file->private_data)->evdev->handle, file);
+}
+
 static int evdev_release(struct inode * inode, struct file * file)
 {
 	struct evdev_list *list = file->private_data;
@@ -120,10 +125,16 @@
 {
 	struct evdev_list *list;
 	int i = minor(inode->i_rdev) - EVDEV_MINOR_BASE;
+	int accept_err;
 
 	if (i >= EVDEV_MINORS || !evdev_table[i])
 		return -ENODEV;
 
+	/* Ask the driver if he wishes to accept the open() */
+	if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) {
+		return accept_err;
+	}
+
 	if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
 		return -ENOMEM;
 	memset(list, 0, sizeof(struct evdev_list));
@@ -167,7 +178,7 @@
 	if (list->head == list->tail) {
 
 		add_wait_queue(&list->evdev->wait, &wait);
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 
 		while (list->head == list->tail) {
 
@@ -187,7 +198,7 @@
 			schedule();
 		}
 
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&list->evdev->wait, &wait);
 	}
 
@@ -219,7 +230,7 @@
 	struct evdev_list *list = file->private_data;
 	struct evdev *evdev = list->evdev;
 	struct input_dev *dev = evdev->handle.dev;
-	int retval;
+	int retval, t, u;
 
 	switch (cmd) {
 
@@ -232,6 +243,40 @@
 			if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval;
 			if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval;
 			return 0;
+		
+		case EVIOCGREP:
+			if ((retval = put_user(dev->rep[0], ((int *) arg) + 0))) return retval;
+			if ((retval = put_user(dev->rep[1], ((int *) arg) + 1))) return retval;
+			return 0;
+
+		case EVIOCSREP:
+			if ((retval = get_user(dev->rep[0], ((int *) arg) + 0))) return retval;
+			if ((retval = get_user(dev->rep[1], ((int *) arg) + 1))) return retval;
+			return 0;
+
+		case EVIOCGKEYCODE:
+			if ((retval = get_user(t, ((int *) arg) + 0))) return retval;
+			if (t < 0 || t > dev->keycodemax) return -EINVAL;
+			switch (dev->keycodesize) {
+				case 1: u = *(u8*)(dev->keycode + t); break;
+				case 2: u = *(u16*)(dev->keycode + t * 2); break;
+				case 4: u = *(u32*)(dev->keycode + t * 4); break;
+				default: return -EINVAL;
+			}
+			if ((retval = put_user(u, ((int *) arg) + 1))) return retval;
+			return 0;
+
+		case EVIOCSKEYCODE:
+			if ((retval = get_user(t, ((int *) arg) + 0))) return retval;
+			if (t < 0 || t > dev->keycodemax) return -EINVAL;
+			if ((retval = get_user(u, ((int *) arg) + 1))) return retval;
+			switch (dev->keycodesize) {
+				case 1: *(u8*)(dev->keycode + t) = u; break;
+				case 2: *(u16*)(dev->keycode + t * 2) = u; break;
+				case 4: *(u32*)(dev->keycode + t * 4) = u; break;
+				default: return -EINVAL;
+			}
+			return 0;
 
 		case EVIOCSFF:
 			if (dev->upload_effect) {
@@ -280,22 +325,55 @@
 					default: return -EINVAL;
 				}
 				len = NBITS(len) * sizeof(long);
-				if (len > _IOC_SIZE(cmd)) {
-					printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n",
-						len, _IOC_SIZE(cmd));
-					len = _IOC_SIZE(cmd);
-				}
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 				return copy_to_user((char *) arg, bits, len) ? -EFAULT : len;
 			}
 
+			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
+				int len;
+				len = NBITS(KEY_MAX) * sizeof(long);
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((char *) arg, dev->key, len) ? -EFAULT : len;
+			}
+
+			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
+				int len;
+				len = NBITS(LED_MAX) * sizeof(long);
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((char *) arg, dev->led, len) ? -EFAULT : len;
+			}
+
+			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
+				int len;
+				len = NBITS(SND_MAX) * sizeof(long);
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((char *) arg, dev->snd, len) ? -EFAULT : len;
+			}
+
 			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
 				int len;
-				if (!dev->name) return 0;
+				if (!dev->name) return -ENOENT;
 				len = strlen(dev->name) + 1;
 				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 				return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
 			}
 
+			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+				int len;
+				if (!dev->phys) return -ENOENT;
+				len = strlen(dev->phys) + 1;
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((char *) arg, dev->phys, len) ? -EFAULT : len;
+			}
+
+			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+				int len;
+				if (!dev->uniq) return -ENOENT;
+				len = strlen(dev->uniq) + 1;
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((char *) arg, dev->uniq, len) ? -EFAULT : len;
+			}
+
 			if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 
 				int t = _IOC_NR(cmd) & ABS_MAX;
@@ -321,9 +399,10 @@
 	release:	evdev_release,
 	ioctl:		evdev_ioctl,
 	fasync:		evdev_fasync,
+	flush:		evdev_flush
 };
 
-static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
 {
 	struct evdev *evdev;
 	int minor;
@@ -342,16 +421,17 @@
 
 	evdev->minor = minor;
 	evdev_table[minor] = evdev;
+	
+	sprintf(evdev->name, "event%d", minor);
 
 	evdev->handle.dev = dev;
+	evdev->handle.name = evdev->name;
 	evdev->handle.handler = handler;
 	evdev->handle.private = evdev;
 
-	evdev->exist = 1;
-
 	evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
 
-//	printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);
+	evdev->exist = 1;
 
 	return &evdev->handle;
 }
@@ -372,12 +452,21 @@
 	}
 }
 
+static struct input_device_id evdev_ids[] = {
+	{ driver_info: 1 },	/* Matches all devices */
+	{ },			/* Terminating zero entry */
+};
+
+MODULE_DEVICE_TABLE(input, evdev_ids);
+
 static struct input_handler evdev_handler = {
 	event:		evdev_event,
 	connect:	evdev_connect,
 	disconnect:	evdev_disconnect,
 	fops:		&evdev_fops,
 	minor:		EVDEV_MINOR_BASE,
+	name:		"evdev",
+	id_table:	evdev_ids,
 };
 
 static int __init evdev_init(void)
@@ -394,7 +483,6 @@
 module_init(evdev_init);
 module_exit(evdev_exit);
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Event character device driver");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Input driver event char devices");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index f17165b..e5b845e 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -1,12 +1,10 @@
 /*
- * $Id: joydev.c,v 1.19 2001/01/10 19:49:40 vojtech Exp $
+ * $Id: joydev.c,v 1.38 2001/12/27 10:37:41 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik 
+ *  Copyright (c) 1999-2001 Vojtech Pavlik 
  *  Copyright (c) 1999 Colin Van Dyke 
  *
  *  Joystick device driver for the input driver suite.
- *
- *  Sponsored by SuSE and Intel
  */
 
 /*
@@ -25,8 +23,8 @@
  * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -45,14 +43,22 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Joystick device interfaces");
+MODULE_SUPPORTED_DEVICE("input/js");
+MODULE_LICENSE("GPL");
+
 #define JOYDEV_MINOR_BASE	0
 #define JOYDEV_MINORS		32
 #define JOYDEV_BUFFER_SIZE	64
 
+#define MSECS(t)	(1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
+
 struct joydev {
 	int exist;
 	int open;
 	int minor;
+	char name[16];
 	struct input_handle handle;
 	wait_queue_head_t wait;
 	devfs_handle_t devfs;
@@ -81,11 +87,6 @@
 
 static struct joydev *joydev_table[JOYDEV_MINORS];
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Joystick device driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("input/js");
-
 static int joydev_correct(int value, struct js_corr *corr)
 {
 	switch (corr->type) {
@@ -133,7 +134,7 @@
 			return;
 	}  
 
-	event.time = jiffies * (1000 / HZ);
+	event.time = MSECS(jiffies);
 
 	while (list) {
 
@@ -163,7 +164,7 @@
 {
 	struct joydev_list *list = file->private_data;
 	struct joydev_list **listptr;
-	
+
 	listptr = &list->joydev->list;
 	joydev_fasync(-1, file, 0);
 
@@ -249,7 +250,7 @@
 	if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) {
 
 		add_wait_queue(&list->joydev->wait, &wait);
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 
 		while (list->head == list->tail) {
 
@@ -265,7 +266,7 @@
 			schedule();
 		}
 
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&list->joydev->wait, &wait);
 	}
 
@@ -276,7 +277,7 @@
 
 		struct js_event event;
 
-		event.time = jiffies * (1000/HZ);
+		event.time = MSECS(jiffies);
 
 		if (list->startup < joydev->nkey) {
 			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
@@ -360,9 +361,9 @@
 			return copy_to_user((struct js_corr *) arg, joydev->corr,
 						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
 		case JSIOCSAXMAP:
-			if (copy_from_user((__u8 *) arg, joydev->abspam, sizeof(__u8) * ABS_MAX))
+			if (copy_from_user(joydev->abspam, (__u8 *) arg, sizeof(__u8) * ABS_MAX))
 				return -EFAULT;
-			for (i = 0; i < ABS_MAX; i++) {
+			for (i = 0; i < joydev->nabs; i++) {
 				if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
 				joydev->absmap[joydev->abspam[i]] = i;
 			}
@@ -371,11 +372,11 @@
 			return copy_to_user((__u8 *) arg, joydev->abspam,
 						sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
 		case JSIOCSBTNMAP:
-			if (copy_from_user((__u16 *) arg, joydev->absmap, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
+			if (copy_from_user(joydev->keypam, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
 				return -EFAULT;
-			for (i = 0; i < KEY_MAX - BTN_MISC; i++); {
+			for (i = 0; i < joydev->nkey; i++); {
 				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
-				joydev->keymap[joydev->abspam[i - BTN_MISC]] = i;
+				joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
 			}
 			return 0;
 		case JSIOCGBTNMAP:
@@ -405,15 +406,13 @@
 	fasync:		joydev_fasync,
 };
 
-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
 {
 	struct joydev *joydev;
-	int i, j, minor;
+	int i, j, t, minor;
 
-	if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
-	     (test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) &&
-	     (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
-		|| test_bit(BTN_1, dev->keybit)))) return NULL; 
+        if (test_bit(BTN_TOUCH, dev->keybit))
+		return NULL;
 
 	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
 	if (minor == JOYDEV_MINORS) {
@@ -430,12 +429,13 @@
 	joydev->minor = minor;
 	joydev_table[minor] = joydev;
 
+	sprintf(joydev->name, "js%d", minor);
+
 	joydev->handle.dev = dev;
+	joydev->handle.name = joydev->name;
 	joydev->handle.handler = handler;
 	joydev->handle.private = joydev;
 
-	joydev->exist = 1;
-
 	for (i = 0; i < ABS_MAX; i++)
 		if (test_bit(i, dev->absbit)) {
 			joydev->absmap[i] = joydev->nabs;
@@ -467,15 +467,17 @@
 		joydev->corr[i].prec = dev->absfuzz[j];
 		joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
 		joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
-		joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
-		joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
+		if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
+			continue;
+		joydev->corr[i].coef[2] = (1 << 29) / t;
+		joydev->corr[i].coef[3] = (1 << 29) / t;
 
 		joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
 	}
 
 	joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
 
-//	printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number);
+	joydev->exist = 1;
 
 	return &joydev->handle;
 }
@@ -495,12 +497,35 @@
 	}
 }
 
+static struct input_device_id joydev_ids[] = {
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+		evbit: { BIT(EV_KEY) | BIT(EV_ABS) },
+		absbit: { BIT(ABS_X) },
+	},
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+		evbit: { BIT(EV_KEY) | BIT(EV_ABS) },
+		absbit: { BIT(ABS_WHEEL) },
+	},
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+		evbit: { BIT(EV_KEY) | BIT(EV_ABS) },
+		absbit: { BIT(ABS_THROTTLE) },
+	},
+	{ }, 	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, joydev_ids);
+
 static struct input_handler joydev_handler = {
 	event:		joydev_event,
 	connect:	joydev_connect,
 	disconnect:	joydev_disconnect,
 	fops:		&joydev_fops,
 	minor:		JOYDEV_MINOR_BASE,
+	name:		"joydev",
+	id_table:	joydev_ids,
 };
 
 static int __init joydev_init(void)
diff --git a/drivers/input/joystick/iforce.c b/drivers/input/joystick/iforce.c
index f77ec22..3dd126a 100644
--- a/drivers/input/joystick/iforce.c
+++ b/drivers/input/joystick/iforce.c
@@ -641,7 +641,7 @@
 		effect->replay.delay,
 		effect->trigger.button,
 		effect->trigger.interval,
-		effect->u.periodic.direction);
+		effect->direction);
 
 	return err;
 }
@@ -680,7 +680,7 @@
 		effect->replay.delay,
 		effect->trigger.button,
 		effect->trigger.interval,
-		effect->u.constant.direction);
+		effect->direction);
 
 	return err;
 }
@@ -722,7 +722,7 @@
 		case 0: /* Only one axis, choose orientation */
 			mod1 = mod_chunk->start;
 			mod2 = 0xffff;
-			direction = effect->u.interactive.direction;
+			direction = effect->direction;
 			axes = 0x20;
 			break;
 
diff --git a/drivers/input/keybdev.c b/drivers/input/keybdev.c
index a437ac1..6731dd2 100644
--- a/drivers/input/keybdev.c
+++ b/drivers/input/keybdev.c
@@ -1,11 +1,9 @@
 /*
- * $Id: keybdev.c,v 1.3 2000/05/28 17:31:36 vojtech Exp $
+ * $Id: keybdev.c,v 1.16 2002/01/09 04:21:41 lethal Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
- *  Input driver to keyboard driver binding.
- *
- *  Sponsored by SuSE
+ *  Input core to console keyboard binding.
  */
 
 /*
@@ -24,8 +22,8 @@
  * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
@@ -37,10 +35,16 @@
 #include <linux/module.h>
 #include <linux/kbd_kern.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Input core to console keyboard binding");
+MODULE_LICENSE("GPL");
+
+char keybdev_name[] = "keyboard";
+
 #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \
     defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH) || \
     defined(CONFIG_PPC) || defined(__mc68000__) || defined(__hppa__) || \
-    defined(__arm__)
+    defined(__arm__) || defined(__x86_64__)
 
 static int x86_sysrq_alt = 0;
 #ifdef CONFIG_SPARC64
@@ -48,8 +52,6 @@
 extern void batten_down_hatches(void);
 #endif
 
-static int jp_kbd_109 = 1;	/* Yes, .jp is the default. See 51142. */
-
 static unsigned short x86_keycodes[256] =
 	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
@@ -62,7 +64,7 @@
 	360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
 	103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
 	291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
-	118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269,
+	118,117,125,374,379,115,112,125,121,123,264,265,266,267,268,269,
 	271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
 	308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
 	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
@@ -167,26 +169,38 @@
 	}
 }
 
+/* Tell the user who may be running in X and not see the console that we have 
+   panic'ed. This is to distingush panics from "real" lockups. 
+   Could in theory send the panic message as morse, but that is left as an
+   exercise for the reader.  */ 
+
+void panic_blink(void)
+{ 
+	static unsigned long last_jiffie;
+	static char led;
+	/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is different. */
+	if (jiffies - last_jiffie > HZ/2) {
+		led ^= 0x01 | 0x04;
+		keybdev_ledfunc(led);
+		last_jiffie = jiffies;
+	}
+}  
+
 void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
 {
 	if (type != EV_KEY) return;
-
-	if (emulate_raw(code, down))
-		printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
-
+	emulate_raw(code, down);
 	tasklet_schedule(&keyboard_tasklet);
 }
 
-static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
 {
 	struct input_handle *handle;
 	int i;
 
-	if (!test_bit(EV_KEY, dev->evbit))
-		return NULL;
-
-	for (i = KEY_RESERVED; i < BTN_MISC; i++)
-		if (test_bit(i, dev->keybit)) break;
+	for (i = KEY_ESC; i < BTN_MISC; i++)
+		if (test_bit(i, dev->keybit))
+			break;
 
 	if (i == BTN_MISC)
  		return NULL;
@@ -196,41 +210,42 @@
 	memset(handle, 0, sizeof(struct input_handle));
 
 	handle->dev = dev;
+	handle->name = keybdev_name;
 	handle->handler = handler;
 
 	input_open_device(handle);
 
-//	printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
-
 	return handle;
 }
 
 static void keybdev_disconnect(struct input_handle *handle)
 {
-//	printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
 	input_close_device(handle);
 	kfree(handle);
 }
+
+static struct input_device_id keybdev_ids[] = {
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+		evbit: { BIT(EV_KEY) },
+	},	
+	{ }, 	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, keybdev_ids);
 	
 static struct input_handler keybdev_handler = {
 	event:		keybdev_event,
 	connect:	keybdev_connect,
 	disconnect:	keybdev_disconnect,
+	name:		"keybdev",
+	id_table:	keybdev_ids,
 };
 
 static int __init keybdev_init(void)
 {
 	input_register_handler(&keybdev_handler);
 	kbd_ledfunc = keybdev_ledfunc;
-
-	if (jp_kbd_109) {
-		x86_keycodes[0xb5] = 0x73;	/* backslash, underscore */
-		x86_keycodes[0xb6] = 0x70;
-		x86_keycodes[0xb7] = 0x7d;	/* Yen, pipe */
-		x86_keycodes[0xb8] = 0x79;
-		x86_keycodes[0xb9] = 0x7b;
-	}
-
 	return 0;
 }
 
@@ -243,7 +258,3 @@
 module_init(keybdev_init);
 module_exit(keybdev_exit);
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Input driver to keyboard driver binding");
-MODULE_PARM(jp_kbd_109, "i");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index c37b6a0..01fb98c 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -1,11 +1,9 @@
 /*
- * $Id: mousedev.c,v 1.24 2000/11/15 10:57:45 vojtech Exp $
+ * $Id: mousedev.c,v 1.38 2001/12/26 21:08:33 jsimmons Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
- *  Input driver to ImExPS/2 device driver module.
- *
- *  Sponsored by SuSE
+ *  Input driver to ExplorerPS/2 device driver module.
  */
 
 /*
@@ -24,8 +22,8 @@
  * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #define MOUSEDEV_MINOR_BASE 	32
@@ -41,6 +39,10 @@
 #include <linux/smp_lock.h>
 #include <linux/random.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
+MODULE_LICENSE("GPL");
+
 #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
 #define CONFIG_INPUT_MOUSEDEV_SCREEN_X	1024
 #endif
@@ -52,6 +54,7 @@
 	int exist;
 	int open;
 	int minor;
+	char name[16];
 	wait_queue_head_t wait;
 	struct mousedev_list *list;
 	struct input_handle handle;
@@ -89,8 +92,6 @@
 	struct mousedev_list *list;
 	int index, size;
 
-	add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
-
 	while (*mousedev) {
 		list = (*mousedev)->list;
 		while (list) {
@@ -101,13 +102,23 @@
 					switch (code) {
 						case ABS_X:	
 							size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-							list->dx += (value * xres - list->oldx) / size;
-							list->oldx += list->dx * size;
+							if (size != 0) {
+								list->dx += (value * xres - list->oldx) / size;
+								list->oldx += list->dx * size;
+							} else {
+								list->dx += value - list->oldx;
+								list->oldx += list->dx;
+							}
 							break;
 						case ABS_Y:
 							size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-							list->dy -= (value * yres - list->oldy) / size;
-							list->oldy -= list->dy * size;
+							if (size != 0) {
+								list->dy -= (value * yres - list->oldy) / size;
+								list->oldy -= list->dy * size;
+							} else {
+								list->dy -= value - list->oldy;
+								list->oldy -= list->dy;
+							}
 							break;
 					}
 					break;
@@ -169,7 +180,7 @@
 {
 	struct mousedev_list *list = file->private_data;
 	struct mousedev_list **listptr;
-	
+
 	listptr = &list->mousedev->list;
 	mousedev_fasync(-1, file, 0);
 
@@ -344,7 +355,7 @@
 	if (!list->ready && !list->buffer) {
 
 		add_wait_queue(&list->mousedev->wait, &wait);
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 
 		while (!list->ready) {
 
@@ -360,7 +371,7 @@
 			schedule();
 		}
 
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&list->mousedev->wait, &wait);
 	}
 
@@ -401,19 +412,11 @@
 	fasync:		mousedev_fasync,
 };
 
-static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
+static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
 {
 	struct mousedev *mousedev;
 	int minor = 0;
 
-	if (!test_bit(EV_KEY, dev->evbit) ||
-	   (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
-		return NULL;
-
-	if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
-	    (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
-		return NULL;
-
 	for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
 	if (minor == MOUSEDEV_MINORS) {
 		printk(KERN_ERR "mousedev: no more free mousedev devices\n");
@@ -425,11 +428,12 @@
 	memset(mousedev, 0, sizeof(struct mousedev));
 	init_waitqueue_head(&mousedev->wait);
 
-	mousedev->exist = 1;
 	mousedev->minor = minor;
 	mousedev_table[minor] = mousedev;
+	sprintf(mousedev->name, "mouse%d", minor);
 
 	mousedev->handle.dev = dev;
+	mousedev->handle.name = mousedev->name;
 	mousedev->handle.handler = handler;
 	mousedev->handle.private = mousedev;
 
@@ -438,7 +442,7 @@
 	if (mousedev_mix.open)
 		input_open_device(&mousedev->handle);
 
-//	printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
+	mousedev->exist = 1;
 
 	return &mousedev->handle;
 }
@@ -459,6 +463,26 @@
 		kfree(mousedev);
 	}
 }
+
+static struct input_device_id mousedev_ids[] = {
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
+		evbit: { BIT(EV_KEY) | BIT(EV_REL) },
+		keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
+		relbit: { BIT(REL_X) | BIT(REL_Y) },
+	},	/* A mouse like device, at least one button, two relative axes */
+
+	{
+		flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+		evbit: { BIT(EV_KEY) | BIT(EV_ABS) },
+		keybit: { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+		absbit: { BIT(ABS_X) | BIT(ABS_Y) },
+	},	/* A tablet like device, at least touch detection, two absolute axes */
+
+	{ }, 	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, mousedev_ids);
 	
 static struct input_handler mousedev_handler = {
 	event:		mousedev_event,
@@ -466,6 +490,8 @@
 	disconnect:	mousedev_disconnect,
 	fops:		&mousedev_fops,
 	minor:		MOUSEDEV_MINOR_BASE,
+	name:		"mousedev",
+	id_table:	mousedev_ids,
 };
 
 static int __init mousedev_init(void)
@@ -493,10 +519,6 @@
 module_init(mousedev_init);
 module_exit(mousedev_exit);
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver");
-MODULE_LICENSE("GPL");
-
 MODULE_PARM(xres, "i");
 MODULE_PARM_DESC(xres, "Horizontal screen resolution");
 MODULE_PARM(yres, "i");
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 13a272d..74f82b3 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -87,8 +87,12 @@
  *
  */
 
+#define DRV_NAME	"3c501"
+#define DRV_VERSION	"2001/11/17"
+
+
 static const char version[] =
-    "3c501.c: 2000/02/08 Alan Cox (alan@redhat.com).\n";
+	DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@redhat.com).\n";
 
 /*
  *	Braindamage remaining:
@@ -108,7 +112,9 @@
 #include <linux/errno.h>
 #include <linux/config.h>	/* for CONFIG_IP_MULTICAST */
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
 
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 
@@ -139,12 +145,14 @@
 static int  el1_close(struct net_device *dev);
 static struct net_device_stats *el1_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 #define EL1_IO_EXTENT	16
 
 #ifndef EL_DEBUG
 #define EL_DEBUG  0	/* use 0 for production, 1 for devel., >2 for debug */
 #endif			/* Anything above 5 is wordy death! */
+#define debug el_debug
 static int el_debug = EL_DEBUG;
 
 /*
@@ -377,6 +385,7 @@
 	dev->stop = &el1_close;
 	dev->get_stats = &el1_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
+	dev->do_ioctl = netdev_ioctl;
 
 	/*
 	 *	Setup the generic properties
@@ -915,6 +924,86 @@
 	}
 }
 
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
 #ifdef MODULE
 
 static struct net_device dev_3c501 = {
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index c1768a1..b096744 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -29,11 +29,17 @@
     Paul Gortmaker	: add support for the 2nd 8kB of RAM on 16 bit cards.
     Paul Gortmaker	: multiple card support for module users.
     rjohnson@analogic.com : Fix up PIO interface for efficient operation.
+    Jeff Garzik		: ethtool support
 
 */
 
+#define DRV_NAME	"3c503"
+#define DRV_VERSION	"1.10a"
+#define DRV_RELDATE	"11/17/2001"
+
+
 static const char version[] =
-    "3c503.c:v1.10 9/23/93  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+    DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Donald Becker (becker@scyld.com)\n";
 
 #include <linux/module.h>
 
@@ -45,7 +51,9 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/ethtool.h>
 
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
@@ -74,6 +82,7 @@
 			   int ring_offset);
 static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 			 int ring_page);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 
 /* This routine probes for a memory-mapped 3c503 board by looking for
@@ -301,6 +310,7 @@
 
     dev->open = &el2_open;
     dev->stop = &el2_close;
+    dev->do_ioctl = &netdev_ioctl;
 
     if (dev->mem_start)
 	printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
@@ -607,6 +617,71 @@
     outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
     return;
 }
+
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
+
 #ifdef MODULE
 #define MAX_EL2_CARDS	4	/* Max number of EL2 cards per module */
 
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 8386add..6327ec4 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -35,8 +35,13 @@
  *                      Philip Blundell <Philip.Blundell@pobox.com>
  *              Multicard/soft configurable dma channel/rev 2 hardware support
  *                      by Christopher Collins <ccollins@pcug.org.au>
+ *		Ethtool support (jgarzik), 11/17/2001
  */
 
+#define DRV_NAME	"3c505"
+#define DRV_VERSION	"1.10a"
+
+
 /* Theory of operation:
  *
  * The 3c505 is quite an intelligent board.  All communication with it is done
@@ -103,6 +108,9 @@
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -148,10 +156,11 @@
  *********************************************************/
 
 #ifdef ELP_DEBUG
-static const int elp_debug = ELP_DEBUG;
+static int elp_debug = ELP_DEBUG;
 #else
-static const int elp_debug;
+static int elp_debug;
 #endif
+#define debug elp_debug
 
 /*
  *  0 = no messages (well, some)
@@ -1260,6 +1269,87 @@
 	}
 }
 
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
+
 /******************************************************
  *
  * initialise Etherlink Plus board
@@ -1280,6 +1370,7 @@
 	dev->tx_timeout = elp_timeout;			/* local */
 	dev->watchdog_timeo = 10*HZ;
 	dev->set_multicast_list = elp_set_mc_list;	/* local */
+	dev->do_ioctl = netdev_ioctl;			/* local */
 
 	/* Setup the generic properties */
 	ether_setup(dev);
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index df46dbb..3de0890 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -25,8 +25,12 @@
 	The statistics need to be updated correctly.
 */
 
+#define DRV_NAME		"3c507"
+#define DRV_VERSION		"1.10a"
+#define DRV_RELDATE		"11/17/2001"
+
 static const char version[] =
-	"3c507.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+	DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Donald Becker (becker@scyld.com)\n";
 
 
 #include <linux/module.h>
@@ -52,6 +56,9 @@
 #include <linux/in.h>
 #include <linux/string.h>
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -70,6 +77,8 @@
 #define NET_DEBUG 1
 #endif
 static unsigned int net_debug = NET_DEBUG;
+#define debug net_debug
+
 
 /* A zero-terminated list of common I/O addresses to be probed. */
 static unsigned int netcard_portlist[] __initdata =
@@ -296,6 +305,7 @@
 
 static void hardware_send_packet(struct net_device *dev, void *buf, short length);
 static void init_82586_mem(struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 
 /* Check for a network adaptor of this type, and return '0' iff one exists.
@@ -427,6 +437,7 @@
 	dev->get_stats	= el16_get_stats;
 	dev->tx_timeout = el16_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->do_ioctl = netdev_ioctl;
 
 	ether_setup(dev);	/* Generic ethernet behaviour */
 
@@ -864,6 +875,88 @@
 	lp->rx_head = rx_head;
 	lp->rx_tail = rx_tail;
 }
+
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
+
 #ifdef MODULE
 static struct net_device dev_3c507;
 static int io = 0x300;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index e6eddb3..4f5c959 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -43,8 +43,14 @@
 		v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au>
 			- Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz)
 			- Reviewed against 1.18 from scyld.com
+		v1.18 17Nov2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+			- ethtool support
 */
 
+#define DRV_NAME	"3c509"
+#define DRV_VERSION	"1.18a"
+#define DRV_RELDATE	"17Nov2001"
+
 /* A few values that may be tweaked. */
 
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -70,12 +76,14 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>	/* for udelay() */
 #include <linux/spinlock.h>
+#include <linux/ethtool.h>
 
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
-static char versionA[] __initdata = "3c509.c:1.18 12Mar2001 becker@scyld.com\n";
+static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE "becker@scyld.com\n";
 static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n";
 
 #ifdef EL3_DEBUG
@@ -84,6 +92,7 @@
 static int el3_debug = 2;
 #endif
 
+
 /* To minimize the size of the driver source I only define operating
    constants if they are used several times.  You'll need the manual
    anyway if you want to understand driver details. */
@@ -158,6 +167,7 @@
 static int el3_close(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static void el3_tx_timeout (struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 #ifdef CONFIG_MCA
 struct el3_mca_adapters_struct {
@@ -513,6 +523,7 @@
 	dev->set_multicast_list = &set_multicast_list;
 	dev->tx_timeout = el3_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->do_ioctl = netdev_ioctl;
 
 	/* Fill in the generic fields of the device structure. */
 	ether_setup(dev);
@@ -1003,6 +1014,85 @@
 	return 0;
 }
 
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = el3_debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		el3_debug = edata.data;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
 #ifdef MODULE
 /* Parameters that may be passed into the module. */
 static int debug = -1;
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 83cecdc..73502bc 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -16,9 +16,17 @@
 	2/2/00- Added support for kernel-level ISAPnP 
 		by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo
 	Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
+	
+	11/17/2001 - Added ethtool support (jgarzik)
+
 */
 
-static char *version = "3c515.c:v0.99-sn 2000/02/12 becker@cesdis.gsfc.nasa.gov and others\n";
+#define DRV_NAME		"3c515"
+#define DRV_VERSION		"0.99t"
+#define DRV_RELDATE		"17-Nov-2001"
+
+static char *version =
+DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " becker@scyld.com and others\n";
 
 #define CORKSCREW 1
 
@@ -63,6 +71,9 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/timer.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -393,6 +404,7 @@
 static void update_stats(int addr, struct net_device *dev);
 static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 
 /* 
@@ -721,6 +733,7 @@
 	dev->stop = &corkscrew_close;
 	dev->get_stats = &corkscrew_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = netdev_ioctl;
 
 	return 0;
 }
@@ -1591,6 +1604,87 @@
 
 	outw(new_mode, ioaddr + EL3_CMD);
 }
+
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = corkscrew_debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		corkscrew_debug = edata.data;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
 
 #ifdef MODULE
 void cleanup_module(void)
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index eb2480f..1837f30 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -81,10 +81,15 @@
    added option to disable multicast as is causes problems
        Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk>
        Stuart Adamson <stuart.adamson@compsoc.net>
+   Nov 2001
+   added support for ethtool (jgarzik)
 	
    $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
  */
 
+#define DRV_NAME		"3c523"
+#define DRV_VERSION		"17-Nov-2001"
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -95,6 +100,9 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/mca.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -182,6 +190,7 @@
 #ifdef ELMC_MULTICAST
 static void set_multicast_list(struct net_device *dev);
 #endif
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 /* helper-functions */
 static int init586(struct net_device *dev);
@@ -563,7 +572,8 @@
 #else
 	dev->set_multicast_list = NULL;
 #endif
-
+	dev->do_ioctl = netdev_ioctl;
+	
 	ether_setup(dev);
 
 	/* note that we haven't actually requested the IRQ from the kernel.
@@ -1214,6 +1224,69 @@
 }
 #endif
 
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
 /*************************************************************************/
 
 #ifdef MODULE
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 75bd0ae..50f70f9 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -16,8 +16,12 @@
  *
  */
 
+#define DRV_NAME		"3c527"
+#define DRV_VERSION		"0.6a"
+#define DRV_RELDATE		"2001/11/17"
+
 static const char *version =
-	"3c527.c:v0.6 2001/03/03 Richard Proctor (rnp@netlink.co.nz)\n";
+DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Proctor (rnp@netlink.co.nz)\n";
 
 /**
  * DOC: Traps for the unwary
@@ -90,6 +94,9 @@
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -108,7 +115,7 @@
  * The name of the card. Is used for messages and in the requests for
  * io regions, irqs and dma channels
  */
-static const char* cardname = "3c527";
+static const char* cardname = DRV_NAME;
 
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
@@ -213,6 +220,7 @@
 static struct	net_device_stats *mc32_get_stats(struct net_device *dev);
 static void	mc32_set_multicast_list(struct net_device *dev);
 static void	mc32_reset_multicast_list(struct net_device *dev);
+static int	netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 /**
  * mc32_probe 	-	Search for supported boards
@@ -502,7 +510,7 @@
 	dev->set_multicast_list = mc32_set_multicast_list;
 	dev->tx_timeout		= mc32_timeout;
 	dev->watchdog_timeo	= HZ*5;	/* Board does all the work */
-
+	dev->do_ioctl		= netdev_ioctl;
 	
 	lp->xceiver_state = HALTED; 
 	
@@ -1644,6 +1652,86 @@
 	do_mc32_set_multicast_list(dev,1);
 }
 
+/**
+ * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @useraddr: userspace address to which data is to be read and returned
+ *
+ * Process the various commands of the SIOCETHTOOL interface.
+ */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = mc32_debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		mc32_debug = edata.data;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/**
+ * netdev_ioctl: Handle network interface ioctls
+ * @dev: network interface on which out-of-band action is to be performed
+ * @rq: user request data
+ * @cmd: command issued by user
+ *
+ * Process the various out-of-band ioctls passed to this driver.
+ */
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc = 0;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+ 
 #ifdef MODULE
 
 static struct net_device this_device;
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index e574584..944407b 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -20,7 +20,6 @@
 	TODO, in rough priority order:
 	* dev->tx_timeout
 	* LinkChg interrupt
-	* ETHTOOL_[GS]SET
 	* Support forcing media type with a module parameter,
 	  like dl2k.c/sundance.c
 	* Implement PCI suspend/resume
@@ -33,18 +32,19 @@
 	* Rx checksumming
 	* Tx checksumming
 	* ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
-	  ETHTOOL_[GS]MSGLVL, ETHTOOL_NWAY_RST
 	* Jumbo frames / dev->change_mtu
 	* Investigate using skb->priority with h/w VLAN priority
 	* Investigate using High Priority Tx Queue with skb->priority
 	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
 	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
+        * Implement Tx software interrupt mitigation via
+	          Tx descriptor bit
 
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"0.0.5"
-#define DRV_RELDATE		"Oct 19, 2001"
+#define DRV_VERSION		"0.0.6cvs"
+#define DRV_RELDATE		"Nov 19, 2001"
 
 
 #include <linux/module.h>
@@ -56,6 +56,7 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/crc32.h>
+#include <linux/mii.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -94,10 +95,10 @@
 	(((CP)->tx_tail <= (CP)->tx_head) ?			\
 	  (CP)->tx_tail + (CP_TX_RING_SIZE - 1) - (CP)->tx_head :	\
 	  (CP)->tx_tail - (CP)->tx_head - 1)
-#define CP_CHIP_VERSION		0x76
 
 #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
 #define RX_OFFSET		2
+#define CP_INTERNAL_PHY		32
 
 /* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
 #define RX_FIFO_THRESH		5	/* Rx buffer level before first PCI xfer.  */
@@ -126,6 +127,11 @@
 	Config3		= 0x59, /* Config3 */
 	Config4		= 0x5A, /* Config4 */
 	MultiIntr	= 0x5C, /* Multiple interrupt select */
+	BasicModeCtrl	= 0x62,	/* MII BMCR */
+	BasicModeStatus	= 0x64, /* MII BMSR */
+	NWayAdvert	= 0x66, /* MII ADVERTISE */
+	NWayLPAR	= 0x68, /* MII LPA */
+	NWayExpansion	= 0x6A, /* MII Expansion */
 	Config5		= 0xD8,	/* Config5 */
 	TxPoll		= 0xD9,	/* Tell chip to check Tx descriptors for work */
 	CpCmd		= 0xE0, /* C+ Command register (C+ mode only) */
@@ -279,6 +285,8 @@
 
 	struct sk_buff		*frag_skb;
 	unsigned		dropping_frag : 1;
+
+	struct mii_if_info	mii_if;
 };
 
 #define cpr8(reg)	readb(cp->regs + (reg))
@@ -985,6 +993,39 @@
 	return 0;
 }
 
+static char mii_2_8139_map[8] = {
+	BasicModeCtrl,
+	BasicModeStatus,
+	0,
+	0,
+	NWayAdvert,
+	NWayLPAR,
+	NWayExpansion,
+	0
+};
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	struct cp_private *cp = dev->priv;
+
+	return location < 8 && mii_2_8139_map[location] ?
+	       readw(cp->regs + mii_2_8139_map[location]) : 0;
+}
+
+
+static void mdio_write(struct net_device *dev, int phy_id, int location,
+		       int value)
+{
+	struct cp_private *cp = dev->priv;
+
+	if (location == 0) {
+		cpw8(Cfg9346, Cfg9346_Unlock);
+		cpw16(BasicModeCtrl, value);
+		cpw8(Cfg9346, Cfg9346_Lock);
+	} else if (location < 8 && mii_2_8139_map[location])
+		cpw16(mii_2_8139_map[location], value);
+}
+
 static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
 {
 	u32 ethcmd;
@@ -992,21 +1033,71 @@
 	/* dev_ioctl() in ../../net/core/dev.c has already checked
 	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
 
-	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+	if (get_user(ethcmd, (u32 *)useraddr))
 		return -EFAULT;
 
 	switch (ethcmd) {
 
-	case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strcpy (info.driver, DRV_NAME);
-			strcpy (info.version, DRV_VERSION);
-			strcpy (info.bus_info, cp->pdev->slot_name);
-			if (copy_to_user (useraddr, &info, sizeof (info)))
-				return -EFAULT;
-			return 0;
-		}
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		strcpy (info.bus_info, cp->pdev->slot_name);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&cp->lock);
+		mii_ethtool_gset(&cp->mii_if, &ecmd);
+		spin_unlock_irq(&cp->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&cp->lock);
+		r = mii_ethtool_sset(&cp->mii_if, &ecmd);
+		spin_unlock_irq(&cp->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&cp->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&cp->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = cp->msg_enable;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		cp->msg_enable = edata.data;
+		return 0;
+	}
 
 	default:
 		break;
@@ -1136,6 +1227,10 @@
 	cp->dev = dev;
 	cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
 	spin_lock_init (&cp->lock);
+	cp->mii_if.dev = dev;
+	cp->mii_if.mdio_read = mdio_read;
+	cp->mii_if.mdio_write = mdio_write;
+	cp->mii_if.phy_id = CP_INTERNAL_PHY;
 
 	rc = pci_enable_device(pdev);
 	if (rc)
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 5d2e80d..91ee34c 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -92,7 +92,7 @@
 */
 
 #define DRV_NAME	"8139too"
-#define DRV_VERSION	"0.9.22"
+#define DRV_VERSION	"0.9.24"
 
 
 #include <linux/config.h>
@@ -160,6 +160,9 @@
    The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
 static int multicast_filter_limit = 32;
 
+/* bitmapped message enable number */
+static int debug = -1;
+
 /* Size of the in-memory receive ring. */
 #define RX_BUF_LEN_IDX	2	/* 0==8K, 1==16K, 2==32K, 3==64K */
 #define RX_BUF_LEN	(8192 << RX_BUF_LEN_IDX)
@@ -213,6 +216,7 @@
 	ADDTRON8139,
 	DFE538TX,
 	DFE690TXD,
+	FE2000VX,
 	RTL8129,
 } board_t;
 
@@ -230,6 +234,7 @@
 	{ "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS },
 	{ "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS },
 	{ "D-Link DFE-690TXD (RealTek RTL8139)", RTL8139_CAPS },
+	{ "AboCom FE2000VX (RealTek RTL8139)", RTL8139_CAPS },
 	{ "RealTek RTL8129", RTL8129_CAPS },
 };
 
@@ -243,6 +248,7 @@
 	{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
 	{0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX },
 	{0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD },
+	{0x13d1, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FE2000VX },
 
 #ifdef CONFIG_8139TOO_8129
 	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
@@ -254,6 +260,7 @@
 	 */
 	{PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
 	{PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, DFE538TX },
+	{PCI_ANY_ID, 0x8139, 0x13d1, 0xab06, 0, 0, FE2000VX },
 
 	{0,}
 };
@@ -526,6 +533,7 @@
 	unsigned long early_rx;
 	unsigned long tx_buf_mapped;
 	unsigned long tx_timeouts;
+	unsigned long rx_lost_in_ring;
 };
 
 struct rtl8139_private {
@@ -544,12 +552,8 @@
 	dma_addr_t tx_bufs_dma;
 	signed char phys[4];		/* MII device addresses. */
 	char twistie, twist_row, twist_col;	/* Twister tune state. */
-	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
-	unsigned int duplex_lock:1;
 	unsigned int default_port:4;	/* Last dev->if_port value. */
-	unsigned int media2:4;	/* Secondary monitored media port. */
 	unsigned int medialock:1;	/* Don't sense media type. */
-	unsigned int mediasense:1;	/* Media sensing in progress. */
 	spinlock_t lock;
 	chip_t chipset;
 	pid_t thr_pid;
@@ -558,6 +562,7 @@
 	u32 rx_config;
 	struct rtl_extra_stats xstats;
 	int time_to_die;
+	struct mii_if_info mii;
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
@@ -568,6 +573,8 @@
 MODULE_PARM (max_interrupt_work, "i");
 MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "8139too bitmapped message enable number");
 MODULE_PARM_DESC (multicast_filter_limit, "8139too maximum number of filtered multicast addresses");
 MODULE_PARM_DESC (max_interrupt_work, "8139too maximum events handled per interrupt");
 MODULE_PARM_DESC (media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
@@ -948,6 +955,9 @@
 	spin_lock_init (&tp->lock);
 	init_waitqueue_head (&tp->thr_wait);
 	init_completion (&tp->thr_exited);
+	tp->mii.dev = dev;
+	tp->mii.mdio_read = mdio_read;
+	tp->mii.mdio_write = mdio_write;
 
 	/* dev is fully set up and ready to use now */
 	DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
@@ -999,18 +1009,18 @@
 	/* The lower four bits are the media type. */
 	option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
 	if (option > 0) {
-		tp->full_duplex = (option & 0x210) ? 1 : 0;
+		tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
 		tp->default_port = option & 0xFF;
 		if (tp->default_port)
 			tp->medialock = 1;
 	}
 	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
-		tp->full_duplex = full_duplex[board_idx];
-	if (tp->full_duplex) {
+		tp->mii.full_duplex = full_duplex[board_idx];
+	if (tp->mii.full_duplex) {
 		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
 		/* Changing the MII-advertised media because might prevent
 		   re-connection. */
-		tp->duplex_lock = 1;
+		tp->mii.duplex_lock = 1;
 	}
 	if (tp->default_port) {
 		printk(KERN_INFO "  Forcing %dMbps %s-duplex operation.\n",
@@ -1267,7 +1277,7 @@
 
 	}
 
-	tp->full_duplex = tp->duplex_lock;
+	tp->mii.full_duplex = tp->mii.duplex_lock;
 	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
 	tp->twistie = 1;
 	tp->time_to_die = 0;
@@ -1279,7 +1289,7 @@
 			" GP Pins %2.2x %s-duplex.\n",
 			dev->name, pci_resource_start (tp->pci_dev, 1),
 			dev->irq, RTL_R8 (MediaStatus),
-			tp->full_duplex ? "full" : "half");
+			tp->mii.full_duplex ? "full" : "half");
 
 	tp->thr_pid = kernel_thread (rtl8139_thread, dev, CLONE_FS | CLONE_FILES);
 	if (tp->thr_pid < 0)
@@ -1295,18 +1305,18 @@
 	struct rtl8139_private *tp = dev->priv;
 
 	if (tp->phys[0] >= 0) {
-		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-		if (mii_reg5 == 0xffff)
+		u16 mii_lpa = mdio_read(dev, tp->phys[0], MII_LPA);
+		if (mii_lpa == 0xffff)
 			;					/* Not there */
-		else if ((mii_reg5 & 0x0100) == 0x0100
-				 || (mii_reg5 & 0x00C0) == 0x0040)
-			tp->full_duplex = 1;
+		else if ((mii_lpa & LPA_100FULL) == LPA_100FULL
+				 || (mii_lpa & 0x00C0) == LPA_10FULL)
+			tp->mii.full_duplex = 1;
 
 		printk (KERN_INFO"%s: Setting %s%s-duplex based on"
 				" auto-negotiated partner ability %4.4x.\n",
-		        dev->name, mii_reg5 == 0 ? "" :
-				(mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
-			tp->full_duplex ? "full" : "half", mii_reg5);
+		        dev->name, mii_lpa == 0 ? "" :
+				(mii_lpa & 0x0180) ? "100mbps " : "10mbps ",
+			tp->mii.full_duplex ? "full" : "half", mii_lpa);
 	}
 }
 
@@ -1494,30 +1504,30 @@
 				 struct rtl8139_private *tp,
 				 void *ioaddr)
 {
-	int mii_reg5;
+	int mii_lpa;
 
-	mii_reg5 = mdio_read (dev, tp->phys[0], 5);
+	mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
 
-	if (!tp->duplex_lock && mii_reg5 != 0xffff) {
-		int duplex = (mii_reg5 & 0x0100)
-		    || (mii_reg5 & 0x01C0) == 0x0040;
-		if (tp->full_duplex != duplex) {
-			tp->full_duplex = duplex;
+	if (!tp->mii.duplex_lock && mii_lpa != 0xffff) {
+		int duplex = (mii_lpa & LPA_100FULL)
+		    || (mii_lpa & 0x01C0) == 0x0040;
+		if (tp->mii.full_duplex != duplex) {
+			tp->mii.full_duplex = duplex;
 
-			if (mii_reg5) {
+			if (mii_lpa) {
 				printk (KERN_INFO
 					"%s: Setting %s-duplex based on MII #%d link"
 					" partner ability of %4.4x.\n",
 					dev->name,
-					tp->full_duplex ? "full" : "half",
-					tp->phys[0], mii_reg5);
+					tp->mii.full_duplex ? "full" : "half",
+					tp->phys[0], mii_lpa);
 			} else {
 				printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
 				       dev->name);
 			}
 #if 0
 			RTL_W8 (Cfg9346, Cfg9346_Unlock);
-			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+			RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
 			RTL_W8 (Cfg9346, Cfg9346_Lock);
 #endif
 		}
@@ -1750,23 +1760,36 @@
 			    struct rtl8139_private *tp, void *ioaddr)
 {
 	u8 tmp8;
+#ifndef CONFIG_8139_NEW_RX_RESET
 	int tmp_work;
+#endif
 
 	DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n",
 	         dev->name, rx_status);
-	if (rx_status & RxTooLong) {
-		DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
-			 dev->name, rx_status);
-		/* A.C.: The chip hangs here. */
-	}
 	tp->stats.rx_errors++;
-	if (rx_status & (RxBadSymbol | RxBadAlign))
-		tp->stats.rx_frame_errors++;
-	if (rx_status & (RxRunt | RxTooLong))
-		tp->stats.rx_length_errors++;
-	if (rx_status & RxCRCErr)
-		tp->stats.rx_crc_errors++;
+	if (!(rx_status & RxStatusOK)) {
+		if (rx_status & RxTooLong) {
+			DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
+			 	dev->name, rx_status);
+			/* A.C.: The chip hangs here. */
+		}
+		if (rx_status & (RxBadSymbol | RxBadAlign))
+			tp->stats.rx_frame_errors++;
+		if (rx_status & (RxRunt | RxTooLong))
+			tp->stats.rx_length_errors++;
+		if (rx_status & RxCRCErr)
+			tp->stats.rx_crc_errors++;
+	} else {
+		tp->xstats.rx_lost_in_ring++;
+	}
 
+#ifdef CONFIG_8139_NEW_RX_RESET
+	tmp8 = RTL_R8 (ChipCmd);
+	RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
+	RTL_W8 (ChipCmd, tmp8);
+	RTL_W32 (RxConfig, tp->rx_config);
+	tp->cur_rx = 0;
+#else
 	/* Reset the receiver, based on RealTek recommendation. (Bug?) */
 
 	/* disable receive */
@@ -1811,6 +1834,7 @@
 
 	/* A.C.: Reset the multicast list. */
 	__set_rx_mode (dev);
+#endif
 }
 
 static void rtl8139_rx_interrupt (struct net_device *dev,
@@ -1945,13 +1969,13 @@
 	    (tp->drv_flags & HAS_LNK_CHNG)) {
 		/* Really link-change on new chips. */
 		int lpar = RTL_R16 (NWayLPAR);
-		int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040
-				|| tp->duplex_lock;
-		if (tp->full_duplex != duplex) {
-			tp->full_duplex = duplex;
+		int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040
+				|| tp->mii.duplex_lock;
+		if (tp->mii.full_duplex != duplex) {
+			tp->mii.full_duplex = duplex;
 #if 0
 			RTL_W8 (Cfg9346, Cfg9346_Unlock);
-			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+			RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
 			RTL_W8 (Cfg9346, Cfg9346_Lock);
 #endif
 		}
@@ -2110,48 +2134,6 @@
 }
 
 
-/* Get the ethtool settings.  Assumes that eset points to kernel
-   memory, *eset has been initialized as {ETHTOOL_GSET}, and other
-   threads or interrupts aren't messing with the 8139.  */
-static void netdev_get_eset (struct net_device *dev, struct ethtool_cmd *eset)
-{
-	struct rtl8139_private *np = dev->priv;
-	void *ioaddr = np->mmio_addr;
-	u16 advert;
-
-	eset->supported = SUPPORTED_10baseT_Half
-		      	| SUPPORTED_10baseT_Full
-		      	| SUPPORTED_100baseT_Half
-		      	| SUPPORTED_100baseT_Full
-		      	| SUPPORTED_Autoneg
-		      	| SUPPORTED_TP;
-
-	eset->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
-	advert = mdio_read (dev, np->phys[0], 4);
-	if (advert & 0x0020)
-		eset->advertising |= ADVERTISED_10baseT_Half;
-	if (advert & 0x0040)
-		eset->advertising |= ADVERTISED_10baseT_Full;
-	if (advert & 0x0080)
-		eset->advertising |= ADVERTISED_100baseT_Half;
-	if (advert & 0x0100)
-		eset->advertising |= ADVERTISED_100baseT_Full;
-
-	eset->speed = (RTL_R8 (MediaStatus) & 0x08) ? 10 : 100;
-	/* (KON)FIXME: np->full_duplex is set or reset by the thread,
-	   which means this always shows half duplex if the interface
-	   isn't up yet, even if it has already autonegotiated.  */
-	eset->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-	eset->port = PORT_TP;
-	/* (KON)FIXME: Is np->phys[0] correct?  starfire.c uses that.  */
-	eset->phy_address = np->phys[0];
-	eset->transceiver = XCVR_INTERNAL;
-	eset->autoneg = (mdio_read (dev, np->phys[0], 0) & 0x1000) != 0;
-	eset->maxtxpkt = 1;
-	eset->maxrxpkt = 1;
-}
-
-
 /* Get the ethtool Wake-on-LAN settings.  Assumes that wol points to
    kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and
    other threads or interrupts aren't messing with the 8139.  */
@@ -2226,7 +2208,6 @@
 	return 0;
 }
 
-
 static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	struct rtl8139_private *np = dev->priv;
@@ -2235,33 +2216,71 @@
 	/* dev_ioctl() in ../../net/core/dev.c has already checked
 	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
 
-	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+	if (get_user(ethcmd, (u32 *)useraddr))
 		return -EFAULT;
 
 	switch (ethcmd) {
-	case ETHTOOL_GSET:
-		{
-			struct ethtool_cmd eset = { ETHTOOL_GSET };
-			spin_lock_irq (&np->lock);
-			netdev_get_eset (dev, &eset);
-			spin_unlock_irq (&np->lock);
-			if (copy_to_user (useraddr, &eset, sizeof (eset)))
-				return -EFAULT;
-			return 0;
-		}
 
-	/* TODO: ETHTOOL_SSET */
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		strcpy (info.bus_info, np->pci_dev->slot_name);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
 
-	case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strcpy (info.driver, DRV_NAME);
-			strcpy (info.version, DRV_VERSION);
-			strcpy (info.bus_info, np->pci_dev->slot_name);
-			if (copy_to_user (useraddr, &info, sizeof (info)))
-				return -EFAULT;
-			return 0;
-		}
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&np->mii);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&np->mii);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
 
 	case ETHTOOL_GWOL:
 		{
@@ -2315,17 +2334,14 @@
 		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
 	case SIOCGMIIPHY:	/* Get the address of the PHY in use. */
-	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
 		data->phy_id = phy;
 		/* Fall Through */
 
 	case SIOCGMIIREG:	/* Read the specified MII register. */
-	case SIOCDEVPRIVATE+1:	/* binary compat, remove in 2.5 */
 		data->val_out = mdio_read (dev, data->phy_id, data->reg_num);
 		break;
 
 	case SIOCSMIIREG:	/* Write the specified MII register */
-	case SIOCDEVPRIVATE+2:	/* binary compat, remove in 2.5 */
 		if (!capable (CAP_NET_ADMIN)) {
 			rc = -EPERM;
 			break;
@@ -2338,9 +2354,9 @@
 				/* Check for autonegotiation on or reset. */
 				tp->medialock = (value & 0x9000) ? 0 : 1;
 				if (tp->medialock)
-					tp->full_duplex = (value & 0x0100) ? 1 : 0;
+					tp->mii.full_duplex = (value & 0x0100) ? 1 : 0;
 				break;
-			case 4: /* tp->advertising = value; */ break;
+			case 4: tp->mii.advertising = value; break;
 			}
 		}
 		mdio_write(dev, data->phy_id, data->reg_num, data->val_in);
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 1007100..eee781f 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -179,6 +179,7 @@
       dep_mbool '      Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO
       dep_mbool '      Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
       dep_mbool '      Support for older RTL-8129/8130 boards' CONFIG_8139TOO_8129 $CONFIG_8139TOO
+      dep_mbool '      Experiment for better RX reset (EXPERIMENTAL)' CONFIG_8139_NEW_RX_RESET $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
       dep_tristate '    SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
       dep_tristate '    SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
       dep_tristate '    Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 2826714..9269343 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -68,7 +68,7 @@
 obj-$(CONFIG_PCNET32) += pcnet32.o
 obj-$(CONFIG_EEPRO100) += eepro100.o
 obj-$(CONFIG_TLAN) += tlan.o
-obj-$(CONFIG_EPIC100) += epic100.o
+obj-$(CONFIG_EPIC100) += epic100.o mii.o
 obj-$(CONFIG_SIS900) += sis900.o
 obj-$(CONFIG_DM9102) += dmfe.o
 obj-$(CONFIG_YELLOWFIN) += yellowfin.o
@@ -77,7 +77,7 @@
 obj-$(CONFIG_NATSEMI) += natsemi.o
 obj-$(CONFIG_NS83820) += ns83820.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
-obj-$(CONFIG_FEALNX) += fealnx.o
+obj-$(CONFIG_FEALNX) += fealnx.o mii.o
 obj-$(CONFIG_TIGON3) += tg3.o
 
 ifeq ($(CONFIG_SK98LIN),y)
@@ -88,7 +88,7 @@
   obj-y += skfp/skfp.o
 endif
 
-obj-$(CONFIG_VIA_RHINE) += via-rhine.o
+obj-$(CONFIG_VIA_RHINE) += via-rhine.o mii.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
 
 #
@@ -101,7 +101,7 @@
 obj-$(CONFIG_AIRONET4500_PROC)	+= aironet4500_proc.o
 obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_proc.o
 
-obj-$(CONFIG_WINBOND_840) += winbond-840.o
+obj-$(CONFIG_WINBOND_840) += winbond-840.o mii.o
 obj-$(CONFIG_SUNDANCE) += sundance.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
@@ -165,8 +165,8 @@
 obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_EEXPRESS) += eexpress.o
 obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_8139CP) += 8139cp.o
-obj-$(CONFIG_8139TOO) += 8139too.o
+obj-$(CONFIG_8139CP) += 8139cp.o mii.o
+obj-$(CONFIG_8139TOO) += 8139too.o mii.o
 obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
 obj-$(CONFIG_ZNET) += znet.o
 obj-$(CONFIG_LAN_SAA9730) += saa9730.o
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 894e65f..e407317 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -1135,12 +1135,14 @@
 
 	/* fixme */
 	switch(cmd) { 
-		case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
 		data[0] = PHY_ADDRESS;
-		case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+
+		case SIOCGMIIREG:		/* Read the specified MII register. */
 		//data[3] = mdio_read(ioaddr, data[0], data[1]); 
 		return 0;
-		case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+
+		case SIOCSMIIREG:		/* Write the specified MII register */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		//mdio_write(ioaddr, data[0], data[1], data[2]);
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index 3af7268..4d79396 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -3645,7 +3645,7 @@
     tmp = virt_to_bus(p->data);
     i = ((tmp + ALIGN) & ~ALIGN) - tmp;
     skb_reserve(p, i);
-    lp->rx_ring[index].buf = tmp + i;
+    lp->rx_ring[index].buf = cpu_to_le32(tmp + i);
 
     ret = lp->rx_skb[index];
     lp->rx_skb[index] = p;
@@ -5616,7 +5616,7 @@
 	if (!capable(CAP_NET_ADMIN)) return -EPERM;
 	omr = inl(DE4X5_OMR);
 	omr &= ~OMR_PR;
-	outb(omr, DE4X5_OMR);
+	outl(omr, DE4X5_OMR);
 	dev->flags &= ~IFF_PROMISC;
 	break;
 
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 707adf2..efdffd6 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -15,18 +15,24 @@
     0.01	2001/05/03	Created DL2000-based linux driver
     0.02	2001/05/21	Added VLAN and hardware checksum support.
     1.00	2001/06/26	Added jumbo frame support.
-    1.01	2001/08/21	Added two parameters, int_count and int_timeout.
+    1.01	2001/08/21	Added two parameters, rx_coalesce and rx_timeout.
     1.02	2001/10/08	Supported fiber media.
     				Added flow control parameters.
-    1.03	2001/10/12	Changed the default media to 1000mbps_fd for the 
-    				fiber devices.
-    1.04	2001/11/08	Fixed a bug which Tx stop when a very busy case.
-*/
+    1.03	2001/10/12	Changed the default media to 1000mbps_fd for 
+    				the fiber devices.
+    1.04	2001/11/08	Fixed Tx stopped when tx very busy.
+    1.05	2001/11/22	Fixed Tx stopped when unidirectional tx busy.
+    1.06	2001/12/13	Fixed disconnect bug at 10Mbps mode.
+    				Fixed tx_full flag incorrect.
+				Added tx_coalesce paramter.
+    1.07	2002/01/03	Fixed miscount of RX frame error.
+    1.08	2002/01/17	Fixed the multicast bug.
+ */
 
 #include "dl2k.h"
 
 static char version[] __devinitdata =
-    KERN_INFO "D-Link DL2000-based linux driver v1.04 2001/11/08\n";
+    KERN_INFO "D-Link DL2000-based linux driver v1.08 2002/01/17\n";
 
 #define MAX_UNITS 8
 static int mtu[MAX_UNITS];
@@ -36,11 +42,13 @@
 static int tx_flow[MAX_UNITS];
 static int rx_flow[MAX_UNITS];
 static int copy_thresh;
-static int int_count;		/* Rx frame count each interrupt */
-static int int_timeout;		/* Rx DMA wait time in 64ns increments */
+static int rx_coalesce = DEFAULT_RXC;
+static int rx_timeout = DEFAULT_RXT;	
+static int tx_coalesce = DEFAULT_TXC;	
 
 MODULE_AUTHOR ("Edward Peng");
 MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
+MODULE_LICENSE("GPL");
 MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i");
 MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s");
 MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i");
@@ -48,13 +56,16 @@
 MODULE_PARM (tx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i");
 MODULE_PARM (rx_flow, "1-" __MODULE_STRING (MAX_UNITS) "i");
 MODULE_PARM (copy_thresh, "i");
-MODULE_PARM (int_count, "i");
-MODULE_PARM (int_timeout, "i");
+MODULE_PARM (rx_coalesce, "i");	/* Rx frame count each interrupt */
+MODULE_PARM (rx_timeout, "i");	/* Rx DMA wait time in 64ns increments */
+MODULE_PARM (tx_coalesce, "i"); /* HW xmit count each TxComplete [1-8] */
+
 
 /* Enable the default interrupts */
+#define DEFAULT_INTR (RxDMAComplete | HostError | IntRequested | TxComplete| \
+       UpdateStats | LinkEvent)
 #define EnableInt() \
-writew(RxDMAComplete | HostError | IntRequested | TxComplete| \
-       UpdateStats | LinkEvent, ioaddr + IntEnable)
+writew(DEFAULT_INTR, ioaddr + IntEnable)
 
 static int max_intrloop = 50;
 static int multicast_filter_limit = 0x40;
@@ -162,11 +173,11 @@
 				np->speed = 10;
 				np->full_duplex = 0;
 			} else if (strcmp (media[card_idx], "1000mbps_fd") == 0 ||
-				 strcmp (media[card_idx], "5") == 0) {
+				 strcmp (media[card_idx], "6") == 0) {
 				np->speed=1000;
 				np->full_duplex=1;
 			} else if (strcmp (media[card_idx], "1000mbps_hd") == 0 ||
-				 strcmp (media[card_idx], "6") == 0) {
+				 strcmp (media[card_idx], "5") == 0) {
 				np->speed = 1000;
 				np->full_duplex = 0;
 			} else {
@@ -175,7 +186,7 @@
 		}
 		if (jumbo[card_idx] != 0) {
 			np->jumbo = 1;
-			dev->mtu = 9000;
+			dev->mtu = MAX_JUMBO;
 		} else {
 			np->jumbo = 0;
 			if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE)
@@ -183,14 +194,17 @@
 		}
 		np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ?
 		    vlan[card_idx] : 0;
-		if (int_count != 0 && int_timeout != 0) {
-			np->int_count = int_count;
-			np->int_timeout = int_timeout;
+		if (rx_coalesce != 0 && rx_timeout != 0) {
+			np->rx_coalesce = rx_coalesce;
+			np->rx_timeout = rx_timeout;
 			np->coalesce = 1;
 		}
 		np->tx_flow = (tx_flow[card_idx]) ? 1 : 0;
 		np->rx_flow = (rx_flow[card_idx]) ? 1 : 0;
-		
+		if (tx_coalesce < 1)
+			tx_coalesce = 1;
+		if (tx_coalesce > 8)
+			tx_coalesce = 8;
 	}
 	dev->open = &rio_open;
 	dev->hard_start_xmit = &start_xmit;
@@ -201,8 +215,8 @@
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->change_mtu = &change_mtu;
-#ifdef TX_HW_CHECKSUM
-	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
+#if 0
+	dev->features = NETIF_F_IP_CSUM;
 #endif
 	pci_set_drvdata (pdev, dev);
 
@@ -326,7 +340,7 @@
 	}
 
 	/* Check CRC */
- 	crc = ~ether_crc_le(256-4, sromdata);
+	crc = ~ether_crc_le(256 - 4, sromdata);
 	if (psrom->crc != crc) {
 		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
 		return -1;
@@ -388,13 +402,12 @@
 	i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
 	if (i)
 		return i;
-
 	/* DebugCtrl bit 4, 5, 9 must set */
 	writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
 
 	/* Jumbo frame */
 	if (np->jumbo != 0)
-		writew (9014, ioaddr + MaxFrameSize);
+		writew (MAX_JUMBO+14, ioaddr + MaxFrameSize);
 
 	alloc_list (dev);
 
@@ -404,7 +417,7 @@
 
 	set_multicast (dev);
 	if (np->coalesce) {
-		writel (np->int_count | np->int_timeout << 16,
+		writel (np->rx_coalesce | np->rx_timeout << 16,
 			ioaddr + RxDMAIntCtrl);
 	}
 	/* Set RIO to poll every N*320nsec. */
@@ -441,13 +454,31 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
-	printk (KERN_WARNING "%s: Transmit timed out, TxStatus %4.4x.\n",
+	printk (KERN_INFO "%s: Tx timed out (%4.4x), is buffer full?\n",
 		dev->name, readl (ioaddr + TxStatus));
+	/* Free used tx skbuffs */
+	for (; np->cur_tx - np->old_tx > 0; np->old_tx++) {
+		int entry = np->old_tx % TX_RING_SIZE;
+		struct sk_buff *skb;
+
+		if (!(np->tx_ring[entry].status & TFDDone))
+			break;
+		skb = np->tx_skbuff[entry];
+		pci_unmap_single (np->pdev,
+				  np->tx_ring[entry].fraginfo,
+				  skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq (skb);
+		np->tx_skbuff[entry] = 0;
+	}
 	dev->if_port = 0;
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
-	if (!np->tx_full)
+	/* If the ring is no longer full, clear tx_full and 
+	   call netif_wake_queue() */
+	if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) {
+		np->tx_full = 0;
 		netif_wake_queue (dev);
+	}
 }
 
  /* allocate and initialize Tx and Rx descriptors */
@@ -465,16 +496,19 @@
 	/* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_skbuff[i] = 0;
-		np->tx_ring[i].status = 0;
+		np->tx_ring[i].status = cpu_to_le64 (TFDDone);
+		np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
+					      ((i+1)%TX_RING_SIZE) *
+					      sizeof (struct
+					      netdev_desc));
 	}
 
 	/* Initialize Rx descriptors */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
-							((i +
-							  1) % RX_RING_SIZE) *
-							sizeof (struct
-								netdev_desc));
+						((i + 1) % RX_RING_SIZE) *
+						sizeof (struct
+						netdev_desc));
 		np->rx_ring[i].status = 0;
 		np->rx_ring[i].fraginfo = 0;
 		np->rx_skbuff[i] = 0;
@@ -522,13 +556,12 @@
 	entry = np->cur_tx % TX_RING_SIZE;
 	np->tx_skbuff[entry] = skb;
 	txdesc = &np->tx_ring[entry];
-	txdesc->next_desc = 0;
 
 	/* Set TFDDone to avoid TxDMA gather this descriptor */
 	txdesc->status = cpu_to_le64 (TFDDone);
 	txdesc->status |=
 	    cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift));
-#ifdef TX_HW_CHECKSUM
+#if 0
 	if (skb->ip_summed == CHECKSUM_HW) {
 		txdesc->status |=
 		    cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
@@ -544,21 +577,13 @@
 
 	/* Send one packet each time at 10Mbps mode */
 	/* Tx coalescing loop do not exceed 8 */
-	if (entry % 0x08 == 0 || np->speed == 10)
+	if (entry % tx_coalesce == 0 || np->speed == 10)
 		txdesc->status |= cpu_to_le64 (TxIndicate);
 	txdesc->fraginfo = cpu_to_le64 (pci_map_single (np->pdev, skb->data,
 							skb->len,
 							PCI_DMA_TODEVICE));
 	txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48;
 
-	/* Chain the last descriptor's pointer to this one */
-	if (np->last_tx)
-		np->last_tx->next_desc = cpu_to_le64 (np->tx_ring_dma +
-						      entry *
-						      sizeof (struct
-							      netdev_desc));
-	np->last_tx = txdesc;
-
 	/* Clear TFDDone, then TxDMA start to send this descriptor */
 	txdesc->status &= ~cpu_to_le64 (TFDDone);
 
@@ -570,8 +595,10 @@
 	if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) {
 		/* do nothing */
 	} else {
+		spin_lock_irqsave(&np->lock, flags);
 		np->tx_full = 1;
 		netif_stop_queue (dev);
+		spin_unlock_irqrestore (&np->lock, flags);
 	}
 
 	/* The first TFDListPtr */
@@ -580,15 +607,15 @@
 			dev->base_addr + TFDListPtr0);
 		writel (0, dev->base_addr + TFDListPtr1);
 	}
-
-	spin_lock_irqsave (&np->lock, flags);
+	
 	if (np->old_tx > TX_RING_SIZE) {
+		spin_lock_irqsave (&np->lock, flags);
 		tx_shift = TX_RING_SIZE;
 		np->old_tx -= tx_shift;
 		np->cur_tx -= tx_shift;
+		spin_unlock_irqrestore (&np->lock, flags);
 	}
-	spin_unlock_irqrestore (&np->lock, flags);
-
+	
 	/* NETDEV WATCHDOG timer */
 	dev->trans_start = jiffies;
 	return 0;
@@ -605,33 +632,24 @@
 
 	ioaddr = dev->base_addr;
 	np = dev->priv;
-	spin_lock (&np->lock);
+	spin_lock(&np->lock);
 	while (1) {
-		int_status = readw (ioaddr + IntStatus) &
-		    (HostError | TxComplete | IntRequested |
-		     UpdateStats | LinkEvent | RxDMAComplete);
-		writew (int_status & (HostError | TxComplete | RxComplete |
-				      IntRequested | UpdateStats | LinkEvent |
-				      TxDMAComplete | RxDMAComplete | RFDListEnd
-				      | RxDMAPriority), ioaddr + IntStatus);
+		int_status = readw (ioaddr + IntStatus); 
+		writew (int_status, ioaddr + IntStatus);
+		int_status &= DEFAULT_INTR;
 		if (int_status == 0)
 			break;
 		/* Processing received packets */
 		if (int_status & RxDMAComplete)
 			receive_packet (dev);
 		/* TxComplete interrupt */
-		if (int_status & TxComplete || np->tx_full) {
-			int tx_status = readl (ioaddr + TxStatus);
+		if ((int_status & TxComplete) || np->tx_full) {
+			int tx_status;
+			tx_status = readl (ioaddr + TxStatus);
 			if (tx_status & 0x01)
 				tx_error (dev, tx_status);
-			/* Send one packet each time at 10Mbps mode */
-			if (np->speed == 10) {
-				np->tx_full = 0;
-				netif_wake_queue (dev);
-			}
-
 			/* Free used tx skbuffs */
-			for (; np->cur_tx - np->old_tx > 0; np->old_tx++) {
+			for (;np->cur_tx - np->old_tx > 0; np->old_tx++) {
 				int entry = np->old_tx % TX_RING_SIZE;
 				struct sk_buff *skb;
 
@@ -648,9 +666,12 @@
 		/* If the ring is no longer full, clear tx_full and 
 		   call netif_wake_queue() */
 		if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) {
-			np->tx_full = 0;
-			netif_wake_queue (dev);
+			if (np->speed != 10 || int_status & TxComplete) {
+				np->tx_full = 0;
+				netif_wake_queue (dev);
+			}
 		}
+
 		/* Handle uncommon events */
 		if (int_status &
 		    (IntRequested | HostError | LinkEvent | UpdateStats))
@@ -665,7 +686,7 @@
 			break;
 		}
 	}
-	spin_unlock (&np->lock);
+	spin_unlock(&np->lock);
 }
 
 static void
@@ -741,7 +762,7 @@
 		np->stats.collisions++;
 #endif
 
-	/* Restart the Tx. */
+	/* Restart the Tx */
 	writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
 }
 
@@ -782,7 +803,7 @@
 			if (frame_status & 0x00300000)
 				np->stats.rx_length_errors++;
 			if (frame_status & 0x00010000)
-				np->stats.rx_fifo_errors++;
+	 			np->stats.rx_fifo_errors++;
 			if (frame_status & 0x00060000)
 				np->stats.rx_frame_errors++;
 			if (frame_status & 0x00080000)
@@ -807,7 +828,7 @@
 				skb_put (skb, pkt_len);
 			}
 			skb->protocol = eth_type_trans (skb, dev);
-#ifdef RX_HW_CHECKSUM
+#if 0
 			/* Checksum done by hw, but csum value unavailable. */
 			if (!(frame_status & (TCPError | UDPError | IPError))) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -898,7 +919,7 @@
 	/* PCI Error, a catastronphic error related to the bus interface 
 	   occurs, set GlobalReset and HostReset to reset. */
 	if (int_status & HostError) {
-		printk (KERN_ERR "%s: PCI Error! IntStatus %4.4x.\n",
+		printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n",
 			dev->name, int_status);
 		writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2);
 		mdelay (500);
@@ -913,8 +934,8 @@
 	u16 temp1;
 	u16 temp2;
 	int i;
-	/* All statistics registers need to acknowledge,
-	   else overflow could cause some problem */
+	/* All statistics registers need to be acknowledged,
+	   else statistic overflow could cause problems */
 	np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
 	np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
 	np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
@@ -931,11 +952,11 @@
 	    readl (ioaddr + FramesWDeferredXmt) + temp2;
 
 	/* detailed rx_error */
-	np->stats.rx_length_errors += readw (ioaddr + InRangeLengthErrors) +
-	    readw (ioaddr + FrameTooLongErrors);
+	np->stats.rx_length_errors += readw (ioaddr + FrameTooLongErrors);
 	np->stats.rx_crc_errors += readw (ioaddr + FrameCheckSeqError);
 
 	/* Clear all other statistic register. */
+	readw (ioaddr + InRangeLengthErrors);
 	readw (ioaddr + MacControlFramesXmtd);
 	readw (ioaddr + BcstFramesXmtdOk);
 	readl (ioaddr + McstFramesXmtdOk);
@@ -960,7 +981,7 @@
 change_mtu (struct net_device *dev, int new_mtu)
 {
 	struct netdev_private *np = dev->priv;
-	int max = (np->jumbo) ? 9000 : 1536;
+	int max = (np->jumbo) ? MAX_JUMBO : 1536;
 
 	if ((new_mtu < 68) || (new_mtu > max)) {
 		return -EINVAL;
@@ -978,36 +999,42 @@
 	u32 hash_table[2];
 	u16 rx_mode = 0;
 	int i;
+	int bit;
+	int index, crc;
 	struct dev_mc_list *mclist;
 	struct netdev_private *np = dev->priv;
-
-	/* Default: receive broadcast and unicast */
-	rx_mode = ReceiveBroadcast | ReceiveUnicast;
+	
+	hash_table[0] = hash_table[1] = 0;
+	/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
+	hash_table[1] |= 0x02000000;
 	if (dev->flags & IFF_PROMISC) {
 		/* Receive all frames promiscuously. */
-		rx_mode |= ReceiveAllFrames;
-	} else if (((dev->flags & IFF_MULTICAST)
-		    && (dev->mc_count > multicast_filter_limit))
-		   || (dev->flags & IFF_ALLMULTI)) {
+		rx_mode = ReceiveAllFrames;
+	} else if ((dev->flags & IFF_ALLMULTI) || 
+			(dev->mc_count > multicast_filter_limit)) {
 		/* Receive broadcast and multicast frames */
-		rx_mode |= ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
-	} else if ((dev->flags & IFF_MULTICAST) & (dev->mc_count > 0)) {
-		/* Receive broadcast frames and multicast frames filtering by Hashtable */
-		rx_mode |=
+		rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
+	} else if (dev->mc_count > 0) {
+		/* Receive broadcast frames and multicast frames filtering 
+		   by Hashtable */
+		rx_mode =
 		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
+		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
+				i++, mclist=mclist->next) {
+			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+			for (index=0, bit=0; bit<6; bit++, crc<<=1) {
+				if (crc & 0x80000000) index |= 1 << bit;
+			}
+			hash_table[index / 32] |= (1 << (index % 32));
+		}
+	} else {
+		rx_mode = ReceiveBroadcast | ReceiveUnicast;
 	}
 	if (np->vlan) {
 		/* ReceiveVLANMatch field in ReceiveMode */
 		rx_mode |= ReceiveVLANMatch;
 	}
-	hash_table[0] = 0x00000000;
-	hash_table[1] = 0x00000000;
 
-	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-	     i++, mclist = mclist->next) {
-		set_bit (ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
-			 hash_table);
-	}
 	writel (hash_table[0], ioaddr + HashTable0);
 	writel (hash_table[1], ioaddr + HashTable1);
 	writew (rx_mode, ioaddr + ReceiveMode);
@@ -1677,8 +1704,9 @@
  
 Compile command: 
  
-gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2x.c
+gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c
 
 Read Documentation/networking/dl2k.txt for details.
 
 */
+
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 6255933..0ee3bbb 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -34,7 +34,7 @@
 #include <linux/spinlock.h>
 #include <linux/time.h>
 #define TX_RING_SIZE	128
-#define TX_QUEUE_LEN	96	/* Limit ring entries actually used.  */
+#define TX_QUEUE_LEN	120	/* Limit ring entries actually used.  */
 #define RX_RING_SIZE 	128
 #define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct netdev_desc)
 #define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct netdev_desc)
@@ -183,12 +183,12 @@
 
 /* Bits in the ReceiveMode register. */
 enum ReceiveMode_bits {
-	ReceiveIPMulticast = 0x0020,
-	ReceiveMulticastHash = 0x0010,
-	ReceiveAllFrames = 0x0008,
-	ReceiveBroadcast = 0x0004,
-	ReceiveMulticast = 0x0002,
 	ReceiveUnicast = 0x0001,
+	ReceiveMulticast = 0x0002,
+	ReceiveBroadcast = 0x0004,
+	ReceiveAllFrames = 0x0008,
+	ReceiveMulticastHash = 0x0010,
+	ReceiveIPMulticast = 0x0020,
 	ReceiveVLANMatch = 0x0100,
 	ReceiveVLANHash = 0x0200,
 };
@@ -650,20 +650,20 @@
 	struct pci_dev *pdev;
 	spinlock_t lock;
 	struct net_device_stats stats;
-	unsigned int rx_buf_sz;	/* Based on MTU+slack. */
-	unsigned int speed;	/* Operating speed */
-	unsigned int vlan;	/* VLAN Id */
-	unsigned int chip_id;	/* PCI table chip id */
-	unsigned int int_count; /* Maximum frames each RxDMAComplete intr */
-	unsigned int int_timeout; /* Wait time between RxDMAComplete intr */
-	unsigned int tx_full:1;	/* The Tx queue is full. */
+	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
+	unsigned int speed;		/* Operating speed */
+	unsigned int vlan;		/* VLAN Id */
+	unsigned int chip_id;		/* PCI table chip id */
+	unsigned int rx_coalesce; 	/* Maximum frames each RxDMAComplete intr */
+	unsigned int rx_timeout; 	/* Wait time between RxDMAComplete intr */
+	unsigned int tx_full:1;		/* The Tx queue is full. */
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
 	unsigned int an_enable:2;	/* Auto-Negotiated Enable */
 	unsigned int jumbo:1;		/* Jumbo frame enable */
 	unsigned int coalesce:1;	/* Rx coalescing enable */
 	unsigned int tx_flow:1;		/* Tx flow control enable */
 	unsigned int rx_flow:1;		/* Rx flow control enable */
-	unsigned int phy_media:1;	/* 1: fiber, 0: copper */ 
+	unsigned int phy_media:1;	/* 1: fiber, 0: copper */
 	struct netdev_desc *last_tx;	/* Last Tx descriptor used. */
 	unsigned long cur_rx, old_rx;	/* Producer/consumer ring indices */
 	unsigned long cur_tx, old_tx;
@@ -698,7 +698,12 @@
 MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
 #define TX_TIMEOUT  (4*HZ)
 #define PACKET_SIZE		1536
+#define MAX_JUMBO		8000
 #define RIO_IO_SIZE             340
+#define DEFAULT_RXC		5
+#define DEFAULT_RXT		750
+#define DEFAULT_TXC		1
+#define MAX_TXC			8
 #ifdef RIO_DEBUG
 #define DEBUG_TFD_DUMP(x) debug_tfd_dump(x)
 #define DEBUG_RFD_DUMP(x,flag) debug_rfd_dump(x,flag)
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 7c30e77..2805d9d 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -53,11 +53,18 @@
 	LK1.1.10:
 	* revert MII transceiver init change (jgarzik)
 
+	LK1.1.11:
+	* implement ETHTOOL_[GS]SET, _NWAY_RST, _[GS]MSGLVL, _GLINK (jgarzik)
+	* replace some MII-related magic numbers with constants
+
+	LK1.1.12:
+	* fix power-up sequence
+
 */
 
 #define DRV_NAME	"epic100"
-#define DRV_VERSION	"1.11+LK1.1.10"
-#define DRV_RELDATE	"July 6, 2001"
+#define DRV_VERSION	"1.11+LK1.1.12"
+#define DRV_RELDATE	"Jan 18, 2002"
 
 
 /* The user-configurable values.
@@ -318,12 +325,9 @@
 	/* Ring pointers. */
 	spinlock_t lock;				/* Group with Tx control cache line. */
 	unsigned int cur_tx, dirty_tx;
-	struct descriptor  *last_tx_desc;
 
 	unsigned int cur_rx, dirty_rx;
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
-	struct descriptor  *last_rx_desc;
-	long last_rx_time;					/* Last Rx, in jiffies. */
 
 	struct pci_dev *pci_dev;			/* PCI bus location. */
 	int chip_id, chip_flags;
@@ -335,13 +339,9 @@
 	signed char phys[4];				/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
 	int mii_phy_cnt;
+	struct mii_if_info mii;
 	unsigned int tx_full:1;				/* The Tx queue is full. */
-	unsigned int full_duplex:1;			/* Current duplex setting. */
-	unsigned int duplex_lock:1;			/* Duplex forced by the user. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
-	unsigned int media2:4;				/* Secondary monitored media port. */
-	unsigned int medialock:1;			/* Don't sense media type. */
-	unsigned int mediasense:1;			/* Media sensing in progress. */
 };
 
 static int epic_open(struct net_device *dev);
@@ -420,6 +420,9 @@
 
 	pci_set_drvdata(pdev, dev);
 	ep = dev->priv;
+	ep->mii.dev = dev;
+	ep->mii.mdio_read = mdio_read;
+	ep->mii.mdio_write = mdio_write;
 
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
@@ -481,7 +484,7 @@
 	{
 		int phy, phy_idx = 0;
 		for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				ep->phys[phy_idx++] = phy;
 				printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
@@ -492,16 +495,17 @@
 		ep->mii_phy_cnt = phy_idx;
 		if (phy_idx != 0) {
 			phy = ep->phys[0];
-			ep->advertising = mdio_read(dev, phy, 4);
+			ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 			printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
 				   "partner %4.4x.\n",
-				   pdev->slot_name, ep->advertising, mdio_read(dev, phy, 5));
+				   pdev->slot_name, ep->mii.advertising, mdio_read(dev, phy, 5));
 		} else if ( ! (ep->chip_flags & NO_MII)) {
 			printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
 			       pdev->slot_name);
 			/* Use the known PHY address of the EPII. */
 			ep->phys[0] = 3;
 		}
+		ep->mii.phy_id = ep->phys[0];
 	}
 
 	/* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
@@ -511,13 +515,11 @@
 
 	/* The lower four bits are the media type. */
 	if (duplex) {
-		ep->duplex_lock = ep->full_duplex = 1;
+		ep->mii.duplex_lock = ep->mii.full_duplex = 1;
 		printk(KERN_INFO DRV_NAME "(%s):  Forced full duplex operation requested.\n",
 		       pdev->slot_name);
 	}
 	dev->if_port = ep->default_port = option;
-	if (ep->default_port)
-		ep->medialock = 1;
 
 	/* The Epic-specific entries in the device structure. */
 	dev->open = &epic_open;
@@ -676,9 +678,8 @@
 	   required by the details of which bits are reset and the transceiver
 	   wiring on the Ositech CardBus card.
 	*/
-#if 0
-	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
-#endif
+
+	outl(0x12, ioaddr + MIICfg);
 	if (ep->chip_flags & MII_PWRDWN)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 
@@ -700,29 +701,29 @@
 
 	if (media2miictl[dev->if_port & 15]) {
 		if (ep->mii_phy_cnt)
-			mdio_write(dev, ep->phys[0], 0, media2miictl[dev->if_port&15]);
+			mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]);
 		if (dev->if_port == 1) {
 			if (debug > 1)
 				printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
 					   "status %4.4x.\n",
-					   dev->name, mdio_read(dev, ep->phys[0], 1));
+					   dev->name, mdio_read(dev, ep->phys[0], MII_BMSR));
 		}
 	} else {
-		int mii_reg5 = mdio_read(dev, ep->phys[0], 5);
-		if (mii_reg5 != 0xffff) {
-			if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040)
-				ep->full_duplex = 1;
-			else if (! (mii_reg5 & 0x4000))
-				mdio_write(dev, ep->phys[0], 0, 0x1200);
+		int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA);
+		if (mii_lpa != 0xffff) {
+			if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL)
+				ep->mii.full_duplex = 1;
+			else if (! (mii_lpa & LPA_LPACK))
+				mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
 			if (debug > 1)
 				printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
 					   " register read of %4.4x.\n", dev->name,
-					   ep->full_duplex ? "full" : "half",
-					   ep->phys[0], mii_reg5);
+					   ep->mii.full_duplex ? "full" : "half",
+					   ep->phys[0], mii_lpa);
 		}
 	}
 
-	outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+	outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
 	outl(ep->rx_ring_dma, ioaddr + PRxCDAR);
 	outl(ep->tx_ring_dma, ioaddr + PTxCDAR);
 
@@ -742,7 +743,7 @@
 		printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
 			   "%s-duplex.\n",
 			   dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL),
-			   ep->full_duplex ? "full" : "half");
+			   ep->mii.full_duplex ? "full" : "half");
 
 	/* Set the timer to switch to check for link beat and perhaps switch
 	   to an alternate media type. */
@@ -811,7 +812,7 @@
 
 	ep->tx_threshold = TX_FIFO_THRESH;
 	outl(ep->tx_threshold, ioaddr + TxThresh);
-	outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+	outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
 	outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)*
 		sizeof(struct epic_rx_desc), ioaddr + PRxCDAR);
 	outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)*
@@ -837,20 +838,20 @@
 {
 	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
-	int mii_reg5 = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], 5) : 0;
-	int negotiated = mii_reg5 & ep->advertising;
+	int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0;
+	int negotiated = mii_lpa & ep->mii.advertising;
 	int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 
-	if (ep->duplex_lock)
+	if (ep->mii.duplex_lock)
 		return;
-	if (mii_reg5 == 0xffff)		/* Bogus read */
+	if (mii_lpa == 0xffff)		/* Bogus read */
 		return;
-	if (ep->full_duplex != duplex) {
-		ep->full_duplex = duplex;
+	if (ep->mii.full_duplex != duplex) {
+		ep->mii.full_duplex = duplex;
 		printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
 			   " partner capability of %4.4x.\n", dev->name,
-			   ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
-		outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+			   ep->mii.full_duplex ? "full" : "half", ep->phys[0], mii_lpa);
+		outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
 	}
 }
 
@@ -914,7 +915,6 @@
 	ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 	ep->dirty_tx = ep->cur_tx = 0;
 	ep->cur_rx = ep->dirty_rx = 0;
-	ep->last_rx_time = jiffies;
 	ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
 
 	/* Initialize all Rx descriptors. */
@@ -1351,17 +1351,66 @@
 		return -EFAULT;
 
 	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strcpy (info.driver, DRV_NAME);
-			strcpy (info.version, DRV_VERSION);
-			strcpy (info.bus_info, np->pci_dev->slot_name);
-			if (copy_to_user (useraddr, &info, sizeof (info)))
-				return -EFAULT;
-			return 0;
-		}
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		strcpy (info.bus_info, np->pci_dev->slot_name);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&np->mii);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&np->mii);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
 	default:
 		break;
 	}
@@ -1380,12 +1429,10 @@
 		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = ep->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		if (! netif_running(dev)) {
 			outl(0x0200, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
@@ -1400,7 +1447,6 @@
 		return 0;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		if (! netif_running(dev)) {
@@ -1412,11 +1458,11 @@
 			switch (data->reg_num) {
 			case 0:
 				/* Check for autonegotiation on or reset. */
-				ep->duplex_lock = (value & 0x9000) ? 0 : 1;
-				if (ep->duplex_lock)
-					ep->full_duplex = (value & 0x0100) ? 1 : 0;
+				ep->mii.duplex_lock = (value & 0x9000) ? 0 : 1;
+				if (ep->mii.duplex_lock)
+					ep->mii.full_duplex = (value & 0x0100) ? 1 : 0;
 				break;
-			case 4: ep->advertising = value; break;
+			case 4: ep->mii.advertising = value; break;
 			}
 			/* Perhaps check_duplex(dev), depending on chip semantics. */
 		}
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 66bde2a..473e59d 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -15,8 +15,19 @@
 
 	Support information and updates available at
 	http://www.scyld.com/network/pci-skeleton.html
+
+	Linux kernel updates:
+
+	Version 2.51, Nov 17, 2001 (jgarzik):
+	- Add ethtool support
+	- Replace some MII-related magic numbers with constants
+
 */
 
+#define DRV_NAME	"fealnx"
+#define DRV_VERSION	"2.51"
+#define DRV_RELDATE	"Nov-17-2001"
+
 static int debug;		/* 1-> print debug message */
 static int max_interrupt_work = 20;
 
@@ -72,14 +83,16 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <linux/crc32.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO "fealnx.c:v2.50 1/17/2001\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "\n";
 
 
 /* This driver was written to use PCI memory space, however some x86 systems
@@ -380,6 +393,8 @@
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_ring_dma;
 
+	spinlock_t lock;
+
 	struct net_device_stats stats;
 
 	/* Media monitoring timer. */
@@ -404,19 +419,17 @@
 	unsigned int linkok;
 	unsigned int line_speed;
 	unsigned int duplexmode;
-	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
-	unsigned int duplex_lock:1;
-	unsigned int medialock:1;	/* Do not sense media. */
 	unsigned int default_port:4;	/* Last dev->if_port value. */
 	unsigned int PHYType;
 
 	/* MII transceiver section. */
 	int mii_cnt;		/* MII device addresses. */
 	unsigned char phys[2];	/* MII device addresses. */
+	struct mii_if_info mii;
 };
 
 
-static unsigned int mdio_read(struct net_device *dev, int phy_id, int location);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int netdev_open(struct net_device *dev);
 static void getlinktype(struct net_device *dev);
@@ -539,9 +552,13 @@
 
 	/* Make certain the descriptor lists are aligned. */
 	np = dev->priv;
+	spin_lock_init(&np->lock);
 	np->pci_dev = pdev;
 	np->flags = skel_netdrv_tbl[chip_id].flags;
 	pci_set_drvdata(pdev, dev);
+	np->mii.dev = dev;
+	np->mii.mdio_read = mdio_read;
+	np->mii.mdio_write = mdio_write;
 
 	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space) {
@@ -606,6 +623,7 @@
 		else
 			np->PHYType = OtherPHY;
 	}
+	np->mii.phy_id = np->phys[0];
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -613,17 +631,14 @@
 	/* The lower four bits are the media type. */
 	if (option > 0) {
 		if (option & 0x200)
-			np->full_duplex = 1;
+			np->mii.full_duplex = 1;
 		np->default_port = option & 15;
-
-		if (np->default_port)
-			np->medialock = 1;
 	}
 
 	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-		np->full_duplex = full_duplex[card_idx];
+		np->mii.full_duplex = full_duplex[card_idx];
 
-	if (np->full_duplex) {
+	if (np->mii.full_duplex) {
 		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
 /* 89/6/13 add, (begin) */
 //      if (np->PHYType==MarvellPHY)
@@ -636,10 +651,10 @@
 		}
 /* 89/6/13 add, (end) */
 		if (np->flags == HAS_MII_XCVR)
-			mdio_write(dev, np->phys[0], 4, 0x141);
+			mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
 		else
-			writel(0x141, dev->base_addr + ANARANLPAR);
-		np->duplex_lock = 1;
+			writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
+		np->mii.duplex_lock = 1;
 	}
 
 	/* The chip-specific entries in the device structure. */
@@ -787,7 +802,7 @@
 }
 
 
-static unsigned int mdio_read(struct net_device *dev, int phyad, int regad)
+static int mdio_read(struct net_device *dev, int phyad, int regad)
 {
 	long miiport = dev->base_addr + MANAGEMENT;
 	ulong miir;
@@ -821,7 +836,7 @@
 	miir &= ~MASK_MIIR_MII_MDC;
 	writel(miir, miiport);
 
-	return data;
+	return data & 0xffff;
 }
 
 
@@ -941,7 +956,7 @@
 // 89/9/1 modify,
 //   np->crvalue = 0x00e40001;    /* tx store and forward, tx/rx enable */
 	np->crvalue |= 0x00e40001;	/* tx store and forward, tx/rx enable */
-	np->full_duplex = np->duplex_lock;
+	np->mii.full_duplex = np->mii.duplex_lock;
 	getlinkstatus(dev);
 	if (np->linkok)
 		getlinktype(dev);
@@ -990,7 +1005,7 @@
 		}
 	} else {
 		for (i = 0; i < DelayTime; ++i) {
-			if (mdio_read(dev, np->phys[0], 1) & 0x4) {
+			if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) {
 				np->linkok = 1;
 				return;
 			}
@@ -1475,7 +1490,7 @@
 						np->stats.tx_window_errors++;
 					if (tx_status & UDF)
 						np->stats.tx_fifo_errors++;
-					if ((tx_status & HF) && np->full_duplex == 0)
+					if ((tx_status & HF) && np->mii.full_duplex == 0)
 						np->stats.tx_heartbeat_errors++;
 
 #ifdef ETHER_STATS
@@ -1751,24 +1766,100 @@
 	writel(np->crvalue, ioaddr + TCRRCR);
 }
 
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+	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_NAME);
+		strcpy (info.version, DRV_VERSION);
+		strcpy (info.bus_info, np->pci_dev->slot_name);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&np->mii);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&np->mii);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
 
 	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		return 0;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 0b3b5e2..45c3021 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1941,17 +1941,14 @@
 	case SIOCETHTOOL:
 		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		return 0;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		/* TODO: Check the sequencing of this.  Might need to stop and
 		 * restart Rx and Tx engines. -KDU
 		 */
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 78afc6a..bfed2a7 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -168,6 +168,10 @@
 	return r;
 }
 
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_DESCRIPTION ("MII hardware support library");
+MODULE_LICENSE("GPL");
+
 EXPORT_SYMBOL(mii_link_ok);
 EXPORT_SYMBOL(mii_nway_restart);
 EXPORT_SYMBOL(mii_ethtool_gset);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 8a11878..1016a21 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1,4 +1,4 @@
-#define VERSION "0.13"
+#define VERSION "0.14"
 /* ns83820.c by Benjamin LaHaise <bcrl@redhat.com>
  *
  * $Revision: 1.34.2.8 $
@@ -45,6 +45,7 @@
  *			0.12 - add statistics counters
  *			     - add allmulti/promisc support
  *	20011009	0.13 - hotplug support, other smaller pci api cleanups
+ *	20011117	0.14 - ethtool GDRVINFO, GLINK support
  *
  * Driver Overview
  * ===============
@@ -86,9 +87,11 @@
 #include <linux/in.h>	/* for IPPROTO_... */
 #include <linux/eeprom.h>
 #include <linux/compiler.h>
+#include <linux/ethtool.h>
 //#include <linux/skbrefill.h>
 
 #include <asm/io.h>
+#include <asm/uaccess.h>
 
 /* Dprintk is used for more interesting debug events */
 #undef Dprintk
@@ -1007,6 +1010,59 @@
 	return &dev->stats;
 }
 
+static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr)
+{
+	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, "ns83820");
+			strcpy (info.version, VERSION);
+			strcpy (info.bus_info, dev->pci_dev->slot_name);
+			if (copy_to_user (useraddr, &info, sizeof (info)))
+				return -EFAULT;
+			return 0;
+		}
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+
+		if (cfg & CFG_LNKSTS)
+			edata.data = 1;
+		else
+			edata.data = 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd)
+{
+	struct ns83820 *dev = _dev->priv;
+
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return ns83820_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct ns83820 *dev = data;
@@ -1294,6 +1350,7 @@
 	dev->net_dev.get_stats = ns83820_get_stats;
 	dev->net_dev.change_mtu = ns83820_change_mtu;
 	dev->net_dev.set_multicast_list = ns83820_set_multicast;
+	dev->net_dev.do_ioctl = ns83820_ioctl;
 	//FIXME: dev->net_dev.tx_timeout = ns83820_tx_timeout;
 
 	pci_set_drvdata(pci_dev, dev);
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 6743227..957b71b 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -834,7 +834,7 @@
 		printk (KERN_INFO
 			"%s: Media type forced to Full Duplex.\n",
 			dev->name);
-		mdio_write (dev, tp->phys[0], 4, 0x141);
+		mdio_write (dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
 		tp->duplex_lock = 1;
 	}
 
@@ -1235,20 +1235,20 @@
 	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int next_tick = 60 * HZ;
-	int mii_reg5;
+	int mii_lpa;
 
-	mii_reg5 = mdio_read (dev, tp->phys[0], 5);
+	mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
 
-	if (!tp->duplex_lock && mii_reg5 != 0xffff) {
-		int duplex = (mii_reg5 & 0x0100)
-		    || (mii_reg5 & 0x01C0) == 0x0040;
+	if (!tp->duplex_lock && mii_lpa != 0xffff) {
+		int duplex = (mii_lpa & LPA_100FULL)
+		    || (mii_lpa & 0x01C0) == 0x0040;
 		if (tp->full_duplex != duplex) {
 			tp->full_duplex = duplex;
 			printk (KERN_INFO
 				"%s: Setting %s-duplex based on MII #%d link"
 				" partner ability of %4.4x.\n", dev->name,
 				tp->full_duplex ? "full" : "half",
-				tp->phys[0], mii_reg5);
+				tp->phys[0], mii_lpa);
 			NETDRV_W8 (Cfg9346, Cfg9346_Unlock);
 			NETDRV_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
 			NETDRV_W8 (Cfg9346, Cfg9346_Lock);
@@ -1793,19 +1793,16 @@
 
 	switch (cmd) {
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = tp->phys[0] & 0x3f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		spin_lock_irqsave (&tp->lock, flags);
 		data->val_out = mdio_read (dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		spin_unlock_irqrestore (&tp->lock, flags);
 		break;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable (CAP_NET_ADMIN)) {
 			rc = -EPERM;
 			break;
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 2098eab..a782e5d 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -17,6 +17,9 @@
 
 ======================================================================*/
 
+#define DRV_NAME	"3c589_cs"
+#define DRV_VERSION	"1.162"
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -28,6 +31,9 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -134,7 +140,7 @@
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"3c589_cs.c 1.162 2001/10/13 00:08:50 (David Hinds)";
+DRV_NAME ".c " DRV_VERSION " 2001/10/13 00:08:50 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -159,6 +165,7 @@
 static int el3_close(struct net_device *dev);
 static void el3_tx_timeout(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
 static dev_info_t dev_info = "3c589_cs";
 
@@ -249,7 +256,8 @@
     dev->tx_timeout = el3_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
-    
+    dev->do_ioctl = netdev_ioctl;
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -640,6 +648,71 @@
 	 | AdapterFailure, ioaddr + EL3_CMD);
 }
 
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+#ifdef PCMCIA_DEBUG
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = pc_debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		pc_debug = edata.data;
+		return 0;
+	}
+#endif
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int rc;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+		break;
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+
 static int el3_config(struct net_device *dev, struct ifmap *map)
 {
     if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
diff --git a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c
index 4c26b7f..3b0195a 100644
--- a/drivers/net/pcmcia/aironet4500_cs.c
+++ b/drivers/net/pcmcia/aironet4500_cs.c
@@ -10,8 +10,11 @@
  *
  */
 
+#define DRV_NAME	"aironet4500_cs"
+#define DRV_VERSION	"0.1"
+
 static const char *awc_version =
-"aironet4500_cs.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n";
+DRV_NAME ".c v" DRV_VERSION " 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n";
 
 
 #include <linux/module.h>
@@ -24,6 +27,9 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -159,6 +165,66 @@
 	return ret;
 }
 
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+#ifdef PCMCIA_DEBUG
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = pc_debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		pc_debug = edata.data;
+		return 0;
+	}
+#endif
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int awc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
 /*
 	awc_attach() creates an "instance" of the driver, allocating
 	local data structures for one device.  The device is registered
@@ -230,7 +296,8 @@
 //	dev->set_config = 		&awc_config_misiganes,aga mitte awc_config;
 	dev->get_stats = 		&awc_get_stats;
 //	dev->set_multicast_list = 	&awc_set_multicast_list;
-
+	dev->do_ioctl =			&awc_ioctl;
+	
 	strcpy(dev->name, ((struct awc_private *)dev->priv)->node.dev_name);
 
 	ether_setup(dev);
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 6c47c37..95bc343 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -28,6 +28,9 @@
    
 ======================================================================*/
 
+#define DRV_NAME	"fmvj18x_cs"
+#define DRV_VERSION	"2.6"
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -39,6 +42,9 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -74,7 +80,7 @@
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version = "fmvj18x_cs.c 2.6 2001/09/17";
+static char *version = DRV_NAME ".c " DRV_VERSION " 2001/09/17";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -104,6 +110,7 @@
 static struct net_device_stats *fjn_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static void fjn_tx_timeout(struct net_device *dev);
+static int fjn_ioctl(struct net_device *, struct ifreq *, int);
 
 static dev_info_t dev_info = "fmvj18x_cs";
 static dev_link_t *dev_list;
@@ -316,6 +323,7 @@
     dev->tx_timeout = fjn_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
+    dev->do_ioctl = fjn_ioctl;
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -1103,6 +1111,65 @@
 
 /*====================================================================*/
 
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+#ifdef PCMCIA_DEBUG
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = pc_debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		pc_debug = edata.data;
+		return 0;
+	}
+#endif
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int fjn_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static int fjn_config(struct net_device *dev, struct ifmap *map){
     return 0;
 }
diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c
index 578af8d..81b9152 100644
--- a/drivers/net/pcmcia/xircom_tulip_cb.c
+++ b/drivers/net/pcmcia/xircom_tulip_cb.c
@@ -1472,21 +1472,18 @@
 
 	/* Legacy mii-diag interface */
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		if (tp->mii_cnt)
 			data[0] = phy;
 		else
 			return -ENODEV;
 		return 0;
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		save_flags(flags);
 		cli();
 		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
 		restore_flags(flags);
 		return 0;
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		save_flags(flags);
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 7b6186f..4bf23c2 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -483,7 +483,7 @@
 		 *      14 Oct 1994 Dmitry Gorodchanin.
 		 */
 #ifdef SL_CHECK_TRANSMIT
-		if (jiffies - dev->trans_start  < 20 * HZ)  {
+		if (time_before(jiffies, dev->trans_start + 20 * HZ))  {
 			/* 20 sec timeout not reached */
 			goto out;
 		}
@@ -1387,7 +1387,7 @@
 	int i;
 
 	if (slip_ctrls != NULL) {
-		unsigned long start = jiffies;
+		unsigned long timeout = jiffies + HZ;
 		int busy = 0;
 
 		/* First of all: check for active disciplines and hangup them.
@@ -1410,7 +1410,7 @@
 				spin_unlock(&slc->ctrl.lock);
 			}
 			local_bh_enable();
-		} while (busy && jiffies - start < 1*HZ);
+		} while (busy && time_before(jiffies, timeout));
 
 		busy = 0;
 		for (i = 0; i < slip_maxdev; i++) {
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 3d17fd6..5792033 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -93,13 +93,16 @@
 	- Fixed initialization timing problems
 	- Fixed interrupt mask definitions
 
+	LK1.3.5 (jgarzik)
+	- ethtool NWAY_RST, GLINK, [GS]MSGLVL support
+
 TODO:
 	- implement tx_timeout() properly
 */
 
 #define DRV_NAME	"starfire"
-#define DRV_VERSION	"1.03+LK1.3.4"
-#define DRV_RELDATE	"August 14, 2001"
+#define DRV_VERSION	"1.03+LK1.3.5"
+#define DRV_RELDATE	"November 17, 2001"
 
 #include <linux/version.h>
 #include <linux/module.h>
@@ -1767,6 +1770,47 @@
 		return 0;
 	}
 
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		int tmp;
+		int r = -EINVAL;
+		/* if autoneg is off, it's an error */
+		tmp = mdio_read(dev, np->phys[0], MII_BMCR);
+		if (tmp & BMCR_ANENABLE) {
+			tmp |= (BMCR_ANRESTART);
+			mdio_write(dev, np->phys[0], MII_BMCR, tmp);
+			r = 0;
+		}
+		return r;
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS)
+			edata.data = 1;
+		else
+			edata.data = 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -1784,17 +1828,14 @@
 
 	/* Legacy mii-diag interface */
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = np->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		return 0;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		if (data->phy_id == np->phys[0]) {
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 7321b34..510573b 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -21,11 +21,15 @@
 	Version 1.01a (jgarzik):
 	- Replace some MII-related magic numbers with constants
 
+	Version 1.02 (D-Link):
+	- Add new board to PCI ID list
+	- Fix multicast bug
+
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.01a"
-#define DRV_RELDATE	"11-Nov-2001"
+#define DRV_VERSION	"1.02"
+#define DRV_RELDATE	"17-Jan-2002"
 
 
 /* The user-configurable values.
@@ -223,8 +227,9 @@
 	{0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
 	{0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
 	{0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
-	{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
-	{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
+	{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -247,6 +252,8 @@
 	 PCI_IOTYPE, 128, CanHaveMII},
 	{"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,},
 	 PCI_IOTYPE, 128, CanHaveMII},
+	{"D-Link DFE-530TXS FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
+	 PCI_IOTYPE, 128, CanHaveMII},
 	{"D-Link DL10050-based FAST Ethernet Adapter",
 	 {0x10021186, 0xffffffff,},
 	 PCI_IOTYPE, 128, CanHaveMII},
@@ -1287,11 +1294,16 @@
 		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
 	} else if (dev->mc_count) {
 		struct dev_mc_list *mclist;
-		memset(mc_filter, 0, sizeof(mc_filter));
+		int bit;
+		int index;
+		int crc;
+		memset (mc_filter, 0, sizeof (mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			 i++, mclist = mclist->next) {
-			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
-					mc_filter);
+		     i++, mclist = mclist->next) {
+			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+			for (index=0, bit=0; bit < 6; bit++, crc <<= 1)
+				if (crc & 0x80000000) index |= 1 << bit;
+			mc_filter[index/16] |= (1 << (index % 16));
 		}
 		rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys;
 	} else {
@@ -1335,17 +1347,14 @@
 	case SIOCETHTOOL:
 		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		return 0;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 1246f43..59a9f0c 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -923,18 +923,15 @@
 
 	switch(cmd) {
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 			data->phy_id = phy;
 
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 			TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out);
 			return 0;
 		
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 0aed62e..3e7634e 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -76,8 +76,17 @@
 
 	LK1.1.12:
 	- Martin Eriksson: Allow Memory-Mapped IO to be enabled.
+
+	LK1.1.13 (jgarzik):
+	- Add ethtool support
+	- Replace some MII-related magic numbers with constants
+	
 */
 
+#define DRV_NAME	"via-rhine"
+#define DRV_VERSION	"1.1.13"
+#define DRV_RELDATE	"Nov-17-2001"
+
 
 /* A few user-configurable values.
    These may be modified when a driver module is loaded. */
@@ -151,18 +160,20 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <linux/crc32.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/uaccess.h>
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO "via-rhine.c:v1.10-LK1.1.12  03/11/2001  Written by Donald Becker\n"
+KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION "  " DRV_RELDATE "  Written by Donald Becker\n"
 KERN_INFO "  http://www.scyld.com/network/via-rhine.html\n";
 
-static char shortname[] __devinitdata = "via-rhine";
+static char shortname[] __devinitdata = DRV_NAME;
 
 
 /* This driver was written to use PCI memory space, however most versions
@@ -471,6 +482,7 @@
 	unsigned char phys[MAX_MII_CNT];			/* MII device addresses. */
 	unsigned int mii_cnt;			/* number of MIIs found, but only the first one is used */
 	u16 mii_status;						/* last read MII status */
+	struct mii_if_info mii_if;
 };
 
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
@@ -486,7 +498,7 @@
 static void via_rhine_error(struct net_device *dev, int intr_status);
 static void via_rhine_set_rx_mode(struct net_device *dev);
 static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  via_rhine_close(struct net_device *dev);
 static inline void clear_tally_counters(long ioaddr);
 
@@ -684,6 +696,9 @@
 	np->chip_id = chip_id;
 	np->drv_flags = via_rhine_chip_info[chip_id].drv_flags;
 	np->pdev = pdev;
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -691,16 +706,16 @@
 	/* The lower four bits are the media type. */
 	if (option > 0) {
 		if (option & 0x200)
-			np->full_duplex = 1;
+			np->mii_if.full_duplex = 1;
 		np->default_port = option & 15;
 	}
 	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
-	if (np->full_duplex) {
+	if (np->mii_if.full_duplex) {
 		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
 			   " disabled.\n", dev->name);
-		np->duplex_lock = 1;
+		np->mii_if.duplex_lock = 1;
 	}
 
 	/* The chip-specific entries in the device structure. */
@@ -709,7 +724,7 @@
 	dev->stop = via_rhine_close;
 	dev->get_stats = via_rhine_get_stats;
 	dev->set_multicast_list = via_rhine_set_rx_mode;
-	dev->do_ioctl = mii_ioctl;
+	dev->do_ioctl = via_rhine_ioctl;
 	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	if (np->drv_flags & ReqTxAlign)
@@ -736,10 +751,10 @@
 			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, 4);
+				np->mii_if.advertising = mdio_read(dev, phy, 4);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x Link %4.4x.\n",
-					   dev->name, phy, mii_status, np->advertising,
+					   dev->name, phy, mii_status, np->mii_if.advertising,
 					   mdio_read(dev, phy, 5));
 
 				/* set IFF_RUNNING */
@@ -750,12 +765,13 @@
 			}
 		}
 		np->mii_cnt = phy_idx;
+		np->mii_if.phy_id = np->phys[0];
 	}
 
 	/* Allow forcing the media type. */
 	if (option > 0) {
 		if (option & 0x220)
-			np->full_duplex = 1;
+			np->mii_if.full_duplex = 1;
 		np->default_port = option & 0x3ff;
 		if (np->default_port & 0x330) {
 			/* FIXME: shouldn't someone check this variable? */
@@ -969,7 +985,7 @@
 		   ioaddr + IntrEnable);
 
 	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
-	if (np->duplex_lock)
+	if (np->mii_if.duplex_lock)
 		np->chip_cmd |= CmdFDuplex;
 	writew(np->chip_cmd, ioaddr + ChipCmd);
 
@@ -1011,12 +1027,12 @@
 		switch (regnum) {
 		case 0:							/* Is user forcing speed/duplex? */
 			if (value & 0x9000)			/* Autonegotiation. */
-				np->duplex_lock = 0;
+				np->mii_if.duplex_lock = 0;
 			else
-				np->full_duplex = (value & 0x0100) ? 1 : 0;
+				np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0;
 			break;
 		case 4:
-			np->advertising = value;
+			np->mii_if.advertising = value;
 			break;
 		}
 	}
@@ -1060,7 +1076,7 @@
 		printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x "
 			   "MII status: %4.4x.\n",
 			   dev->name, readw(ioaddr + ChipCmd),
-			   mdio_read(dev, np->phys[0], 1));
+			   mdio_read(dev, np->phys[0], MII_BMSR));
 
 	netif_start_queue(dev);
 
@@ -1078,19 +1094,19 @@
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
-	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
-	int negotiated = mii_reg5 & np->advertising;
+	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
+	int negotiated = mii_lpa & np->mii_if.advertising;
 	int duplex;
 
-	if (np->duplex_lock  ||  mii_reg5 == 0xffff)
+	if (np->mii_if.duplex_lock  ||  mii_lpa == 0xffff)
 		return;
 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-	if (np->full_duplex != duplex) {
-		np->full_duplex = duplex;
+	if (np->mii_if.full_duplex != duplex) {
+		np->mii_if.full_duplex = duplex;
 		if (debug)
 			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
 				   " partner capability of %4.4x.\n", dev->name,
-				   duplex ? "full" : "half", np->phys[0], mii_reg5);
+				   duplex ? "full" : "half", np->phys[0], mii_lpa);
 		if (duplex)
 			np->chip_cmd |= CmdFDuplex;
 		else
@@ -1118,7 +1134,7 @@
 	via_rhine_check_duplex(dev);
 
 	/* make IFF_RUNNING follow the MII status bit "Link established" */
-	mii_status = mdio_read(dev, np->phys[0], 1);
+	mii_status = mdio_read(dev, np->phys[0], MII_BMSR);
 	if ( (mii_status & MIILink) != (np->mii_status & MIILink) ) {
 		if (mii_status & MIILink)
 			netif_carrier_on(dev);
@@ -1142,7 +1158,7 @@
 	printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
 		"%4.4x, resetting...\n",
 		dev->name, readw (ioaddr + IntrStatus),
-		mdio_read (dev, np->phys[0], 1));
+		mdio_read (dev, np->phys[0], MII_BMSR));
 
 	dev->if_port = 0;
 
@@ -1457,14 +1473,14 @@
 		if (readb(ioaddr + MIIStatus) & 0x02) {
 			/* Link failed, restart autonegotiation. */
 			if (np->drv_flags & HasDavicomPhy)
-				mdio_write(dev, np->phys[0], 0, 0x3300);
+				mdio_write(dev, np->phys[0], MII_BMCR, 0x3300);
 		} else
 			via_rhine_check_duplex(dev);
 		if (debug)
 			printk(KERN_ERR "%s: MII status changed: Autonegotiation "
 				   "advertising %4.4x  partner %4.4x.\n", dev->name,
-			   mdio_read(dev, np->phys[0], 4),
-			   mdio_read(dev, np->phys[0], 5));
+			   mdio_read(dev, np->phys[0], MII_ADVERTISE),
+			   mdio_read(dev, np->phys[0], MII_LPA));
 	}
 	if (intr_status & IntrStatsMax) {
 		np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
@@ -1554,29 +1570,112 @@
 	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
 }
 
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int via_rhine_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+	u32 ethcmd;
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		strcpy (info.bus_info, np->pdev->slot_name);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		if (!(np->drv_flags & CanHaveMII))
+			break;
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (!(np->drv_flags & CanHaveMII))
+			break;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		if (!(np->drv_flags & CanHaveMII))
+			break;
+		return mii_nway_restart(&np->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		if (!(np->drv_flags & CanHaveMII))
+			break;
+		edata.data = mii_link_ok(&np->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
 	unsigned long flags;
 	int retval;
 
+	if (cmd == SIOCETHTOOL)
+		return via_rhine_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
 	spin_lock_irqsave(&np->lock, flags);
 	retval = 0;
 
 	switch(cmd) {
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = np->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		break;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN)) {
 			retval = -EPERM;
 			break;
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 405d218..4812d84 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -175,7 +175,7 @@
 
     case LMCIOCSINFO: /*fold01*/
         sp = &((struct ppp_device *) dev)->sppp;
-        if (!suser ()) {
+        if (!capable(CAP_NET_ADMIN)) {
             ret = -EPERM;
             break;
         }
@@ -210,7 +210,7 @@
             u_int16_t	old_type = sc->if_type;
             u_int16_t	new_type;
 
-	    if (!suser ()) {
+	    if (!capable(CAP_NET_ADMIN)) {
 		ret = -EPERM;
 		break;
 	    }
@@ -290,7 +290,7 @@
         break;
 
     case LMCIOCCLEARLMCSTATS: /*fold01*/
-        if (!suser ()){
+        if (!capable(CAP_NET_ADMIN)){
             ret = -EPERM;
             break;
         }
@@ -304,7 +304,7 @@
         break;
 
     case LMCIOCSETCIRCUIT: /*fold01*/
-        if (!suser ()){
+        if (!capable(CAP_NET_ADMIN)){
             ret = -EPERM;
             break;
         }
@@ -322,7 +322,7 @@
         break;
 
     case LMCIOCRESET: /*fold01*/
-        if (!suser ()){
+        if (!capable(CAP_NET_ADMIN)){
             ret = -EPERM;
             break;
         }
@@ -355,7 +355,7 @@
         {
             struct lmc_xilinx_control xc; /*fold02*/
 
-            if (!suser ()){
+            if (!capable(CAP_NET_ADMIN)){
                 ret = -EPERM;
                 break;
             }
diff --git a/drivers/net/winbond-840.c b/drivers/net/winbond-840.c
index 92e1880..514b57d 100644
--- a/drivers/net/winbond-840.c
+++ b/drivers/net/winbond-840.c
@@ -36,6 +36,8 @@
 		power management.
 		support for big endian descriptors
 			Copyright (C) 2001 Manfred Spraul
+  	* ethtool support (jgarzik)
+	* Replace some MII-related magic numbers with constants (jgarzik)
   
 	TODO:
 	* enable pci_power_off
@@ -43,8 +45,8 @@
 */
   
 #define DRV_NAME	"winbond-840"
-#define DRV_VERSION	"1.01-c"
-#define DRV_RELDATE	"6/30/2000"
+#define DRV_VERSION	"1.01-d"
+#define DRV_RELDATE	"Nov-17-2001"
 
 
 /* Automatically extracted configuration info:
@@ -364,14 +366,11 @@
 	unsigned int cur_tx, dirty_tx;
 	unsigned int tx_q_bytes;
 	unsigned int tx_full;				/* The Tx queue is full. */
-	/* These values are keep track of the transceiver/media in use. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int duplex_lock:1;
 	/* MII transceiver section. */
 	int mii_cnt;						/* MII device addresses. */
-	u16 advertising;					/* NWay media advertisement */
 	unsigned char phys[MII_CNT];		/* MII device addresses, but only the first is used */
 	u32 mii;
+	struct mii_if_info mii_if;
 };
 
 static int  eeprom_read(long ioaddr, int location);
@@ -453,6 +452,9 @@
 	np->chip_id = chip_idx;
 	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
 	spin_lock_init(&np->lock);
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
 	
 	pci_set_drvdata(pdev, dev);
 
@@ -462,16 +464,16 @@
 	/* The lower four bits are the media type. */
 	if (option > 0) {
 		if (option & 0x200)
-			np->full_duplex = 1;
+			np->mii_if.full_duplex = 1;
 		if (option & 15)
 			printk(KERN_INFO "%s: ignoring user supplied media type %d",
 				dev->name, option & 15);
 	}
 	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
-	if (np->full_duplex)
-		np->duplex_lock = 1;
+	if (np->mii_if.full_duplex)
+		np->mii_if.duplex_lock = 1;
 
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
@@ -496,18 +498,19 @@
 	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, 4);
-				np->mii = (mdio_read(dev, phy, 2) << 16)+
-						mdio_read(dev, phy, 3);
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+
+						mdio_read(dev, phy, MII_PHYSID2);
 				printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, np->mii, phy, mii_status, np->advertising);
+					   dev->name, np->mii, phy, mii_status, np->mii_if.advertising);
 			}
 		}
 		np->mii_cnt = phy_idx;
+		np->mii_if.phy_id = np->phys[0];
 		if (phy_idx == 0) {
 				printk(KERN_WARNING "%s: MII PHY not found -- this device may "
 					   "not operate correctly.\n", dev->name);
@@ -654,7 +657,7 @@
 	int i;
 
 	if (location == 4  &&  phy_id == np->phys[0])
-		np->advertising = value;
+		np->mii_if.advertising = value;
 
 	if (mii_preamble_required)
 		mdio_sync(mdio_addr);
@@ -728,12 +731,12 @@
 	int duplex, fasteth, result, mii_reg;
 
 	/* BSMR */
-	mii_reg = mdio_read(dev, np->phys[0], 1);
+	mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
 
 	if (mii_reg == 0xffff)
 		return np->csr6;
 	/* reread: the link status bit is sticky */
-	mii_reg = mdio_read(dev, np->phys[0], 1);
+	mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
 	if (!(mii_reg & 0x4)) {
 		if (netif_carrier_ok(dev)) {
 			if (debug)
@@ -759,18 +762,18 @@
 		 * Instead bit 9 and 13 of the BMCR are updated to the result
 		 * of the negotiation..
 		 */
-		mii_reg = mdio_read(dev, np->phys[0], 0);
-		duplex = mii_reg & 0x100;
-		fasteth = mii_reg & 0x2000;
+		mii_reg = mdio_read(dev, np->phys[0], MII_BMCR);
+		duplex = mii_reg & BMCR_FULLDPLX;
+		fasteth = mii_reg & BMCR_SPEED100;
 	} else {
 		int negotiated;
-		mii_reg	= mdio_read(dev, np->phys[0], 5);
-		negotiated = mii_reg & np->advertising;
+		mii_reg	= mdio_read(dev, np->phys[0], MII_LPA);
+		negotiated = mii_reg & np->mii_if.advertising;
 
-		duplex = (negotiated & 0x0100) || ((negotiated & 0x02C0) == 0x0040);
+		duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
 		fasteth = negotiated & 0x380;
 	}
-	duplex |= np->duplex_lock;
+	duplex |= np->mii_if.duplex_lock;
 	/* remove fastether and fullduplex */
 	result = np->csr6 & ~0x20000200;
 	if (duplex)
@@ -822,7 +825,7 @@
 	/* and restart them with the new configuration */
 	writel(np->csr6, ioaddr + NetworkConfig);
 	if (new & 0x200)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 }
 
 static void netdev_timer(unsigned long data)
@@ -1131,7 +1134,7 @@
 			if (tx_status & 0x0C80) np->stats.tx_carrier_errors++;
 			if (tx_status & 0x0200) np->stats.tx_window_errors++;
 			if (tx_status & 0x0002) np->stats.tx_fifo_errors++;
-			if ((tx_status & 0x0080) && np->full_duplex == 0)
+			if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0)
 				np->stats.tx_heartbeat_errors++;
 #ifdef ETHER_STATS
 			if (tx_status & 0x0100) np->stats.collisions16++;
@@ -1469,6 +1472,56 @@
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&np->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&np->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
         }
 	
 	return -EOPNOTSUPP;
@@ -1483,19 +1536,16 @@
 	case SIOCETHTOOL:
 		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		spin_lock_irq(&np->lock);
 		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		spin_unlock_irq(&np->lock);
 		return 0;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		spin_lock_irq(&np->lock);
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index e56ab05..be17f0b 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1420,17 +1420,14 @@
 	case SIOCETHTOOL:
 		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = np->phys[0] & 0x1f;
 		/* Fall Through */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
 		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		return 0;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		if (data->phy_id == np->phys[0]) {
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index 82ed633..6d150d9 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -1338,7 +1338,7 @@
 		spin_unlock_irqrestore(&kbd_queue_lock, flags);
 
 #ifdef CONFIG_SPARC32_COMPAT
-		if (current->thread.flags & SPARC_FLAG_32BIT) {
+		if (test_thread_flag(TIF_32BIT)) {
 			if (copy_to_user((Firm_event *)p, &this_event,
 					 sizeof(Firm_event)-sizeof(struct timeval)))
 				return -EFAULT;
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c
index 8bb45cb..c006a52 100644
--- a/drivers/sbus/char/sunmouse.c
+++ b/drivers/sbus/char/sunmouse.c
@@ -462,7 +462,7 @@
 			spin_unlock_irqrestore(&sunmouse.lock, flags);
 
 #ifdef CONFIG_SPARC32_COMPAT
-			if (current->thread.flags & SPARC_FLAG_32BIT) {
+			if (test_thread_flag(TIF_32BIT)) {
 				if ((end - p) <
 				    ((sizeof(Firm_event) - sizeof(struct timeval) +
 				      (sizeof(u32) * 2))))
diff --git a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c
index 6ee303a..e661825 100644
--- a/drivers/usb/hcd/ehci-hcd.c
+++ b/drivers/usb/hcd/ehci-hcd.c
@@ -277,7 +277,7 @@
 	 */
 	usb_connect (udev);
 	udev->speed = USB_SPEED_HIGH;
-	if (usb_new_device (udev) != 0) {
+	if (usb_register_root_hub (udev, &ehci->hcd.pdev->dev) != 0) {
 		if (hcd->state == USB_STATE_RUNNING)
 			ehci_ready (ehci);
 		while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
diff --git a/drivers/usb/hcd/ohci-hcd.c b/drivers/usb/hcd/ohci-hcd.c
index 4857630..9dbceb3 100644
--- a/drivers/usb/hcd/ohci-hcd.c
+++ b/drivers/usb/hcd/ohci-hcd.c
@@ -469,7 +469,7 @@
 
 	usb_connect (udev);
 	udev->speed = USB_SPEED_FULL;
-	if (usb_new_device (udev) != 0) {
+	if (usb_register_root_hub (udev, &ohci->hcd.pdev->dev) != 0) {
 		usb_free_dev (udev); 
 		ohci->disabled = 1;
 // FIXME cleanup
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 23eb747..c545bd8 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -721,6 +721,20 @@
 		info("new USB device on bus %d path %s, assigned address %d",
 			dev->bus->busnum, dev->devpath, dev->devnum);
 
+		/* put the device in the global device tree */
+		dev->dev.parent = &dev->parent->dev;
+		sprintf (&dev->dev.name[0], "USB device %04x:%04x",
+			 dev->descriptor.idVendor,
+			 dev->descriptor.idProduct);
+		/* find the number of the port this device is connected to */
+		sprintf (&dev->dev.bus_id[0], "unknown_port_%03d", dev->devnum);
+		for (i = 0; i < USB_MAXCHILDREN; ++i) {
+			if (dev->parent->children[i] == dev) {
+				sprintf (&dev->dev.bus_id[0], "%02d", i);
+				break;
+			}
+		}
+
 		/* Run it through the hoops (find a driver, etc) */
 		if (!usb_new_device(dev))
 			goto done;
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index de765d9..e668cf3 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -2842,7 +2842,7 @@
 
 	usb_connect(uhci->rh.dev);
 
-	if (usb_new_device(uhci->rh.dev) != 0) {
+	if (usb_register_root_hub(uhci->rh.dev, &dev->dev) != 0) {
 		err("unable to start root hub");
 		retval = -ENOMEM;
 		goto err_start_root_hub;
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 94f84ed..29384b4 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -2231,7 +2231,7 @@
 	dev = usb_to_ohci (usb_dev);
 	ohci->bus->root_hub = usb_dev;
 	usb_connect (usb_dev);
-	if (usb_new_device (usb_dev) != 0) {
+	if (usb_register_root_hub (usb_dev, &ohci->ohci_dev->dev) != 0) {
 		usb_free_dev (usb_dev); 
 		ohci->disabled = 1;
 		return -ENODEV;
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 83d38a9..6d332d3 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -2904,7 +2904,7 @@
 	s->bus->root_hub = usb_dev;
 	usb_connect (usb_dev);
 
-	if (usb_new_device (usb_dev) != 0) {
+	if (usb_register_root_hub (usb_dev, &s->uhci_pci->dev) != 0) {
 		usb_free_dev (usb_dev);
 		return -1;
 	}
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index e94daf9..be9fa8a 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -980,8 +980,16 @@
 	unsigned claimed = 0;
 
 	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
+		struct usb_interface *interface = &dev->actconfig->interface[ifnum];
+		
+		/* register this interface with driverfs */
+		interface->dev.parent = &dev->dev;
+		sprintf (&interface->dev.bus_id[0], "%03d", ifnum);
+		sprintf (&interface->dev.name[0], "figure out some name...");
+		device_register (&interface->dev);
+
 		/* if this interface hasn't already been claimed */
-		if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) {
+		if (!usb_interface_claimed(interface)) {
 			if (usb_find_interface_driver(dev, ifnum))
 				rejected++;
 			else
@@ -1969,8 +1977,10 @@
 				if (driver->owner)
 					__MOD_DEC_USE_COUNT(driver->owner);
 				/* if driver->disconnect didn't release the interface */
-				if (interface->driver)
+				if (interface->driver) {
+					put_device (&interface->dev);
 					usb_driver_release_interface(driver, interface);
+				}
 			}
 		}
 	}
@@ -1989,6 +1999,7 @@
 	if (dev->devnum > 0) {
 		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
 		usbfs_remove_device(dev);
+		put_device(&dev->dev);
 	}
 
 	/* Free up the device itself */
@@ -2715,6 +2726,11 @@
 		usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
 #endif
 
+	/* register this device in the driverfs tree */
+	err = device_register (&dev->dev);
+	if (err)
+		return err;
+
 	/* now that the basic setup is over, add a /proc/bus/usb entry */
 	usbfs_add_device(dev);
 
@@ -2727,6 +2743,29 @@
 	return 0;
 }
 
+/**
+ * usb_register_root_hub - called by a usb host controller to register the root hub device in the system
+ * @usb_dev: the usb root hub device to be registered.
+ * @parent_dev: the parent device of this root hub.
+ *
+ * The USB host controller calls this function to register the root hub
+ * properly with the USB subsystem.  It sets up the device properly in
+ * the driverfs tree, and then calls usb_new_device() to register the
+ * usb device.
+ */
+int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
+{
+	int retval;
+
+	usb_dev->dev.parent = parent_dev;
+	strcpy (&usb_dev->dev.name[0], "usb_name");
+	strcpy (&usb_dev->dev.bus_id[0], "usb_bus");
+	retval = usb_new_device (usb_dev);
+	if (retval)
+		put_device (&usb_dev->dev);
+	return retval;
+}
+
 static int usb_open(struct inode * inode, struct file * file)
 {
 	int minor = minor(inode->i_rdev);
@@ -2832,6 +2871,7 @@
 EXPORT_SYMBOL(usb_free_bus);
 EXPORT_SYMBOL(usb_register_bus);
 EXPORT_SYMBOL(usb_deregister_bus);
+EXPORT_SYMBOL(usb_register_root_hub);
 EXPORT_SYMBOL(usb_alloc_dev);
 EXPORT_SYMBOL(usb_free_dev);
 EXPORT_SYMBOL(usb_inc_dev_use);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 350a648..256a285 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -33,7 +33,6 @@
 #include <linux/coda_cache.h>
 
 /* VFS super_block ops */
-static struct super_block *coda_read_super(struct super_block *, void *, int);
 static void coda_read_inode(struct inode *);
 static void coda_clear_inode(struct inode *);
 static void coda_put_super(struct super_block *);
@@ -140,8 +139,7 @@
 	return idx;
 }
 
-static struct super_block * coda_read_super(struct super_block *sb, 
-					    void *data, int silent)
+static int coda_fill_super(struct super_block *sb, void *data, int silent)
 {
         struct inode *root = 0; 
 	struct coda_sb_info *sbi = NULL;
@@ -161,17 +159,17 @@
 	vc = &coda_comms[idx];
 	if (!vc->vc_inuse) {
 		printk("coda_read_super: No pseudo device\n");
-		return NULL;
+		return -EINVAL;
 	}
 
         if ( vc->vc_sb ) {
 		printk("coda_read_super: Device already mounted\n");
-		return NULL;
+		return -EBUSY;
 	}
 
 	sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
 	if(!sbi) {
-		return NULL;
+		return -ENOMEM;
 	}
 
 	vc->vc_sb = sb;
@@ -192,7 +190,7 @@
 	        printk("coda_read_super: coda_get_rootfid failed with %d\n",
 		       error);
 		goto error;
-	}	  
+	}
 	printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
 	
 	/* make root inode */
@@ -205,7 +203,7 @@
 	printk("coda_read_super: rootinode is %ld dev %x\n", 
 	       root->i_ino, kdev_val(root->i_dev));
 	sb->s_root = d_alloc_root(root);
-        return sb;
+        return 0;
 
  error:
 	if (sbi) {
@@ -216,7 +214,7 @@
 	if (root)
                 iput(root);
 
-        return NULL;
+        return -EINVAL;
 }
 
 static void coda_put_super(struct super_block *sb)
@@ -313,5 +311,14 @@
 
 /* init_coda: used by filesystems.c to register coda */
 
-DECLARE_FSTYPE( coda_fs_type, "coda", coda_read_super, 0);
+static struct super_block *coda_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, coda_fill_super);
+}
 
+struct file_system_type coda_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"coda",
+	get_sb:		coda_get_sb,
+};
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 3b7e37e..dd3eef4 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -304,7 +304,7 @@
 	 * Wait for the lockd process to exit, but since we're holding
 	 * the lockd semaphore, we can't wait around forever ...
 	 */
-	current->work.sigpending = 0;
+	clear_thread_flag(TIF_SIGPENDING);
 	interruptible_sleep_on_timeout(&lockd_exit, HZ);
 	if (nlmsvc_pid) {
 		printk(KERN_WARNING 
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 1b4886e..be82172 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -163,8 +163,7 @@
 	return 0;
 }
 
-static struct super_block *minix_read_super(struct super_block *s, void *data,
-				     int silent)
+static int minix_fill_super(struct super_block *s, void *data, int silent)
 {
 	struct buffer_head *bh;
 	struct buffer_head **map;
@@ -273,7 +272,7 @@
  	else if (sbi->s_mount_state & MINIX_ERROR_FS)
 		printk ("MINIX-fs: mounting file system with errors, "
 			"running fsck is recommended.\n");
-	return s;
+	return 0;
 
 out_iput:
 	iput(root_inode);
@@ -314,7 +313,7 @@
 out_bad_sb:
 	printk("MINIX-fs: unable to read superblock\n");
  out:
-	return NULL;
+	return -EINVAL;
 }
 
 static int minix_statfs(struct super_block *sb, struct statfs *buf)
@@ -558,7 +557,18 @@
 		V2_minix_truncate(inode);
 }
 
-static DECLARE_FSTYPE_DEV(minix_fs_type,"minix",minix_read_super);
+static struct super_block *minix_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super);
+}
+
+static struct file_system_type minix_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"minix",
+	get_sb:		minix_get_sb,
+	fs_flags:	FS_REQUIRES_DEV,
+};
 
 static int __init init_minix_fs(void)
 {
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index e4ed042..4e79dcb 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -300,8 +300,7 @@
 	clear_inode(inode);
 }
 
-struct super_block *
-ncp_read_super(struct super_block *sb, void *raw_data, int silent)
+static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
 {
 	struct ncp_mount_data_kernel data;
 	struct ncp_server *server;
@@ -434,7 +433,7 @@
 	ncp_unlock_server(server);
 	if (error < 0)
 		goto out_no_connect;
-	DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
+	DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
 
 #ifdef CONFIG_NCPFS_PACKET_SIGNING
 	if (ncp_negotiate_size_and_options(server, default_bufsize,
@@ -486,31 +485,31 @@
         root_inode = ncp_iget(sb, &finfo);
         if (!root_inode)
 		goto out_no_root;
-	DPRINTK("ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
+	DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
 	sb->s_root = d_alloc_root(root_inode);
         if (!sb->s_root)
 		goto out_no_root;
 	sb->s_root->d_op = &ncp_dentry_operations;
-	return sb;
+	return 0;
 
 out_no_root:
-	printk(KERN_ERR "ncp_read_super: get root inode failed\n");
+	printk(KERN_ERR "ncp_fill_super: get root inode failed\n");
 	iput(root_inode);
 	goto out_disconnect;
 out_no_bufsize:
-	printk(KERN_ERR "ncp_read_super: could not get bufsize\n");
+	printk(KERN_ERR "ncp_fill_super: could not get bufsize\n");
 out_disconnect:
 	ncp_lock_server(server);
 	ncp_disconnect(server);
 	ncp_unlock_server(server);
 	goto out_free_packet;
 out_no_connect:
-	printk(KERN_ERR "ncp_read_super: Failed connection, error=%d\n", error);
+	printk(KERN_ERR "ncp_fill_super: Failed connection, error=%d\n", error);
 out_free_packet:
 	vfree(server->packet);
 	goto out_free_server;
 out_no_packet:
-	printk(KERN_ERR "ncp_read_super: could not alloc packet\n");
+	printk(KERN_ERR "ncp_fill_super: could not alloc packet\n");
 out_free_server:
 #ifdef CONFIG_NCPFS_NLS
 	unload_nls(server->nls_io);
@@ -527,16 +526,16 @@
 out_bad_file2:
 	fput(ncp_filp);
 out_bad_file:
-	printk(KERN_ERR "ncp_read_super: invalid ncp socket\n");
+	printk(KERN_ERR "ncp_fill_super: invalid ncp socket\n");
 	goto out;
 out_bad_mount:
-	printk(KERN_INFO "ncp_read_super: kernel requires mount version %d\n",
+	printk(KERN_INFO "ncp_fill_super: kernel requires mount version %d\n",
 		NCP_MOUNT_VERSION);
 	goto out;
 out_no_data:
-	printk(KERN_ERR "ncp_read_super: missing data argument\n");
+	printk(KERN_ERR "ncp_fill_super: missing data argument\n");
 out:
-	return NULL;
+	return -EINVAL;
 }
 
 static void ncp_put_super(struct super_block *sb)
@@ -750,7 +749,17 @@
 int ncp_current_malloced;
 #endif
 
-static DECLARE_FSTYPE(ncp_fs_type, "ncpfs", ncp_read_super, 0);
+static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, ncp_fill_super);
+}
+
+static struct file_system_type ncp_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"ncpfs",
+	get_sb:		ncp_get_sb,
+};
 
 static int __init init_ncp_fs(void)
 {
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 7bb3338..a4a6d4c 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -468,7 +468,7 @@
 		return 0;
 	}
 
-	current->work.sigpending = 0;
+	clear_thread_flag(TIF_SIGPENDING);
 	want_lock++;
 	while (hash_count || hash_lock) {
 		interruptible_sleep_on(&hash_wait);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index d0fbb66..08993e3 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -391,7 +391,7 @@
 		task->nswap,
 		task->cnswap,
 		task->exit_signal,
-		task->cpu);
+		task->thread_info->cpu);
 	if(mm)
 		mmput(mm);
 	return res;
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 61727bc..688ba2d 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -460,8 +460,7 @@
 	}
 }
 
-struct super_block *
-smb_read_super(struct super_block *sb, void *raw_data, int silent)
+int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
 {
 	struct smb_sb_info *server = &sb->u.smbfs_sb;
 	struct smb_mount_data_kernel *mnt;
@@ -561,7 +560,7 @@
 		goto out_no_root;
 	smb_new_dentry(sb->s_root);
 
-	return sb;
+	return 0;
 
 out_no_root:
 	iput(root_inode);
@@ -573,15 +572,15 @@
 	smb_vfree(server->packet);
 out_no_mem:
 	if (!server->mnt)
-		printk(KERN_ERR "smb_read_super: allocation failure\n");
+		printk(KERN_ERR "smb_fill_super: allocation failure\n");
 	goto out_fail;
 out_wrong_data:
 	printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
 	goto out_fail;
 out_no_data:
-	printk(KERN_ERR "smb_read_super: missing data argument\n");
+	printk(KERN_ERR "smb_fill_super: missing data argument\n");
 out_fail:
-	return NULL;
+	return -EINVAL;
 }
 
 static int
@@ -706,7 +705,17 @@
 int smb_current_vmalloced;
 #endif
 
-static DECLARE_FSTYPE( smb_fs_type, "smbfs", smb_read_super, 0);
+static struct super_block *smb_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_nodev(fs_type, flags, data, smb_fill_super);
+}
+
+static struct file_system_type smb_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"smbfs",
+	get_sb:		smb_get_sb,
+};
 
 static int __init init_smb_fs(void)
 {
diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h
index 65b1871..1f24042 100644
--- a/fs/smbfs/proto.h
+++ b/fs/smbfs/proto.h
@@ -53,7 +53,6 @@
 extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr);
 extern void smb_invalidate_inodes(struct smb_sb_info *server);
 extern int smb_revalidate_inode(struct dentry *dentry);
-extern struct super_block *smb_read_super(struct super_block *sb, void *raw_data, int silent);
 extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
 /* file.c */
 extern struct address_space_operations smb_file_aops;
diff --git a/fs/super.c b/fs/super.c
index f9f6a98..2a4cb32 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -797,11 +797,6 @@
 {
 	return get_sb_bdev(fs_type, flags, dev_name, data, fill_super);
 }
-static struct super_block *__get_sb_nodev(struct file_system_type *fs_type,
-	int flags, char *dev_name, void * data)
-{
-	return get_sb_nodev(fs_type, flags, data, fill_super);
-}
 
 struct vfsmount *
 do_kern_mount(const char *fstype, int flags, char *name, void *data)
@@ -820,8 +815,6 @@
 		sb = type->get_sb(type, flags, name, data);
 	else if (type->fs_flags & FS_REQUIRES_DEV)
 		sb = __get_sb_bdev(type, flags, name, data);
-	else
-		sb = __get_sb_nodev(type, flags, name, data);
 	if (IS_ERR(sb))
 		goto out_mnt;
 	if (type->fs_flags & FS_NOMOUNT)
diff --git a/fs/sysv/ChangeLog b/fs/sysv/ChangeLog
index 5e13c96..adda370 100644
--- a/fs/sysv/ChangeLog
+++ b/fs/sysv/ChangeLog
@@ -1,13 +1,18 @@
+Thu Feb  7 2002  Alexander Viro  <viro@math.psu.edu>
+
+	* super.c: switched to ->get_sb()
+	* ChangeLog: fixed dates ;-)
+
 2002-01-24  David S. Miller  <davem@redhat.com>
 
 	* inode.c: Include linux/init.h
 
-Mon Jan 21 2001  Alexander Viro  <viro@math.psu.edu>
+Mon Jan 21 2002  Alexander Viro  <viro@math.psu.edu>
 	* ialloc.c (sysv_new_inode): zero SYSV_I(inode)->i_data out.
 	* i_vnode renamed to vfs_inode.  Sorry, but let's keep that
 	  consistent.
 
-Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+Sat Jan 19 2002  Christoph Hellwig  <hch@infradead.org>
 
 	* include/linux/sysv_fs.h (SYSV_I): Get fs-private inode data using
 		list_entry() instead of inode->u.
@@ -19,7 +24,7 @@
 		in the case of failed register_filesystem for V7.
 	(exit_sysv_fs): Destroy inode cache.
 
-Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+Sat Jan 19 2002  Christoph Hellwig  <hch@infradead.org>
 
 	* include/linux/sysv_fs.h: Include <linux/sysv_fs_i.h>, declare SYSV_I().
 	* dir.c (sysv_find_entry): Use SYSV_I() instead of ->u.sysv_i to
@@ -32,7 +37,7 @@
 	* symlink.c (sysv_readlink): Likewise.
 	(sysv_follow_link): Likewise.
 
-Fri Jan  4 2001  Alexander Viro  <viro@math.psu.edu>
+Fri Jan  4 2002  Alexander Viro  <viro@math.psu.edu>
 
 	* ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname().
 	* inode.c (sysv_read_inode): Likewise.
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index 1e853dd..793578e 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -340,8 +340,7 @@
 	return 1;
 }
 
-static struct super_block *sysv_read_super(struct super_block *sb,
-					   void *data, int silent)
+static int sysv_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct buffer_head *bh1;
 	struct buffer_head *bh = NULL;
@@ -397,7 +396,7 @@
 		sb->sv_bh1 = bh1;
 		sb->sv_bh2 = bh;
 		if (complete_read_super(sb, silent, size))
-			return sb;
+			return 0;
 	}
 
 	brelse(bh1);
@@ -405,7 +404,7 @@
 	sb_set_blocksize(sb, BLOCK_SIZE);
 	printk("oldfs: cannot read superblock\n");
 failed:
-	return NULL;
+	return -EINVAL;
 
 Eunknown:
 	brelse(bh);
@@ -421,8 +420,7 @@
 	goto failed;
 }
 
-static struct super_block *v7_read_super(struct super_block *sb,void *data,
-				  int silent)
+static int v7_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct buffer_head *bh, *bh2 = NULL;
 	struct v7_super_block *v7sb;
@@ -466,18 +464,41 @@
 	sb->sv_bh1 = bh;
 	sb->sv_bh2 = bh;
 	if (complete_read_super(sb, silent, 1))
-		return sb;
+		return 0;
 
 failed:
 	brelse(bh2);
 	brelse(bh);
-	return NULL;
+	return -EINVAL;
 }
 
 /* Every kernel module contains stuff like this. */
 
-static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super);
-static DECLARE_FSTYPE_DEV(v7_fs_type, "v7", v7_read_super);
+static struct super_block *sysv_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super);
+}
+
+static struct super_block *v7_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super);
+}
+
+static struct file_system_type sysv_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"sysv",
+	get_sb:		sysv_get_sb,
+	fs_flags:	FS_REQUIRES_DEV,
+};
+
+static struct file_system_type v7_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"v7",
+	get_sb:		v7_get_sb,
+	fs_flags:	FS_REQUIRES_DEV,
+};
 
 extern int sysv_init_icache(void) __init;
 extern void sysv_destroy_icache(void);
diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h
index bc1496a..4385a95 100644
--- a/include/asm-i386/current.h
+++ b/include/asm-i386/current.h
@@ -1,14 +1,14 @@
 #ifndef _I386_CURRENT_H
 #define _I386_CURRENT_H
 
+#include <asm/thread_info.h>
+
 struct task_struct;
 
 static inline struct task_struct * get_current(void)
 {
-	struct task_struct *current;
-	__asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
-	return current;
- }
+	return current_thread_info()->task;
+}
  
 #define current get_current()
 
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index b321dd0..5b43b7c 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -116,7 +116,8 @@
 
 #define GET_CURRENT \
 	"movl %esp, %ebx\n\t" \
-	"andl $-8192, %ebx\n\t"
+	"andl $-8192, %ebx\n\t" \
+	"movl (%ebx),%ebx\n\t"
 
 /*
  *	SMP has a few special interrupts for IPI messages
diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h
index 1cf8dc2..3463340 100644
--- a/include/asm-i386/i387.h
+++ b/include/asm-i386/i387.h
@@ -28,16 +28,17 @@
 
 
 #define unlazy_fpu( tsk ) do { \
-	if ( tsk->flags & PF_USEDFPU ) \
+	if (test_thread_flag(TIF_USEDFPU)) \
 		save_init_fpu( tsk ); \
 } while (0)
 
-#define clear_fpu( tsk ) do { \
-	if ( tsk->flags & PF_USEDFPU ) { \
-		asm volatile("fwait"); \
-		tsk->flags &= ~PF_USEDFPU; \
-		stts(); \
-	} \
+#define clear_fpu( tsk )			\
+do {						\
+	if (test_thread_flag(TIF_USEDFPU)) {	\
+		asm volatile("fwait");		\
+		clear_thread_flag(TIF_USEDFPU);	\
+		stts();				\
+	}					\
 } while (0)
 
 /*
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 34820d6..c457c7a 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -105,7 +105,7 @@
  * so this is correct in the x86 case.
  */
 
-#define smp_processor_id() (current->cpu)
+#define smp_processor_id() (current_thread_info()->cpu)
 
 static __inline int hard_smp_processor_id(void)
 {
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
new file mode 100644
index 0000000..e8515e0
--- /dev/null
+++ b/include/asm-i386/thread_info.h
@@ -0,0 +1,113 @@
+/* thread_info.h: i386 low-level thread information
+ *
+ * Copyright (C) 2002  David Howells (dhowells@redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#endif
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ * - if the contents of this structure are changed, the assembly constants must also be changed
+ */
+#ifndef __ASSEMBLY__
+struct thread_info {
+	struct task_struct	*task;		/* main task structure */
+	struct exec_domain	*exec_domain;	/* execution domain */
+	unsigned long		flags;		/* low level flags */
+	__u32			cpu;		/* current CPU */
+
+	mm_segment_t		addr_limit;	/* thread address space:
+					 	   0-0xBFFFFFFF for user-thead
+						   0-0xFFFFFFFF for kernel-thread
+						*/
+
+	__u8			supervisor_stack[0];
+};
+
+#else /* !__ASSEMBLY__ */
+
+/* offsets into the thread_info struct for assembly code access */
+#define TI_TASK		0x00000000
+#define TI_EXEC_DOMAIN	0x00000004
+#define TI_FLAGS	0x00000008
+#define TI_CPU		0x0000000C
+#define TI_ADDR_LIMIT	0x00000010
+
+#endif
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ */
+#ifndef __ASSEMBLY__
+#define INIT_THREAD_INFO(tsk)			\
+{						\
+	task:		&tsk,			\
+	exec_domain:	&default_exec_domain,	\
+	flags:		0,			\
+	cpu:		0,			\
+	addr_limit:	KERNEL_DS,		\
+}
+
+#define init_thread_info	(init_thread_union.thread_info)
+#define init_stack		(init_thread_union.stack)
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+	struct thread_info *ti;
+	__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~8191UL));
+	return ti;
+}
+
+/* thread information allocation */
+#define THREAD_SIZE (2*PAGE_SIZE)
+#define alloc_thread_info() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#define get_thread_info(ti) get_task_struct((ti)->l_task)
+#define put_thread_info(ti) put_task_struct((ti)->l_task)
+
+#else /* !__ASSEMBLY__ */
+
+/* how to get the thread information struct from ASM */
+#define GET_THREAD_INFO(reg) \
+	movl $-8192, reg; \
+	andl %esp, reg
+
+#endif
+
+/*
+ * thread information flags
+ * - these are process state flags that various assembly files may need to access
+ * - pending work-to-be-done flags are in LSW
+ * - other flags in MSW
+ */
+#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_NOTIFY_RESUME	1	/* resumption notification requested */
+#define TIF_SIGPENDING		2	/* signal pending */
+#define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+#define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
+#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+
+#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+#define _TIF_USEDFPU		(1<<TIF_USEDFPU)
+#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+
+#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
+#define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index ecc6693..c932a69 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -27,14 +27,14 @@
 #define USER_DS		MAKE_MM_SEG(PAGE_OFFSET)
 
 #define get_ds()	(KERNEL_DS)
-#define get_fs()	(current->addr_limit)
-#define set_fs(x)	(current->addr_limit = (x))
+#define get_fs()	(current_thread_info()->addr_limit)
+#define set_fs(x)	(current_thread_info()->addr_limit = (x))
 
 #define segment_eq(a,b)	((a).seg == (b).seg)
 
 extern int __verify_write(const void *, unsigned long);
 
-#define __addr_ok(addr) ((unsigned long)(addr) < (current->addr_limit.seg))
+#define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
 
 /*
  * Uhhuh, this needs 33-bit arithmetic. We have a carry..
@@ -43,7 +43,7 @@
 	unsigned long flag,sum; \
 	asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
 		:"=&r" (flag), "=r" (sum) \
-		:"1" (addr),"g" ((int)(size)),"g" (current->addr_limit.seg)); \
+		:"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \
 	flag; })
 
 #ifdef CONFIG_X86_WP_WORKS_OK
diff --git a/include/asm-i386/xor.h b/include/asm-i386/xor.h
index 5a99f54..3130e82 100644
--- a/include/asm-i386/xor.h
+++ b/include/asm-i386/xor.h
@@ -20,7 +20,7 @@
 
 #define FPU_SAVE							\
   do {									\
-	if (!(current->flags & PF_USEDFPU))				\
+	if (!test_thread_flag(TIF_USEDFPU))				\
 		__asm__ __volatile__ (" clts;\n");			\
 	__asm__ __volatile__ ("fsave %0; fwait": "=m"(fpu_save[0]));	\
   } while (0)
@@ -28,7 +28,7 @@
 #define FPU_RESTORE							\
   do {									\
 	__asm__ __volatile__ ("frstor %0": : "m"(fpu_save[0]));		\
-	if (!(current->flags & PF_USEDFPU))				\
+	if (!test_thread_flag(TIF_USEDFPU))				\
 		stts();							\
   } while (0)
 
diff --git a/include/asm-sparc64/a.out.h b/include/asm-sparc64/a.out.h
index 12f58b4..7ebbfcd 100644
--- a/include/asm-sparc64/a.out.h
+++ b/include/asm-sparc64/a.out.h
@@ -1,4 +1,4 @@
-/* $Id: a.out.h,v 1.7 2001-04-24 01:09:12 davem Exp $ */
+/* $Id: a.out.h,v 1.8 2002-02-09 19:49:31 davem Exp $ */
 #ifndef __SPARC64_A_OUT_H__
 #define __SPARC64_A_OUT_H__
 
@@ -95,7 +95,7 @@
 
 #ifdef __KERNEL__
 
-#define STACK_TOP (current->thread.flags & SPARC_FLAG_32BIT ? 0xf0000000 : 0x80000000000L)
+#define STACK_TOP (test_thread_flag(TIF_32BIT) ? 0xf0000000 : 0x80000000000L)
 
 #endif
 
diff --git a/include/asm-sparc64/checksum.h b/include/asm-sparc64/checksum.h
index 2ee3622..81cc757 100644
--- a/include/asm-sparc64/checksum.h
+++ b/include/asm-sparc64/checksum.h
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.18 2002-02-01 22:01:05 davem Exp $ */
+/* $Id: checksum.h,v 1.19 2002-02-09 19:49:31 davem Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -45,7 +45,7 @@
 			   unsigned int sum)
 {
 	int ret;
-	unsigned char cur_ds = current->thread.current_ds.seg;
+	unsigned char cur_ds = get_thread_current_ds();
 	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "i" (ASI_P));
 	ret = csum_partial_copy_sparc64(src, dst, len, sum);
 	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" (cur_ds));
diff --git a/include/asm-sparc64/current.h b/include/asm-sparc64/current.h
index 80652fb..7683c6b 100644
--- a/include/asm-sparc64/current.h
+++ b/include/asm-sparc64/current.h
@@ -1,7 +1,8 @@
 #ifndef _SPARC64_CURRENT_H
 #define _SPARC64_CURRENT_H
 
-/* Sparc rules... */
-register struct task_struct *current asm("g6");
+#include <asm/thread_info.h>
+
+#define current		(current_thread_info()->task)
 
 #endif /* !(_SPARC64_CURRENT_H) */
diff --git a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h
index 69c60a7..dceb5dd 100644
--- a/include/asm-sparc64/elf.h
+++ b/include/asm-sparc64/elf.h
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.31 2002-01-08 16:00:20 davem Exp $ */
+/* $Id: elf.h,v 1.32 2002-02-09 19:49:31 davem Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -69,16 +69,11 @@
 
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2)			\
-do {	unsigned char flags = current->thread.flags;	\
-	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)	\
-		flags |= SPARC_FLAG_32BIT;		\
+do {	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)	\
+		set_thread_flag(TIF_32BIT);		\
 	else						\
-		flags &= ~SPARC_FLAG_32BIT;		\
-	if (flags != current->thread.flags) {		\
-		/* flush_thread will update pgd cache */\
-		current->thread.flags = flags;		\
-	}						\
-							\
+		clear_thread_flag(TIF_32BIT);		\
+	/* flush_thread will update pgd cache */	\
 	if (ibcs2)					\
 		set_personality(PER_SVR4);		\
 	else if (current->personality != PER_LINUX32)	\
diff --git a/include/asm-sparc64/fpumacro.h b/include/asm-sparc64/fpumacro.h
index 3fd5cab..21d2740 100644
--- a/include/asm-sparc64/fpumacro.h
+++ b/include/asm-sparc64/fpumacro.h
@@ -14,7 +14,7 @@
 	u32	regs[64];
 };
 
-#define FPUSTATE (struct fpustate *)(((unsigned long)current) + AOFF_task_fpregs)
+#define FPUSTATE (struct fpustate *)(current_thread_info()->fpregs)
 
 extern __inline__ unsigned long fprs_read(void)
 {
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
index e8103b7..46ecb86 100644
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.53 2002-01-30 01:40:00 davem Exp $ */
+/* $Id: mmu_context.h,v 1.54 2002-02-09 19:49:31 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -101,7 +101,7 @@
 	register unsigned long pgd_cache asm("o4"); \
 	paddr = __pa((__mm)->pgd); \
 	pgd_cache = 0UL; \
-	if ((__tsk)->thread.flags & SPARC_FLAG_32BIT) \
+	if ((__tsk)->thread_info->flags & _TIF_32BIT) \
 		pgd_cache = pgd_val((__mm)->pgd[0]) << 11UL; \
 	__asm__ __volatile__("wrpr	%%g0, 0x494, %%pstate\n\t" \
 			     "mov	%3, %%g4\n\t" \
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index 86662d2..68fe493 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.38 2001-11-30 01:04:10 davem Exp $ */
+/* $Id: page.h,v 1.39 2002-02-09 19:49:31 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -95,7 +95,7 @@
 
 #endif /* (STRICT_MM_TYPECHECKS) */
 
-#define TASK_UNMAPPED_BASE	((current->thread.flags & SPARC_FLAG_32BIT) ? \
+#define TASK_UNMAPPED_BASE	(test_thread_flag(TIF_32BIT) ? \
 				 (0x0000000070000000UL) : (PAGE_OFFSET))
 
 #endif /* !(__ASSEMBLY__) */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index e013039..61615d5 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.155 2001-12-21 04:56:17 davem Exp $
+/* $Id: pgtable.h,v 1.156 2002-02-09 19:49:31 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -76,7 +76,7 @@
  * is different so we can optimize correctly for 32-bit tasks.
  */
 #define REAL_PTRS_PER_PMD	(1UL << PMD_BITS)
-#define PTRS_PER_PMD		((const int)((current->thread.flags & SPARC_FLAG_32BIT) ? \
+#define PTRS_PER_PMD		((const int)(test_thread_flag(TIF_32BIT) ? \
 				 (1UL << (32 - (PAGE_SHIFT-3) - PAGE_SHIFT)) : (REAL_PTRS_PER_PMD)))
 
 /*
@@ -90,8 +90,8 @@
 			(PAGE_SHIFT-3) + PMD_BITS)))
 
 /* Kernel has a separate 44bit address space. */
-#define USER_PTRS_PER_PGD	((const int)((current->thread.flags & SPARC_FLAG_32BIT) ? \
-				 (1) : (PTRS_PER_PGD)))
+#define USER_PTRS_PER_PGD	((const int)(test_thread_flag(TIF_32BIT)) ? \
+				 (1) : (PTRS_PER_PGD))
 #define FIRST_USER_PGD_NR	0
 
 #define pte_ERROR(e)	__builtin_trap()
diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h
index 8d6fdbe..dbeacf2 100644
--- a/include/asm-sparc64/processor.h
+++ b/include/asm-sparc64/processor.h
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.81 2002-02-02 03:33:48 kanoj Exp $
+/* $Id: processor.h,v 1.82 2002-02-09 19:49:31 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -44,29 +44,13 @@
 
 #ifndef __ASSEMBLY__
 
-#define NSWINS		7
-
 typedef struct {
 	unsigned char seg;
 } mm_segment_t;
 
 /* The Sparc processor specific thread struct. */
+/* XXX This should die, everything can go into thread_info now. */
 struct thread_struct {
-	/* D$ line 1 */
-	unsigned long ksp __attribute__ ((aligned(16)));
-	unsigned char wstate, cwp, flags;
-	mm_segment_t current_ds;
-	unsigned char w_saved, fpdepth, fault_code, use_blkcommit;
-	unsigned long fault_address;
-	unsigned char fpsaved[7];
-	unsigned char __pad2;
-	
-	/* D$ line 2, 3, 4 */
-	struct pt_regs *kregs;
-	unsigned long *utraps;
-	unsigned long gsr[7];
-	unsigned long xfsr[7];
-
 #ifdef CONFIG_DEBUG_SPINLOCK
 	/* How many spinlocks held by this thread.
 	 * Used with spin lock debugging to catch tasks
@@ -74,96 +58,29 @@
 	 */
 	int smp_lock_count;
 	unsigned int smp_lock_pc;
+#else
+	int dummy; /* f'in gcc bug... */
 #endif
-
-	struct reg_window reg_window[NSWINS];
-	unsigned long rwbuf_stkptrs[NSWINS];
-	
-	/* Performance counter state */
-	u64 *user_cntd0, *user_cntd1;
-	u64 kernel_cntd0, kernel_cntd1;
-	u64 pcr_reg;
 };
 
 #endif /* !(__ASSEMBLY__) */
 
-#define SPARC_FLAG_UNALIGNED    0x01    /* is allowed to do unaligned accesses	*/
-#define SPARC_FLAG_NEWSIGNALS   0x02    /* task wants new-style signals		*/
-#define SPARC_FLAG_32BIT        0x04    /* task is older 32-bit binary		*/
-#define SPARC_FLAG_NEWCHILD     0x08    /* task is just-spawned child process	*/
-#define SPARC_FLAG_PERFCTR	0x10    /* task has performance counters active	*/
-
-#define FAULT_CODE_WRITE	0x01	/* Write access, implies D-TLB		*/
-#define FAULT_CODE_DTLB		0x02	/* Miss happened in D-TLB		*/
-#define FAULT_CODE_ITLB		0x04	/* Miss happened in I-TLB		*/
-#define FAULT_CODE_WINFIXUP	0x08	/* Miss happened during spill/fill	*/
-
 #ifndef CONFIG_DEBUG_SPINLOCK
-#define INIT_THREAD  {					\
-/* ksp, wstate, cwp, flags, current_ds, */ 		\
-   0,   0,      0,   0,     KERNEL_DS,			\
-/* w_saved, fpdepth, fault_code, use_blkcommit, */	\
-   0,       0,       0,          0,			\
-/* fault_address, fpsaved, __pad2, kregs, */		\
-   0,             { 0 },   0,      0,			\
-/* utraps, gsr,   xfsr, */				\
-   0,	   { 0 }, { 0 },				\
-/* reg_window */					\
-   { { { 0, }, { 0, } }, }, 				\
-/* rwbuf_stkptrs */					\
-   { 0, 0, 0, 0, 0, 0, 0, },				\
-/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
-   0,          0,          0,		 0,            0, \
+#define INIT_THREAD  {			\
+	0,				\
 }
 #else /* CONFIG_DEBUG_SPINLOCK */
 #define INIT_THREAD  {					\
-/* ksp, wstate, cwp, flags, current_ds, */ 		\
-   0,   0,      0,   0,     KERNEL_DS,			\
-/* w_saved, fpdepth, fault_code, use_blkcommit, */	\
-   0,       0,       0,          0,			\
-/* fault_address, fpsaved, __pad2, kregs, */		\
-   0,             { 0 },   0,      0,			\
-/* utraps, gsr,   xfsr,  smp_lock_count, smp_lock_pc, */\
-   0,	   { 0 }, { 0 }, 0,		 0,		\
-/* reg_window */					\
-   { { { 0, }, { 0, } }, }, 				\
-/* rwbuf_stkptrs */					\
-   { 0, 0, 0, 0, 0, 0, 0, },				\
-/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
-   0,          0,          0,		 0,            0, \
+/* smp_lock_count, smp_lock_pc, */			\
+   0,		   0,					\
 }
 #endif /* !(CONFIG_DEBUG_SPINLOCK) */
 
-#ifdef __KERNEL__
-#if PAGE_SHIFT == 13
-#define THREAD_SIZE (2*PAGE_SIZE)
-#define THREAD_SHIFT (PAGE_SHIFT + 1)
-#else /* PAGE_SHIFT == 13 */
-#define THREAD_SIZE PAGE_SIZE
-#define THREAD_SHIFT PAGE_SHIFT
-#endif /* PAGE_SHIFT == 13 */
-#endif /* __KERNEL__ */
-
 #ifndef __ASSEMBLY__
 
 /* Return saved PC of a blocked thread. */
-extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
-{
-	unsigned long ret = 0xdeadbeefUL;
-	
-	if (t->ksp) {
-		unsigned long *sp;
-		sp = (unsigned long *)(t->ksp + STACK_BIAS);
-		if (((unsigned long)sp & (sizeof(long) - 1)) == 0UL &&
-		    sp[14]) {
-			unsigned long *fp;
-			fp = (unsigned long *)(sp[14] + STACK_BIAS);
-			if (((unsigned long)fp & (sizeof(long) - 1)) == 0UL)
-				ret = fp[15];
-		}
-	}
-	return ret;
-}
+struct thread_info;
+extern unsigned long thread_saved_pc(struct thread_info *);
 
 /* On Uniprocessor, even in RMO processes see TSO semantics */
 #ifdef CONFIG_SMP
@@ -179,13 +96,13 @@
 	regs->tpc = ((pc & (~3)) - 4); \
 	regs->tnpc = regs->tpc + 4; \
 	regs->y = 0; \
-	current->thread.wstate = (1 << 3); \
-	if (current->thread.utraps) { \
-		if (*(current->thread.utraps) < 2) \
-			kfree (current->thread.utraps); \
+	set_thread_wstate(1 << 3); \
+	if (current_thread_info()->utraps) { \
+		if (*(current_thread_info()->utraps) < 2) \
+			kfree(current_thread_info()->utraps); \
 		else \
-			(*(current->thread.utraps))--; \
-		current->thread.utraps = NULL; \
+			(*(current_thread_info()->utraps))--; \
+		current_thread_info()->utraps = NULL; \
 	} \
 	__asm__ __volatile__( \
 	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
@@ -208,7 +125,7 @@
 	: \
 	: "r" (regs), "r" (sp - REGWIN_SZ - STACK_BIAS), \
 	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
-} while(0)
+} while (0)
 
 #define start_thread32(regs, pc, sp) \
 do { \
@@ -219,13 +136,13 @@
 	regs->tpc = ((pc & (~3)) - 4); \
 	regs->tnpc = regs->tpc + 4; \
 	regs->y = 0; \
-	current->thread.wstate = (2 << 3); \
-	if (current->thread.utraps) { \
-		if (*(current->thread.utraps) < 2) \
-			kfree (current->thread.utraps); \
+	set_thread_wstate(2 << 3); \
+	if (current_thread_info()->utraps) { \
+		if (*(current_thread_info()->utraps) < 2) \
+			kfree(current_thread_info()->utraps); \
 		else \
-			(*(current->thread.utraps))--; \
-		current->thread.utraps = NULL; \
+			(*(current_thread_info()->utraps))--; \
+		current_thread_info()->utraps = NULL; \
 	} \
 	__asm__ __volatile__( \
 	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
@@ -248,10 +165,10 @@
 	: \
 	: "r" (regs), "r" (sp - REGWIN32_SZ), \
 	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
-} while(0)
+} while (0)
 
 /* Free all resources held by a thread. */
-#define release_thread(tsk)		do { } while(0)
+#define release_thread(tsk)		do { } while (0)
 
 extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
@@ -262,19 +179,20 @@
 ({	extern void scheduling_functions_start_here(void); \
 	extern void scheduling_functions_end_here(void); \
 	unsigned long pc, fp, bias = 0; \
-	unsigned long task_base = (unsigned long) (__TSK); \
+	unsigned long thread_info_base; \
 	struct reg_window *rw; \
         unsigned long __ret = 0; \
 	int count = 0; \
 	if (!(__TSK) || (__TSK) == current || \
             (__TSK)->state == TASK_RUNNING) \
 		goto __out; \
+	thread_info_base = (unsigned long) ((__TSK)->thread_info); \
 	bias = STACK_BIAS; \
-	fp = (__TSK)->thread.ksp + bias; \
+	fp = (__TSK)->thread_info->ksp + bias; \
 	do { \
 		/* Bogus frame pointer? */ \
-		if (fp < (task_base + sizeof(struct task_struct)) || \
-		    fp >= (task_base + THREAD_SIZE)) \
+		if (fp < (thread_info_base + sizeof(struct thread_info)) || \
+		    fp >= (thread_info_base + THREAD_SIZE)) \
 			break; \
 		rw = (struct reg_window *) fp; \
 		pc = rw->ins[7]; \
@@ -288,27 +206,11 @@
 __out:	__ret; \
 })
 
-#define KSTK_EIP(tsk)  ((tsk)->thread.kregs->tpc)
-#define KSTK_ESP(tsk)  ((tsk)->thread.kregs->u_regs[UREG_FP])
-
-#ifdef __KERNEL__
-/* Allocation and freeing of task_struct and kernel stack. */
-#if PAGE_SHIFT == 13
-#define alloc_task_struct()   ((struct task_struct *)__get_free_pages(GFP_KERNEL, 1))
-#define free_task_struct(tsk) free_pages((unsigned long)(tsk),1)
-#else /* PAGE_SHIFT == 13 */
-#define alloc_task_struct()   ((struct task_struct *)__get_free_pages(GFP_KERNEL, 0))
-#define free_task_struct(tsk) free_pages((unsigned long)(tsk),0)
-#endif /* PAGE_SHIFT == 13 */
-#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
-
-#define init_task	(init_task_union.task)
-#define init_stack	(init_task_union.stack)
+#define KSTK_EIP(tsk)  ((tsk)->thread_info->kregs->tpc)
+#define KSTK_ESP(tsk)  ((tsk)->thread_info->kregs->u_regs[UREG_FP])
 
 #define cpu_relax()	udelay(1 + smp_processor_id())
 
-#endif /* __KERNEL__ */
-
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__ASM_SPARC64_PROCESSOR_H) */
diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h
index 386f474..b2e191d 100644
--- a/include/asm-sparc64/ptrace.h
+++ b/include/asm-sparc64/ptrace.h
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.13 1997-09-17 17:27:51 davem Exp $ */
+/* $Id: ptrace.h,v 1.14 2002-02-09 19:49:32 davem Exp $ */
 #ifndef _SPARC64_PTRACE_H
 #define _SPARC64_PTRACE_H
 
@@ -110,8 +110,6 @@
 #define TRACEREG32_SZ		0x50
 #define STACKFRAME32_SZ		0x60
 #define REGWIN32_SZ		0x40
-
-#include <asm/asm_offsets.h>
 #endif
 
 #ifdef __KERNEL__
diff --git a/include/asm-sparc64/sfp-machine.h b/include/asm-sparc64/sfp-machine.h
index 49c77bd..5015bb8 100644
--- a/include/asm-sparc64/sfp-machine.h
+++ b/include/asm-sparc64/sfp-machine.h
@@ -74,7 +74,7 @@
 
 /* Obtain the current rounding mode. */
 #ifndef FP_ROUNDMODE
-#define FP_ROUNDMODE	((current->thread.xfsr[0] >> 30) & 0x3)
+#define FP_ROUNDMODE	((current_thread_info()->xfsr[0] >> 30) & 0x3)
 #endif
 
 /* Exception flags. */
@@ -86,6 +86,6 @@
 
 #define FP_HANDLE_EXCEPTIONS return _fex
 
-#define FP_INHIBIT_RESULTS ((current->thread.xfsr[0] >> 23) & _fex)
+#define FP_INHIBIT_RESULTS ((current_thread_info()->xfsr[0] >> 23) & _fex)
 
 #endif
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index d73d3e6..ae53073 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -103,7 +103,7 @@
 	}
 }
 
-#define smp_processor_id() (current->cpu)
+#define smp_processor_id() (current_thread_info()->cpu)
 
 /* This needn't do anything as we do not sleep the cpu
  * inside of the idler task, so an interrupt is not needed
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 58976a0..f87be0c 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -1,12 +1,12 @@
-/* $Id: system.h,v 1.68 2001-11-18 00:12:56 davem Exp $ */
+/* $Id: system.h,v 1.69 2002-02-09 19:49:31 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
 #include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
-#include <asm/asm_offsets.h>
 #include <asm/visasm.h>
+#include <asm/thread_info.h>
 
 #ifndef __ASSEMBLY__
 /*
@@ -174,19 +174,19 @@
 	 */
 #define switch_to(prev, next, last)						\
 do {	CHECK_LOCKS(prev);							\
-	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
+	if (test_thread_flag(TIF_PERFCTR)) {					\
 		unsigned long __tmp;						\
 		read_pcr(__tmp);						\
-		current->thread.pcr_reg = __tmp;				\
+		current_thread_info()->pcr_reg = __tmp;				\
 		read_pic(__tmp);						\
-		current->thread.kernel_cntd0 += (unsigned int)(__tmp);		\
-		current->thread.kernel_cntd1 += ((__tmp) >> 32);		\
+		current_thread_info()->kernel_cntd0 += (unsigned int)(__tmp);	\
+		current_thread_info()->kernel_cntd1 += ((__tmp) >> 32);		\
 	}									\
 	save_and_clear_fpu();							\
 	/* If you are tempted to conditionalize the following */		\
 	/* so that ASI is only written if it changes, think again. */		\
 	__asm__ __volatile__("wr %%g0, %0, %%asi"				\
-			     : : "r" (next->thread.current_ds.seg));		\
+	: : "r" (__thread_flag_byte_ptr(next->thread_info)[TI_FLAG_BYTE_CURRENT_DS]));	\
 	__asm__ __volatile__(							\
 	"mov	%%g6, %%g5\n\t"							\
 	"wrpr	%%g0, 0x95, %%pstate\n\t"					\
@@ -202,7 +202,7 @@
 	"wrpr	%%g1, %%cwp\n\t"						\
 	"ldx	[%%g6 + %3], %%o6\n\t"						\
 	"ldub	[%%g6 + %2], %%o5\n\t"						\
-	"ldub	[%%g6 + %4], %%o7\n\t"						\
+	"ldx	[%%g6 + %4], %%o7\n\t"						\
 	"mov	%%g6, %%l2\n\t"							\
 	"wrpr	%%o5, 0x0, %%wstate\n\t"					\
 	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"					\
@@ -212,21 +212,18 @@
 	"wrpr	%%g0, 0x96, %%pstate\n\t"					\
 	"andcc	%%o7, %6, %%g0\n\t"						\
 	"bne,pn	%%icc, ret_from_syscall\n\t"					\
-	" mov	%%g5, %0\n\t"							\
+	" ldx	[%%g5 + %7], %0\n\t"						\
 	: "=&r" (last)								\
-	: "r" (next),								\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.wstate)),\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.ksp)),	\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.flags)),\
-	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.cwp)),	\
-	  "i" (SPARC_FLAG_NEWCHILD)						\
+	: "r" (next->thread_info),						\
+	  "i" (TI_WSTATE), "i" (TI_KSP), "i" (TI_FLAGS), "i" (TI_CWP),		\
+	  "i" (_TIF_NEWCHILD), "i" (TI_TASK)					\
 	: "cc", "g1", "g2", "g3", "g5", "g7",					\
 	  "l2", "l3", "l4", "l5", "l6", "l7",					\
 	  "i0", "i1", "i2", "i3", "i4", "i5",					\
 	  "o0", "o1", "o2", "o3", "o4", "o5", "o7");				\
 	/* If you fuck with this, update ret_from_syscall code too. */		\
-	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
-		write_pcr(current->thread.pcr_reg);				\
+	if (test_thread_flag(TIF_PERFCTR)) {					\
+		write_pcr(current_thread_info()->pcr_reg);			\
 		reset_pic();							\
 	}									\
 } while(0)
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h
index 33d3363..a302515 100644
--- a/include/asm-sparc64/ttable.h
+++ b/include/asm-sparc64/ttable.h
@@ -1,9 +1,9 @@
-/* $Id: ttable.h,v 1.17 2001-11-28 23:32:16 davem Exp $ */
+/* $Id: ttable.h,v 1.18 2002-02-09 19:49:32 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
 #include <linux/config.h>
-#include <asm/asm_offsets.h>
+#include <asm/thread_info.h>
 #include <asm/utrap.h>
 
 #define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
@@ -104,14 +104,14 @@
 	 mov	num, %g1;				\
 	nop;nop;nop;
 	
-#define TRAP_UTRAP(handler,lvl)						\
-	ldx	[%g6 + AOFF_task_thread + AOFF_thread_utraps], %g1;	\
-	sethi	%hi(109f), %g7;						\
-	brz,pn	%g1, utrap;						\
-	 or	%g7, %lo(109f), %g7;					\
-	ba,pt	%xcc, utrap;						\
-109:	 ldx	[%g1 + handler*8], %g1;					\
-	ba,pt	%xcc, utrap_ill;					\
+#define TRAP_UTRAP(handler,lvl)				\
+	ldx	[%g6 + TI_UTRAPS], %g1;			\
+	sethi	%hi(109f), %g7;				\
+	brz,pn	%g1, utrap;				\
+	 or	%g7, %lo(109f), %g7;			\
+	ba,pt	%xcc, utrap;				\
+109:	 ldx	[%g1 + handler*8], %g1;			\
+	ba,pt	%xcc, utrap_ill;			\
 	 mov	lvl, %o1;
 
 #ifdef CONFIG_SUNOS_EMUL
diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h
index 7c4bfd9..f1f8799 100644
--- a/include/asm-sparc64/uaccess.h
+++ b/include/asm-sparc64/uaccess.h
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.34 2001-09-27 04:36:24 kanoj Exp $ */
+/* $Id: uaccess.h,v 1.35 2002-02-09 19:49:31 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -36,14 +36,14 @@
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
 
-#define get_fs() (current->thread.current_ds)
+#define get_fs() ((mm_segment_t) { get_thread_current_ds() })
 #define get_ds() (KERNEL_DS)
 
 #define segment_eq(a,b)  ((a).seg == (b).seg)
 
 #define set_fs(val)								\
 do {										\
-	current->thread.current_ds = (val);					\
+	set_thread_current_ds((val).seg);					\
 	__asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg));	\
 } while(0)
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8e3ce34..68902b1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -964,17 +964,14 @@
 	int flags, void *data,
 	int (*fill_super)(struct super_block *, void *, int));
 
-#define DECLARE_FSTYPE(var,type,read,flags) \
+#define DECLARE_FSTYPE_DEV(var,type,read) \
 struct file_system_type var = { \
 	name:		type, \
 	read_super:	read, \
-	fs_flags:	flags, \
+	fs_flags:	FS_REQUIRES_DEV, \
 	owner:		THIS_MODULE, \
 }
 
-#define DECLARE_FSTYPE_DEV(var,type,read) \
-	DECLARE_FSTYPE(var,type,read,FS_REQUIRES_DEV)
-
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
 	(((fops) && (fops)->owner)	\
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index 5e741a1..4077fd8 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -2,11 +2,9 @@
 #define _GAMEPORT_H
 
 /*
- * $Id: gameport.h,v 1.11 2001/04/26 10:24:46 vojtech Exp $
+ * $Id: gameport.h,v 1.20 2002/01/03 08:55:05 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -26,21 +24,27 @@
  *
  * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
-#include <linux/sched.h>
-#include <linux/delay.h>
 #include <asm/io.h>
+#include <linux/input.h>
 
 struct gameport;
 
 struct gameport {
 
-	void *private;
-
+	void *private;	/* Private pointer for joystick drivers */
+	void *driver;	/* Private pointer for gameport drivers */
+	char *name;
+	char *phys;
 	int number;
 
+	unsigned short idbus;
+	unsigned short idvendor;
+	unsigned short idproduct;
+	unsigned short idversion;
+
 	int io;
 	int speed;
 	int fuzz;
@@ -59,6 +63,7 @@
 struct gameport_dev {
 
 	void *private;
+	char *name;
 
 	void (*connect)(struct gameport *, struct gameport_dev *dev);
 	void (*disconnect)(struct gameport *);
@@ -74,8 +79,8 @@
 void gameport_register_port(struct gameport *gameport);
 void gameport_unregister_port(struct gameport *gameport);
 #else
-static void __inline__ gameport_register_port(struct gameport *gameport) { return; }
-static void __inline__ gameport_unregister_port(struct gameport *gameport) { return; }
+void __inline__ gameport_register_port(struct gameport *gameport) { return; }
+void __inline__ gameport_unregister_port(struct gameport *gameport) { return; }
 #endif
 
 void gameport_register_device(struct gameport_dev *dev);
@@ -94,6 +99,7 @@
 #define GAMEPORT_ID_VENDOR_MICROSOFT	0x0007
 #define GAMEPORT_ID_VENDOR_THRUSTMASTER	0x0008
 #define GAMEPORT_ID_VENDOR_GRAVIS	0x0009
+#define GAMEPORT_ID_VENDOR_GUILLEMOT	0x000a
 
 static __inline__ void gameport_trigger(struct gameport *gameport)
 {
@@ -134,7 +140,7 @@
 
 static __inline__ void wait_ms(unsigned int ms)
 {
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(1 + ms * HZ / 1000);
 }
 
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 4da3384..9007fe5 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -35,14 +35,6 @@
 	siglock:	SPIN_LOCK_UNLOCKED 		\
 }
 
-#define INIT_TASK_WORK				\
-{						\
-	need_resched:	0,			\
-	syscall_trace:	0,			\
-	sigpending:	0,			\
-	notify_resume:	0,			\
-}
-
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -50,10 +42,8 @@
 #define INIT_TASK(tsk)	\
 {									\
     state:		0,						\
+    thread_info:	&init_thread_info,				\
     flags:		0,						\
-    work:		INIT_TASK_WORK,					\
-    addr_limit:		KERNEL_DS,					\
-    exec_domain:	&default_exec_domain,				\
     lock_depth:		-1,						\
     __nice:		DEF_USER_NICE,					\
     policy:		SCHED_OTHER,					\
diff --git a/include/linux/input.h b/include/linux/input.h
index 3f961ae..7ebdaaa 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -2,11 +2,9 @@
 #define _INPUT_H
 
 /*
- * $Id: input.h,v 1.34 2001/05/28 09:06:44 vojtech Exp $
+ * $Id: input.h,v 1.57 2002/01/02 11:59:56 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -17,7 +15,7 @@
  *
  * 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
+ * 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
@@ -25,8 +23,8 @@
  * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #ifdef __KERNEL__
@@ -64,17 +62,20 @@
 #define EVIOCSREP		_IOW('E', 0x03, int[2])			/* get repeat settings */
 #define EVIOCGKEYCODE		_IOR('E', 0x04, int[2])			/* get keycode */
 #define EVIOCSKEYCODE		_IOW('E', 0x04, int[2])			/* set keycode */
-#define EVIOCGKEY		_IOR('E', 0x05, int[2])			/* get key value */
+
 #define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x06, len)		/* get device name */
-#define EVIOCGBUS		_IOR('E', 0x07, short[4])		/* get bus address */
+#define EVIOCGPHYS(len)		_IOC(_IOC_READ, 'E', 0x07, len)		/* get physical location */
+#define EVIOCGUNIQ(len)		_IOC(_IOC_READ, 'E', 0x08, len)		/* get unique identifier */
+
+#define EVIOCGKEY(len)		_IOC(_IOC_READ, 'E', 0x18, len)		/* get global keystate */
+#define EVIOCGLED(len)		_IOC(_IOC_READ, 'E', 0x19, len)		/* get all LEDs */
+#define EVIOCGSND(len)		_IOC(_IOC_READ, 'E', 0x1a, len)		/* get all sounds status */
 
 #define EVIOCGBIT(ev,len)	_IOC(_IOC_READ, 'E', 0x20 + ev, len)	/* get event bits */
 #define EVIOCGABS(abs)		_IOR('E', 0x40 + abs, int[5])		/* get abs value/limits */
 
 #define EVIOCSFF		_IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))	/* send a force effect to a force feedback device */
 #define EVIOCRMFF		_IOW('E', 0x81, int)			/* Erase a force effect */
-#define EVIOCSGAIN		_IOW('E', 0x82, unsigned short)		/* Set overall gain */
-#define EVIOCSAUTOCENTER	_IOW('E', 0x83, unsigned short)		/* Enable or disable auto-centering */
 #define EVIOCGEFFECTS		_IOR('E', 0x84, int)			/* Report number of effects playable at the same time */
 
 /*
@@ -90,6 +91,8 @@
 #define EV_SND			0x12
 #define EV_REP			0x14
 #define EV_FF			0x15
+#define EV_PWR			0x16
+#define EV_FF_STATUS		0x17
 #define EV_MAX			0x1f
 
 /*
@@ -304,8 +307,23 @@
 #define KEY_PROG4		203
 #define KEY_SUSPEND		205
 #define KEY_CLOSE		206
+#define KEY_PLAY		207
+#define KEY_FASTFORWARD		208
+#define KEY_BASSBOOST		209
+#define KEY_PRINT		210
+#define KEY_HP			211
+#define KEY_CAMERA		212
+#define KEY_SOUND		213
+#define KEY_QUESTION		214
+#define KEY_EMAIL		215
+#define KEY_CHAT		216
+#define KEY_SEARCH		217
+#define KEY_CONNECT		218
+#define KEY_FINANCE		219
+#define KEY_SPORT		220
+#define KEY_SHOP		221
 
-#define KEY_UNKNOWN		220
+#define KEY_UNKNOWN		240
 
 #define BTN_MISC		0x100
 #define BTN_0			0x100
@@ -415,14 +433,16 @@
 #define ABS_DISTANCE		0x19
 #define ABS_TILT_X		0x1a
 #define ABS_TILT_Y		0x1b
-#define ABS_MISC		0x1c
-#define ABS_MAX			0x1f
+#define ABS_VOLUME		0x20
+#define ABS_MISC		0x28
+#define ABS_MAX			0x3f
 
 /*
  * Misc events
  */
 
 #define MSC_SERIAL		0x00
+#define MSC_PULSELED		0x01
 #define MSC_MAX			0x07
 
 /*
@@ -468,6 +488,7 @@
 #define BUS_PCI			0x01
 #define BUS_ISAPNP		0x02
 #define BUS_USB			0x03
+#define BUS_HIL			0x04
 
 #define BUS_ISA			0x10
 #define BUS_I8042		0x11
@@ -480,32 +501,42 @@
 #define BUS_I2C			0x18
 
 /*
+ * Values describing the status of an effect
+ */
+#define FF_STATUS_STOPPED	0x00
+#define FF_STATUS_PLAYING	0x01
+#define FF_STATUS_MAX		0x01
+
+/*
  * Structures used in ioctls to upload effects to a device
  * The first structures are not passed directly by using ioctls.
  * They are sub-structures of the actually sent structure (called ff_effect)
+ *
+ * Ranges:
+ *  0 <= __u16 <= 65535
+ *  -32767 <= __s16 <= +32767     ! Not -32768 for lower bound !
  */
 
 struct ff_replay {
-	__u16 length;		/* Duration of an effect */
+	__u16 length;		/* Duration of an effect in ms. All other times are also expressed in ms */
 	__u16 delay;		/* Time to wait before to start playing an effect */
 };
 
 struct ff_trigger {
 	__u16 button;		/* Number of button triggering an effect */
-	__u16 interval;		/* Time to wait before an effect can be re-triggered */
+	__u16 interval;		/* Time to wait before an effect can be re-triggered (ms) */
 };
 
 struct ff_shape {
-	__u16 attack_length;	/* Duration of attack */
-	__s16 attack_level;	/* Level at beginning of attack */
-	__u16 fade_length;	/* Duration of fade */
-	__s16 fade_level;	/* Level at end of fade */
+	__u16 attack_length;	/* Duration of attack (ms) */
+	__u16 attack_level;	/* Level at beginning of attack */
+	__u16 fade_length;	/* Duration of fade (ms) */
+	__u16 fade_level;	/* Level at end of fade */
 };
 
 /* FF_CONSTANT */
 struct ff_constant_effect {
-	__s16 level;		/* Strength of effect */
-	__u16 direction;	/* Direction of effect (see periodic effects) */
+	__s16 level;		/* Strength of effect. Negative values are OK */
 	struct ff_shape shape;
 };
 
@@ -514,12 +545,13 @@
 /* Axis along which effect must be created. If null, the field named direction
  * is used
  * It is a bit array (ie to enable axes X and Y, use BIT(ABS_X) | BIT(ABS_Y)
+ * It overrides the value of ff_effect::direction, which is used only if
+ * axis == 0
  */
 	__u16 axis;
-	__u16 direction;
 
-	__s16 right_saturation; /* Max level when joystick is on the right */
-	__s16 left_saturation;  /* Max level when joystick in on the left */
+	__u16 right_saturation; /* Max level when joystick is on the right */
+	__u16 left_saturation;	/* Max level when joystick in on the left */
 
 	__s16 right_coeff;	/* Indicates how fast the force grows when the
 				   joystick moves to the right */
@@ -533,12 +565,10 @@
 /* FF_PERIODIC */
 struct ff_periodic_effect {
 	__u16 waveform;		/* Kind of wave (sine, square...) */
-	__u16 period;
+	__u16 period;		/* in ms */
 	__s16 magnitude;	/* Peak value */
 	__s16 offset;		/* Mean value of wave (roughly) */
 	__u16 phase;		/* 'Horizontal' shift */
-	__u16 direction;	/* Direction. 0 deg -> 0x0000
-					     90 deg -> 0x4000 */
 
 	struct ff_shape shape;
 };
@@ -549,10 +579,17 @@
 struct ff_effect {
 	__u16 type;
 /* Following field denotes the unique id assigned to an effect.
- * It is set by the driver.
+ * If user sets if to -1, a new effect is created, and its id is returned in the same field
+ * Else, the user sets it to the effect id it wants to update.
  */
 	__s16 id;
 
+	__u16 direction;	/* Direction. 0 deg -> 0x0000 (down)
+					     90 deg -> 0x4000 (left)
+					    180 deg -> 0x8000 (up)
+					    270 deg -> 0xC000 (right)
+				*/
+
 	struct ff_trigger trigger;
 	struct ff_replay replay;
 
@@ -564,7 +601,7 @@
 };
 
 /*
- * Buttons that can trigger effects.  Use for example FF_BTN(BTN_TRIGGER) to
+ * Buttons that can trigger effects. Use for example FF_BTN(BTN_TRIGGER) to
  * access the bitmap.
  */
 
@@ -625,8 +662,11 @@
 
 	void *private;
 
-	int number;
 	char *name;
+	char *phys;
+	char *uniq;
+	int number;
+
 	unsigned short idbus;
 	unsigned short idvendor;
 	unsigned short idproduct;
@@ -649,6 +689,9 @@
 	unsigned int repeat_key;
 	struct timer_list timer;
 
+	struct pm_dev *pm_dev;
+	int state;
+
 	int abs[ABS_MAX + 1];
 	int rep[REP_MAX + 1];
 
@@ -661,8 +704,12 @@
 	int absfuzz[ABS_MAX + 1];
 	int absflat[ABS_MAX + 1];
 
+	int only_one_writer;
+
 	int (*open)(struct input_dev *dev);
 	void (*close)(struct input_dev *dev);
+	int (*accept)(struct input_dev *dev, struct file *file);
+	int (*flush)(struct input_dev *dev, struct file *file);
 	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 	int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
 	int (*erase_effect)(struct input_dev *dev, int effect_id);
@@ -671,16 +718,63 @@
 	struct input_dev *next;
 };
 
+/*
+ * Structure for hotplug & device<->driver matching.
+ */
+
+#define INPUT_DEVICE_ID_MATCH_BUS	1
+#define INPUT_DEVICE_ID_MATCH_VENDOR	2
+#define INPUT_DEVICE_ID_MATCH_PRODUCT	4
+#define INPUT_DEVICE_ID_MATCH_VERSION	8
+
+#define INPUT_DEVICE_ID_MATCH_EVBIT	0x010
+#define INPUT_DEVICE_ID_MATCH_KEYBIT	0x020
+#define INPUT_DEVICE_ID_MATCH_RELBIT	0x040
+#define INPUT_DEVICE_ID_MATCH_ABSBIT	0x080
+#define INPUT_DEVICE_ID_MATCH_MSCIT	0x100
+#define INPUT_DEVICE_ID_MATCH_LEDBIT	0x200
+#define INPUT_DEVICE_ID_MATCH_SNDBIT	0x400
+#define INPUT_DEVICE_ID_MATCH_FFBIT	0x800
+
+#define INPUT_DEVICE_ID_MATCH_DEVICE\
+	(INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT)
+#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\
+	(INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION)
+
+struct input_device_id {
+
+	unsigned long flags;
+
+	unsigned short idbus;
+	unsigned short idvendor;
+	unsigned short idproduct;
+	unsigned short idversion;
+
+	unsigned long evbit[NBITS(EV_MAX)];
+	unsigned long keybit[NBITS(KEY_MAX)];
+	unsigned long relbit[NBITS(REL_MAX)];
+	unsigned long absbit[NBITS(ABS_MAX)];
+	unsigned long mscbit[NBITS(MSC_MAX)];
+	unsigned long ledbit[NBITS(LED_MAX)];
+	unsigned long sndbit[NBITS(SND_MAX)];
+	unsigned long ffbit[NBITS(FF_MAX)];
+
+	unsigned long driver_info;
+};
+
 struct input_handler {
 
 	void *private;
 
 	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-	struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev);
+	struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
 	void (*disconnect)(struct input_handle *handle);
 
 	struct file_operations *fops;
 	int minor;
+	char *name;
+
+	struct input_device_id *id_table;
 
 	struct input_handle *handle;
 	struct input_handler *next;
@@ -691,6 +785,7 @@
 	void *private;
 
 	int open;
+	char *name;
 
 	struct input_dev *dev;
 	struct input_handler *handler;
@@ -708,6 +803,9 @@
 int input_open_device(struct input_handle *);
 void input_close_device(struct input_handle *);
 
+int input_accept_process(struct input_handle *handle, struct file *file);
+int input_flush_device(struct input_handle* handle, struct file* file);
+
 devfs_handle_t input_register_minor(char *name, int minor, int minor_base);
 void input_unregister_minor(devfs_handle_t handle);
 
@@ -716,6 +814,8 @@
 #define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))
 #define input_report_rel(a,b,c) input_event(a, EV_REL, b, c)
 #define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c)
+#define input_report_ff(a,b,c)	input_event(a, EV_FF, b, c)
+#define input_report_ff_status(a,b,c)	input_event(a, EV_FF_STATUS, b, c)
 
 #endif
 #endif
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index 0f285d5..0dd1c21 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -228,7 +228,6 @@
 
 /* linux/fs/ncpfs/inode.c */
 int ncp_notify_change(struct dentry *, struct iattr *);
-struct super_block *ncp_read_super(struct super_block *, void *, int);
 struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *);
 void ncp_update_inode(struct inode *, struct ncp_entry_info *);
 void ncp_update_inode2(struct inode *, struct ncp_entry_info *);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 8cefa88..ab9305b 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -103,8 +103,8 @@
 	void		*data;
 
 	unsigned long	 flags;
-	int		 state;
-	int		 prev_state;
+	unsigned long	 state;
+	unsigned long	 prev_state;
 
 	struct list_head entry;
 };
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 5d3f7b0..78a5834 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -13,6 +13,7 @@
 #include <linux/times.h>
 #include <linux/timex.h>
 #include <linux/rbtree.h>
+#include <linux/thread_info.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -229,37 +230,15 @@
 
 typedef struct prio_array prio_array_t;
 
-/* this struct must occupy one 32-bit chunk so that is can be read in one go */
-struct task_work {
-	__s8	need_resched;
-	__u8	syscall_trace;	/* count of syscall interceptors */
-	__u8	sigpending;
-	__u8	notify_resume;	/* request for notification on
-				   userspace execution resumption */
-} __attribute__((packed));
-
 struct task_struct {
-	/*
-	 * offsets of these are hardcoded elsewhere - touch with care
-	 */
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
+	struct thread_info *thread_info;
+	atomic_t usage;
 	unsigned long flags;	/* per process flags, defined below */
-	volatile struct task_work work;
-
-	mm_segment_t addr_limit;	/* thread address space:
-					 	0-0xBFFFFFFF for user-thead
-						0-0xFFFFFFFF for kernel-thread
-					 */
-	struct exec_domain *exec_domain;
-	long __pad;
 	unsigned long ptrace;
 
 	int lock_depth;		/* Lock depth */
 
-	/*
-	 * offset 32 begins here on 32-bit platforms.
-	 */
-	unsigned int cpu;
 	int prio;
 	long __nice;
 	list_t run_list;
@@ -368,6 +347,11 @@
 	void *journal_info;
 };
 
+extern void __put_task_struct(struct task_struct *tsk);
+#define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0)
+#define put_task_struct(tsk) \
+do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
+
 /*
  * Per process flags
  */
@@ -384,17 +368,14 @@
 #define PF_FREE_PAGES	0x00002000	/* per process page freeing */
 #define PF_NOIO		0x00004000	/* avoid generating further I/O */
 
-#define PF_USEDFPU	0x00100000	/* task used FPU this quantum (SMP) */
-
 /*
  * Ptrace flags
  */
 
 #define PT_PTRACED	0x00000001
-#define PT_SYSCALLTRACE	0x00000002	/* T if syscall_trace is +1 for ptrace() */
-#define PT_DTRACE	0x00000004	/* delayed trace (used on m68k, i386) */
-#define PT_TRACESYSGOOD	0x00000008
-#define PT_PTRACE_CAP	0x00000010	/* ptracer can follow suid-exec */
+#define PT_DTRACE	0x00000002	/* delayed trace (used on m68k, i386) */
+#define PT_TRACESYSGOOD	0x00000004
+#define PT_PTRACE_CAP	0x00000008	/* ptracer can follow suid-exec */
 
 /*
  * Limit the stack by to some sane default: root can always
@@ -470,16 +451,17 @@
  */
 extern struct exec_domain	default_exec_domain;
 
-#ifndef INIT_TASK_SIZE
-# define INIT_TASK_SIZE	2048*sizeof(long)
+#ifndef INIT_THREAD_SIZE
+# define INIT_THREAD_SIZE	2048*sizeof(long)
 #endif
 
-union task_union {
-	struct task_struct task;
-	unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
+union thread_union {
+	struct thread_info thread_info;
+	unsigned long stack[INIT_THREAD_SIZE/sizeof(long)];
 };
 
-extern union task_union init_task_union;
+extern union thread_union init_thread_union;
+extern struct task_struct init_task;
 
 extern struct   mm_struct init_mm;
 extern struct task_struct *init_tasks[NR_CPUS];
@@ -584,22 +566,6 @@
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
 
-static inline int signal_pending(struct task_struct *p)
-{
-	return (p->work.sigpending != 0);
-}
-  
-static inline int need_resched(void)
-{
-	return unlikely(current->work.need_resched != 0);
-}
-
-static inline void cond_resched(void)
-{
-	if (need_resched())
-		schedule();
-}
-
 /*
  * Re-calculate pending state from the set of locally pending
  * signals, globally pending signals, and blocked signals.
@@ -630,15 +596,6 @@
 	return ready !=	0;
 }
 
-/* Reevaluate whether the task has signals pending delivery.
-   This is required every time the blocked sigset_t changes.
-   All callers should have t->sigmask_lock.  */
-
-static inline void recalc_sigpending(struct task_struct *t)
-{
-	t->work.sigpending = has_pending_signals(&t->pending.signal, &t->blocked);
-}
-
 /* True if we are on the alternate signal stack.  */
 
 static inline int on_sig_stack(unsigned long sp)
@@ -888,6 +845,72 @@
 	return res;
 }
 
+/* set thread flags in other task's structures
+ * - see asm/thread_info.h for TIF_xxxx flags available
+ */
+static inline void set_tsk_thread_flag(struct task_struct *tsk, int flag)
+{
+	set_ti_thread_flag(tsk->thread_info,flag);
+}
+
+static inline void clear_tsk_thread_flag(struct task_struct *tsk, int flag)
+{
+	clear_ti_thread_flag(tsk->thread_info,flag);
+}
+
+static inline int test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag)
+{
+	return test_and_set_ti_thread_flag(tsk->thread_info,flag);
+}
+
+static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag)
+{
+	return test_and_clear_ti_thread_flag(tsk->thread_info,flag);
+}
+
+static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag)
+{
+	return test_ti_thread_flag(tsk->thread_info,flag);
+}
+
+static inline void set_tsk_need_resched(struct task_struct *tsk)
+{
+	set_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
+}
+
+static inline void clear_tsk_need_resched(struct task_struct *tsk)
+{
+	clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
+}
+
+static inline int signal_pending(struct task_struct *p)
+{
+	return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING));
+}
+  
+static inline int need_resched(void)
+{
+	return unlikely(test_thread_flag(TIF_NEED_RESCHED));
+}
+
+static inline void cond_resched(void)
+{
+	if (need_resched())
+		schedule();
+}
+
+/* Reevaluate whether the task has signals pending delivery.
+   This is required every time the blocked sigset_t changes.
+   Athread cathreaders should have t->sigmask_lock.  */
+
+static inline void recalc_sigpending(struct task_struct *t)
+{
+	if (has_pending_signals(&t->pending.signal, &t->blocked))
+		set_thread_flag(TIF_SIGPENDING);
+	else
+		clear_thread_flag(TIF_SIGPENDING);
+}
+
 #endif /* __KERNEL__ */
 
 #endif
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 3619a86..fae3602 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -2,31 +2,29 @@
 #define _SERIO_H
 
 /*
- * $Id: serio.h,v 1.11 2001/05/29 02:58:50 jsimmons Exp $
+ * $Id: serio.h,v 1.21 2001/12/19 05:15:21 skids Exp $
  *
- * Copyright (C) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
+ * Copyright (C) 1999-2001 Vojtech Pavlik
  */
 
 /*
  * 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 
+ * 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, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 /*
@@ -42,23 +40,31 @@
 
 	void *private;
 	void *driver;
+	char *name;
+	char *phys;
+	int number;
+
+	unsigned short idbus;
+	unsigned short idvendor;
+	unsigned short idproduct;
+	unsigned short idversion;
 
 	unsigned long type;
-	int number;
 
 	int (*write)(struct serio *, unsigned char);
 	int (*open)(struct serio *);
 	void (*close)(struct serio *);
 
 	struct serio_dev *dev;
-
 	struct serio *next;
 };
 
 struct serio_dev {
 
 	void *private;
+	char *name;
 
+	void (*write_wakeup)(struct serio *);
 	void (*interrupt)(struct serio *, unsigned char, unsigned int);
 	void (*connect)(struct serio *, struct serio_dev *dev);
 	void (*disconnect)(struct serio *);
@@ -80,6 +86,13 @@
 	return serio->write(serio, data);
 }
 
+static __inline__ void serio_dev_write_wakeup(struct serio *serio)
+{
+	if (serio->dev && serio->dev->write_wakeup) {
+		serio->dev->write_wakeup(serio);
+	}
+}
+
 #define SERIO_TIMEOUT	1
 #define SERIO_PARITY	2
 
@@ -87,6 +100,7 @@
 #define SERIO_XT	0x00000000UL
 #define SERIO_8042	0x01000000UL
 #define SERIO_RS232	0x02000000UL
+#define SERIO_HIL_MLC	0x03000000UL
 
 #define SERIO_PROTO	0xFFUL
 #define SERIO_MSC	0x01
@@ -108,6 +122,9 @@
 #define SERIO_STOWAWAY	0x20
 #define SERIO_H3600	0x21
 #define SERIO_PS2SER	0x22
+#define SERIO_TWIDKBD	0x23
+#define SERIO_TWIDJOY	0x24
+#define SERIO_HIL	0x25
 
 #define SERIO_ID	0xff00UL
 #define SERIO_EXTRA	0xff0000UL
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
new file mode 100644
index 0000000..9261863
--- /dev/null
+++ b/include/linux/thread_info.h
@@ -0,0 +1,82 @@
+/* thread_info.h: common low-level thread information accessors
+ *
+ * Copyright (C) 2002  David Howells (dhowells@redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds
+ */
+
+#ifndef _LINUX_THREAD_INFO_H
+#define _LINUX_THREAD_INFO_H
+
+#include <asm/thread_info.h>
+#include <asm/bitops.h>
+
+#ifdef __KERNEL__
+
+/*
+ * flag set/clear/test wrappers
+ * - pass TIF_xxxx constants to these functions
+ */
+
+static inline void set_thread_flag(int flag)
+{
+	set_bit(flag,&current_thread_info()->flags);
+}
+
+static inline void clear_thread_flag(int flag)
+{
+	clear_bit(flag,&current_thread_info()->flags);
+}
+
+static inline int test_and_set_thread_flag(int flag)
+{
+	return test_and_set_bit(flag,&current_thread_info()->flags);
+}
+
+static inline int test_and_clear_thread_flag(int flag)
+{
+	return test_and_clear_bit(flag,&current_thread_info()->flags);
+}
+
+static inline int test_thread_flag(int flag)
+{
+	return test_bit(flag,&current_thread_info()->flags);
+}
+
+static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
+{
+	set_bit(flag,&ti->flags);
+}
+
+static inline void clear_ti_thread_flag(struct thread_info *ti, int flag)
+{
+	clear_bit(flag,&ti->flags);
+}
+
+static inline int test_and_set_ti_thread_flag(struct thread_info *ti, int flag)
+{
+	return test_and_set_bit(flag,&ti->flags);
+}
+
+static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag)
+{
+	return test_and_clear_bit(flag,&ti->flags);
+}
+
+static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
+{
+	return test_bit(flag,&ti->flags);
+}
+
+static inline void set_need_resched(void)
+{
+	set_thread_flag(TIF_NEED_RESCHED);
+}
+
+static inline void clear_need_resched(void)
+{
+	clear_thread_flag(TIF_NEED_RESCHED);
+}
+
+#endif
+
+#endif /* _LINUX_THREAD_INFO_H */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index d598c72..b577fce 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1,6 +1,8 @@
 #ifndef __LINUX_USB_H
 #define __LINUX_USB_H
 
+#include <linux/device.h>
+
 /* USB constants */
 
 /*
@@ -260,6 +262,7 @@
 	int max_altsetting;             /* total memory allocated */
  
 	struct usb_driver *driver;	/* driver */
+	struct device dev;		/* interface specific device info */
 	void *private_data;
 };
 
@@ -945,6 +948,7 @@
 extern void usb_free_bus(struct usb_bus *);
 extern void usb_register_bus(struct usb_bus *);
 extern void usb_deregister_bus(struct usb_bus *);
+extern int usb_register_root_hub(struct usb_device *usb_dev, struct device *parent_dev);
 
 extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
 extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
@@ -1041,6 +1045,8 @@
 	struct usb_device *parent;
 	struct usb_bus *bus;		/* Bus we're part of */
 
+	struct device dev;		/* Generic device interface */
+
 	struct usb_device_descriptor descriptor;/* Descriptor */
 	struct usb_config_descriptor *config;	/* All of the configs */
 	struct usb_config_descriptor *actconfig;/* the active configuration */
diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c
index fc2c885..7d5ea35 100644
--- a/kernel/exec_domain.c
+++ b/kernel/exec_domain.c
@@ -67,8 +67,8 @@
 	}
 	set_personality(pers);
 
-	if (current->exec_domain->handler != default_handler)
-		current->exec_domain->handler(segment, regp);
+	if (current_thread_info()->exec_domain->handler != default_handler)
+		current_thread_info()->exec_domain->handler(segment, regp);
 	else
 		send_sig(SIGSEGV, current, 1);
 }
@@ -162,7 +162,7 @@
 	struct exec_domain	*ep, *oep;
 
 	ep = lookup_exec_domain(personality);
-	if (ep == current->exec_domain) {
+	if (ep == current_thread_info()->exec_domain) {
 		current->personality = personality;
 		return 0;
 	}
@@ -190,8 +190,8 @@
 	 */
 
 	current->personality = personality;
-	oep = current->exec_domain;
-	current->exec_domain = ep;
+	oep = current_thread_info()->exec_domain;
+	current_thread_info()->exec_domain = ep;
 	set_fs_altroot();
 
 	put_exec_domain(oep);
diff --git a/kernel/exit.c b/kernel/exit.c
index 429fd29..6b5a7cb 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -65,7 +65,7 @@
 	__restore_flags(flags);
 
 	p->pid = 0;
-	free_task_struct(p);
+	put_task_struct(p);
 }
 
 /*
@@ -529,7 +529,7 @@
 	if (current->leader)
 		disassociate_ctty(1);
 
-	put_exec_domain(tsk->exec_domain);
+	put_exec_domain(tsk->thread_info->exec_domain);
 	if (tsk->binfmt && tsk->binfmt->module)
 		__MOD_DEC_USE_COUNT(tsk->binfmt->module);
 
diff --git a/kernel/fork.c b/kernel/fork.c
index bfbae1b..3e49ad5 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -28,6 +28,8 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
+static kmem_cache_t *task_struct_cachep;
+
 /* The idle threads do not count.. */
 int nr_threads;
 
@@ -70,6 +72,14 @@
 
 void __init fork_init(unsigned long mempages)
 {
+	/* create a slab on which task_structs can be allocated */
+	task_struct_cachep =
+		kmem_cache_create("task_struct",
+				  sizeof(struct task_struct),0,
+				  SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!task_struct_cachep)
+		panic("fork_init(): cannot create task_struct SLAB cache");
+
 	/*
 	 * The default maximum number of threads is set to a safe
 	 * value: the thread structures can take up at most half
@@ -81,6 +91,35 @@
 	init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
 }
 
+struct task_struct *dup_task_struct(struct task_struct *orig)
+{
+	struct task_struct *tsk;
+	struct thread_info *ti;
+
+	ti = alloc_thread_info();
+	if (!ti) return NULL;
+
+	tsk = kmem_cache_alloc(task_struct_cachep,GFP_ATOMIC);
+	if (!tsk) {
+		free_thread_info(ti);
+		return NULL;
+	}
+
+	*ti = *orig->thread_info;
+	*tsk = *orig;
+	tsk->thread_info = ti;
+	ti->task = tsk;
+	atomic_set(&tsk->usage,1);
+
+	return tsk;
+}
+
+void __put_task_struct(struct task_struct *tsk)
+{
+	free_thread_info(tsk->thread_info);
+	kmem_cache_free(task_struct_cachep,tsk);
+}
+
 /* Protects next_safe and last_pid. */
 spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;
 
@@ -546,7 +585,7 @@
 {
 	unsigned long new_flags = p->flags;
 
-	new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU);
+	new_flags &= ~PF_SUPERPRIV;
 	new_flags |= PF_FORKNOEXEC;
 	if (!(clone_flags & CLONE_PTRACE))
 		p->ptrace = 0;
@@ -585,12 +624,10 @@
 	}
 
 	retval = -ENOMEM;
-	p = alloc_task_struct();
+	p = dup_task_struct(current);
 	if (!p)
 		goto fork_out;
 
-	*p = *current;
-
 	retval = -EAGAIN;
 	if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) {
 		if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE))
@@ -608,7 +645,7 @@
 	if (nr_threads >= max_threads)
 		goto bad_fork_cleanup_count;
 	
-	get_exec_domain(p->exec_domain);
+	get_exec_domain(p->thread_info->exec_domain);
 
 	if (p->binfmt && p->binfmt->module)
 		__MOD_INC_USE_COUNT(p->binfmt->module);
@@ -631,7 +668,7 @@
 	}
 	spin_lock_init(&p->alloc_lock);
 
-	p->work.sigpending = 0;
+	clear_tsk_thread_flag(p,TIF_SIGPENDING);
 	init_sigpending(&p->pending);
 
 	p->it_real_value = p->it_virt_value = p->it_prof_value = 0;
@@ -755,7 +792,7 @@
 		 * Let the child process run first, to avoid most of the
 		 * COW overhead when the child exec()s afterwards.
 		 */
-		current->work.need_resched = 1;
+		set_need_resched();
 
 fork_out:
 	return retval;
@@ -771,14 +808,14 @@
 bad_fork_cleanup_files:
 	exit_files(p); /* blocking */
 bad_fork_cleanup:
-	put_exec_domain(p->exec_domain);
+	put_exec_domain(p->thread_info->exec_domain);
 	if (p->binfmt && p->binfmt->module)
 		__MOD_DEC_USE_COUNT(p->binfmt->module);
 bad_fork_cleanup_count:
 	atomic_dec(&p->user->processes);
 	free_uid(p->user);
 bad_fork_free:
-	free_task_struct(p);
+	put_task_struct(p);
 	goto fork_out;
 }
 
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 4ff3e77..57e60f0 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -566,7 +566,8 @@
 
 /* init task, for moving kthread roots - ought to export a function ?? */
 
-EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(init_task);
+EXPORT_SYMBOL(init_thread_union);
 
 EXPORT_SYMBOL(tasklist_lock);
 EXPORT_SYMBOL(pidhash);
diff --git a/kernel/pm.c b/kernel/pm.c
index a33e7b2..0992b66 100644
--- a/kernel/pm.c
+++ b/kernel/pm.c
@@ -154,7 +154,7 @@
 int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
 {
 	int status = 0;
-	int prev_state, next_state;
+	unsigned long prev_state, next_state;
 
 	if (in_interrupt())
 		BUG();
@@ -163,7 +163,7 @@
 	case PM_SUSPEND:
 	case PM_RESUME:
 		prev_state = dev->state;
-		next_state = (int) data;
+		next_state = (unsigned long) data;
 		if (prev_state != next_state) {
 			if (dev->callback)
 				status = (*dev->callback)(dev, rqst, data);
diff --git a/kernel/signal.c b/kernel/signal.c
index d648cff..74d7835 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -23,7 +23,7 @@
 #define DEBUG_SIG 0
 
 #if DEBUG_SIG
-#define SIG_SLAB_DEBUG	(SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */)
+#define SIG_SLAB_DEBUG	(SLAB_RED_ZONE /* | SLAB_POISON */)
 #else
 #define SIG_SLAB_DEBUG	0
 #endif
@@ -105,7 +105,7 @@
 void
 flush_signals(struct task_struct *t)
 {
-	t->work.sigpending = 0;
+	clear_tsk_thread_flag(t,TIF_SIGPENDING);
 	flush_sigqueue(&t->pending);
 }
 
@@ -119,7 +119,7 @@
 		if (atomic_dec_and_test(&sig->count))
 			kmem_cache_free(sigact_cachep, sig);
 	}
-	tsk->work.sigpending = 0;
+	clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
 	flush_sigqueue(&tsk->pending);
 	spin_unlock_irq(&tsk->sigmask_lock);
 }
@@ -275,7 +275,7 @@
 		if (current->notifier) {
 			if (sigismember(current->notifier_mask, sig)) {
 				if (!(current->notifier)(current->notifier_data)) {
-					current->work.sigpending = 0;
+					clear_thread_flag(TIF_SIGPENDING);
 					return 0;
 				}
 			}
@@ -494,7 +494,7 @@
  */
 static inline void signal_wake_up(struct task_struct *t)
 {
-	t->work.sigpending = 1;
+	set_tsk_thread_flag(t,TIF_SIGPENDING);
 
 #ifdef CONFIG_SMP
 	/*
@@ -507,7 +507,7 @@
 	 * process of changing - but no harm is done by that
 	 * other than doing an extra (lightweight) IPI interrupt.
 	 */
-	if ((t->state == TASK_RUNNING) && (t->cpu != smp_processor_id()))
+	if ((t->state == TASK_RUNNING) && (t->thread_info->cpu != smp_processor_id()))
 		kick_if_running(t);
 #endif
 	if (t->state & TASK_INTERRUPTIBLE) {
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 6e32158..fb480e5 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -1109,7 +1109,7 @@
 	unsigned long flags;
 
 	while (all_tasks) {
-		current->work.sigpending = 0;
+		clear_thread_flag(TIF_SIGPENDING);
 		rpc_killall_tasks(NULL);
 		__rpc_schedule();
 		if (all_tasks) {
@@ -1183,7 +1183,7 @@
 	 * Usually rpciod will exit very quickly, so we
 	 * wait briefly before checking the process id.
 	 */
-	current->work.sigpending = 0;
+	clear_thread_flag(TIF_SIGPENDING);
 	yield();
 	/*
 	 * Display a message if we're going to wait longer.
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 3a65741..c7793be 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -185,7 +185,7 @@
 		progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
 
 	if (!port)
-		current->work.sigpending = 0;
+		clear_thread_flag(TIF_SIGPENDING);
 
 	for (i = 0; i < progp->pg_nvers; i++) {
 		if (progp->pg_vers[i] == NULL)