alpha: switch to generic kernel_thread()

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 9944ded..7da9124 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -20,6 +20,7 @@
 	select GENERIC_CMOS_UPDATE
 	select GENERIC_STRNCPY_FROM_USER
 	select GENERIC_STRNLEN_USER
+	select GENERIC_KERNEL_THREAD
 	help
 	  The Alpha is a 64-bit general-purpose processor designed and
 	  marketed by the Digital Equipment Corporation of blessed memory,
diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h
index e37b887..6cb7fe8 100644
--- a/arch/alpha/include/asm/processor.h
+++ b/arch/alpha/include/asm/processor.h
@@ -49,9 +49,6 @@
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Create a kernel thread without removing it from tasklists.  */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
 unsigned long get_wchan(struct task_struct *p);
 
 #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 15fa821..89566b3 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -50,9 +50,6 @@
 EXPORT_SYMBOL(alpha_write_fp_reg);
 EXPORT_SYMBOL(alpha_write_fp_reg_s);
 
-/* entry.S */
-EXPORT_SYMBOL(kernel_thread);
-
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_tcpudp_magic);
 EXPORT_SYMBOL(ip_compute_csum);
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 61ff145..421dccf 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -609,59 +609,22 @@
 .end ret_from_fork
 
 /*
- * kernel_thread(fn, arg, clone_flags)
+ * ... and new kernel threads - here
  */
 	.align 4
-	.globl	kernel_thread
-	.ent	kernel_thread
-kernel_thread:
-	/* We can be called from a module.  */
-	ldgp	$gp, 0($27)
-	.prologue 1
-	subq	$sp, SP_OFF+6*8, $sp
-	br	$1, 2f		/* load start address */
-
-	/* We've now "returned" from a fake system call.  */
-	unop
-	blt	$0, 1f		/* error?  */
-	ldi	$1, 0x3fff
-	beq	$20, 1f		/* parent or child?  */
-
-	bic	$sp, $1, $8	/* in child.  */
-	jsr	$26, ($27)
+	.globl	ret_from_kernel_thread
+	.ent	ret_from_kernel_thread
+ret_from_kernel_thread:
+	mov	$17, $16
+	jsr	$26, schedule_tail
+	mov	$9, $27
+	mov	$10, $16
+	jsr	$26, ($9)
 	ldgp	$gp, 0($26)
 	mov	$0, $16
 	mov	$31, $26
 	jmp	$31, sys_exit
-
-1:	ret			/* in parent.  */
-
-	.align 4
-2:	/* Fake a system call stack frame, as we can't do system calls
-	   from kernel space.  Note that we store FN and ARG as they
-	   need to be set up in the child for the call.  Also store $8
-	   and $26 for use in the parent.  */
-	stq	$31, SP_OFF($sp)	/* ps */
-	stq	$1, SP_OFF+8($sp)	/* pc */
-	stq	$gp, SP_OFF+16($sp)	/* gp */
-	stq	$16, 136($sp)		/* $27; FN for child */
-	stq	$17, SP_OFF+24($sp)	/* $16; ARG for child */
-	stq	$8, 64($sp)		/* $8 */
-	stq	$26, 128($sp)		/* $26 */
-	/* Avoid the HAE being gratuitously wrong, to avoid restoring it.  */
-	ldq	$2, alpha_mv+HAE_CACHE
-	stq	$2, 152($sp)		/* HAE */
-
-	/* Shuffle FLAGS to the front; add CLONE_VM.  */
-	ldi	$1, CLONE_VM|CLONE_UNTRACED
-	or	$18, $1, $16
-	bsr	$26, sys_clone
-
-	/* We don't actually care for a3 success widgetry in the kernel.
-	   Not for positive errno values.  */
-	stq	$0, 0($sp)		/* $0 */
-	br	ret_to_kernel
-.end kernel_thread
+.end ret_from_kernel_thread
 
 
 /*
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 14547390..6b33ecd 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -259,33 +259,35 @@
 
 /*
  * Copy an alpha thread..
- *
- * Note the "stack_offset" stuff: when returning to kernel mode, we need
- * to have some extra stack-space for the kernel stack that still exists
- * after the "ret_from_fork".  When returning to user mode, we only want
- * the space needed by the syscall stack frame (ie "struct pt_regs").
- * Use the passed "regs" pointer to determine how much space we need
- * for a kernel fork().
  */
 
 int
 copy_thread(unsigned long clone_flags, unsigned long usp,
-	    unsigned long unused,
+	    unsigned long arg,
 	    struct task_struct * p, struct pt_regs * regs)
 {
 	extern void ret_from_fork(void);
+	extern void ret_from_kernel_thread(void);
 
 	struct thread_info *childti = task_thread_info(p);
-	struct pt_regs * childregs;
-	struct switch_stack * childstack, *stack;
-	unsigned long stack_offset, settls;
+	struct pt_regs *childregs = task_pt_regs(p);
+	struct switch_stack *childstack, *stack;
+	unsigned long settls;
 
-	stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
-	if (!(regs->ps & 8))
-		stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
-	childregs = (struct pt_regs *)
-	  (stack_offset + PAGE_SIZE + task_stack_page(p));
-		
+	childstack = ((struct switch_stack *) childregs) - 1;
+	if (unlikely(!regs)) {
+		/* kernel thread */
+		memset(childstack, 0,
+			sizeof(struct switch_stack) + sizeof(struct pt_regs));
+		childstack->r26 = (unsigned long) ret_from_kernel_thread;
+		childstack->r9 = usp;	/* function */
+		childstack->r10 = arg;
+		childregs->hae = alpha_mv.hae_cache,
+		childti->pcb.usp = 0;
+		childti->pcb.ksp = (unsigned long) childstack;
+		childti->pcb.flags = 1;	/* set FEN, clear everything else */
+		return 0;
+	}
 	*childregs = *regs;
 	settls = regs->r20;
 	childregs->r0 = 0;
@@ -293,7 +295,6 @@
 	childregs->r20 = 1;	/* OSF/1 has some strange fork() semantics.  */
 	regs->r20 = 0;
 	stack = ((struct switch_stack *) regs) - 1;
-	childstack = ((struct switch_stack *) childregs) - 1;
 	*childstack = *stack;
 	childstack->r26 = (unsigned long) ret_from_fork;
 	childti->pcb.usp = usp;