MN10300: Save frame pointer in thread_info struct rather than global var

Save the current exception frame pointer in the thread_info struct rather than
in a global variable as the latter makes SMP tricky, especially when preemption
is also enabled.

This also replaces __frame with current_frame() and rearranges header file
inclusions to make it all compile.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com>
diff --git a/arch/mn10300/include/asm/frame.inc b/arch/mn10300/include/asm/frame.inc
index 406060e..2ee58e3 100644
--- a/arch/mn10300/include/asm/frame.inc
+++ b/arch/mn10300/include/asm/frame.inc
@@ -18,9 +18,7 @@
 #ifndef __ASM_OFFSETS_H__
 #include <asm/asm-offsets.h>
 #endif
-#ifdef CONFIG_SMP
-#include <proc/smp-regs.h>
-#endif
+#include <asm/thread_info.h>
 
 #define pi break
 
@@ -40,27 +38,15 @@
 	movm	[d2,d3,a2,a3,exreg0,exreg1,exother],(sp)
 	mov	sp,fp				# FRAME pointer in A3
 	add	-12,sp				# allow for calls to be made
-#ifdef CONFIG_SMP
-#ifdef CONFIG_PREEMPT /* FIXME */
-	mov	epsw,d2
-	and	~EPSW_IE,epsw
-#endif
-	mov	(CPUID),a0
-	add	a0,a0
-	add	a0,a0
-	mov	(___frame,a0),a1
-	mov	a1,(REG_NEXT,fp)
-	mov	fp,(___frame,a0)
-#ifdef CONFIG_PREEMPT /* FIXME */
-	mov	d2,epsw
-#endif
-#else  /* CONFIG_SMP */
-	mov	(__frame),a1
-	mov	a1,(REG_NEXT,fp)
-	mov	fp,(__frame)
-#endif /* CONFIG_SMP */
 
-	and	~EPSW_FE,epsw			# disable the FPU inside the kernel
+	# push the exception frame onto the front of the list
+	GET_THREAD_INFO a1
+	mov	(TI_frame,a1),a0
+	mov	a0,(REG_NEXT,fp)
+	mov	fp,(TI_frame,a1)
+
+	# disable the FPU inside the kernel
+	and	~EPSW_FE,epsw
 
 	# we may be holding current in E2
 #ifdef CONFIG_MN10300_CURRENT_IN_E2
@@ -76,27 +62,11 @@
 .macro RESTORE_ALL
 	# peel back the stack to the calling frame
 	# - this permits execve() to discard extra frames due to kernel syscalls
-#ifdef  CONFIG_SMP
-#ifdef CONFIG_PREEMPT /* FIXME */
-	mov	epsw,d2
-	and	~EPSW_IE,epsw
-#endif
-	mov	(CPUID),a0
-	add	a0,a0
-	add	a0,a0
-	mov	(___frame,a0),fp
+	GET_THREAD_INFO a0
+	mov	(TI_frame,a0),fp
 	mov	fp,sp
-	mov	(REG_NEXT,fp),d0                # userspace has regs->next == 0
-	mov	d0,(___frame,a0)
-#ifdef CONFIG_PREEMPT /* FIXME */
-	mov	d2,epsw
-#endif
-#else   /* CONFIG_SMP */
-	mov	(__frame),fp
-	mov	fp,sp
-	mov	(REG_NEXT,fp),d0                # userspace has regs->next == 0
-	mov	d0,(__frame)
-#endif  /* CONFIG_SMP */
+	mov	(REG_NEXT,fp),d0
+	mov	d0,(TI_frame,a0)                # userspace has regs->next == 0
 
 #ifndef CONFIG_MN10300_USING_JTAG
 	mov	(REG_EPSW,fp),d0
diff --git a/arch/mn10300/include/asm/irq_regs.h b/arch/mn10300/include/asm/irq_regs.h
index a848cd2..97d0cb5 100644
--- a/arch/mn10300/include/asm/irq_regs.h
+++ b/arch/mn10300/include/asm/irq_regs.h
@@ -18,7 +18,11 @@
 #define ARCH_HAS_OWN_IRQ_REGS
 
 #ifndef __ASSEMBLY__
-#define get_irq_regs() (__frame)
+static inline __attribute__((const))
+struct pt_regs *get_irq_regs(void)
+{
+	return current_frame();
+}
 #endif
 
 #endif /* _ASM_IRQ_REGS_H */
diff --git a/arch/mn10300/include/asm/pgalloc.h b/arch/mn10300/include/asm/pgalloc.h
index a19f113..146bacf 100644
--- a/arch/mn10300/include/asm/pgalloc.h
+++ b/arch/mn10300/include/asm/pgalloc.h
@@ -11,7 +11,6 @@
 #ifndef _ASM_PGALLOC_H
 #define _ASM_PGALLOC_H
 
-#include <asm/processor.h>
 #include <asm/page.h>
 #include <linux/threads.h>
 #include <linux/mm.h>		/* for struct page */
diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h
index 75c422a..4c1b5cc 100644
--- a/arch/mn10300/include/asm/processor.h
+++ b/arch/mn10300/include/asm/processor.h
@@ -13,10 +13,13 @@
 #ifndef _ASM_PROCESSOR_H
 #define _ASM_PROCESSOR_H
 
+#include <linux/threads.h>
+#include <linux/thread_info.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/cpu-regs.h>
-#include <linux/threads.h>
+#include <asm/uaccess.h>
+#include <asm/current.h>
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -83,10 +86,6 @@
  */
 #define TASK_UNMAPPED_BASE	0x30000000
 
-typedef struct {
-	unsigned long	seg;
-} mm_segment_t;
-
 struct fpu_state_struct {
 	unsigned long	fs[32];		/* fpu registers */
 	unsigned long	fpcr;		/* fpu control register */
@@ -99,7 +98,6 @@
 	unsigned long		a3;		/* kernel FP */
 	unsigned long		wchan;
 	unsigned long		usp;
-	struct pt_regs		*frame;
 	unsigned long		fpu_flags;
 #define THREAD_USING_FPU	0x00000001	/* T if this task is using the FPU */
 #define THREAD_HAS_FPU		0x00000002	/* T if this task owns the FPU right now */
@@ -113,7 +111,6 @@
 	.sp	= 0,		\
 	.a3	= 0,		\
 	.wchan	= 0,		\
-	.frame	= NULL,		\
 }
 
 #define INIT_MMAP \
@@ -125,27 +122,20 @@
  * - need to discard the frame stacked by the kernel thread invoking the execve
  *   syscall (see RESTORE_ALL macro)
  */
-#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) /* FIXME */
-#define start_thread(regs, new_pc, new_sp) do {		\
-	int cpu;					\
-	preempt_disable();				\
-	cpu = CPUID;					\
-	set_fs(USER_DS);				\
-	___frame[cpu] = current->thread.uregs;		\
-	___frame[cpu]->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;\
-	___frame[cpu]->pc = new_pc;			\
-	___frame[cpu]->sp = new_sp;			\
-	preempt_enable();				\
-} while (0)
-#else  /* CONFIG_SMP && CONFIG_PREEMPT */
-#define start_thread(regs, new_pc, new_sp) do {		\
-	set_fs(USER_DS);				\
-	__frame = current->thread.uregs;		\
-	__frame->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;	\
-	__frame->pc = new_pc;				\
-	__frame->sp = new_sp;				\
-} while (0)
-#endif /* CONFIG_SMP && CONFIG_PREEMPT */
+static inline void start_thread(struct pt_regs *regs,
+				unsigned long new_pc, unsigned long new_sp)
+{
+	struct thread_info *ti = current_thread_info();
+	struct pt_regs *frame0;
+	set_fs(USER_DS);
+
+	frame0 = thread_info_to_uregs(ti);
+	frame0->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;
+	frame0->pc = new_pc;
+	frame0->sp = new_sp;
+	ti->frame = frame0;
+}
+
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
diff --git a/arch/mn10300/include/asm/ptrace.h b/arch/mn10300/include/asm/ptrace.h
index c2b77bd..b696181 100644
--- a/arch/mn10300/include/asm/ptrace.h
+++ b/arch/mn10300/include/asm/ptrace.h
@@ -86,12 +86,6 @@
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_SMP
-extern struct pt_regs *___frame[];	/* current frame pointer */
-#else
-extern struct pt_regs *__frame;		/* current frame pointer */
-#endif
-
 #define user_mode(regs)			(((regs)->epsw & EPSW_nSL) == EPSW_nSL)
 #define instruction_pointer(regs)	((regs)->pc)
 #define user_stack_pointer(regs)	((regs)->sp)
diff --git a/arch/mn10300/include/asm/smp.h b/arch/mn10300/include/asm/smp.h
index b8585b4..a3930e4 100644
--- a/arch/mn10300/include/asm/smp.h
+++ b/arch/mn10300/include/asm/smp.h
@@ -93,19 +93,6 @@
 extern void __cpu_die(unsigned int cpu);
 #endif /* CONFIG_HOTPLUG_CPU */
 
-#ifdef CONFIG_PREEMPT /* FIXME */
-#define __frame					\
-	({					\
-		struct pt_regs *f;		\
-		preempt_disable();		\
-		f = ___frame[CPUID];		\
-		preempt_enable();		\
-		f;				\
-	})
-#else
-#define __frame ___frame[CPUID]
-#endif
-
 #endif /* __ASSEMBLY__ */
 #else /* CONFIG_SMP */
 #ifndef __ASSEMBLY__
diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h
index 2001cb6..aa07a4a 100644
--- a/arch/mn10300/include/asm/thread_info.h
+++ b/arch/mn10300/include/asm/thread_info.h
@@ -16,10 +16,6 @@
 
 #include <asm/page.h>
 
-#ifndef __ASSEMBLY__
-#include <asm/processor.h>
-#endif
-
 #define PREEMPT_ACTIVE		0x10000000
 
 #ifdef CONFIG_4KSTACKS
@@ -38,10 +34,14 @@
  *   must also be changed
  */
 #ifndef __ASSEMBLY__
+typedef struct {
+	unsigned long	seg;
+} mm_segment_t;
 
 struct thread_info {
 	struct task_struct	*task;		/* main task structure */
 	struct exec_domain	*exec_domain;	/* execution domain */
+	struct pt_regs		*frame;		/* current exception frame */
 	unsigned long		flags;		/* low level flags */
 	__u32			cpu;		/* current CPU */
 	__s32			preempt_count;	/* 0 => preemptable, <0 => BUG */
@@ -55,6 +55,10 @@
 	__u8			supervisor_stack[0];
 };
 
+#define thread_info_to_uregs(ti)					\
+	((struct pt_regs *)						\
+	 ((unsigned long)ti + THREAD_SIZE - sizeof(struct pt_regs)))
+
 #else /* !__ASSEMBLY__ */
 
 #ifndef __ASM_OFFSETS_H__
@@ -102,6 +106,12 @@
 	return ti;
 }
 
+static inline __attribute__((const))
+struct pt_regs *current_frame(void)
+{
+	return current_thread_info()->frame;
+}
+
 /* how to get the current stack pointer from C */
 static inline unsigned long current_stack_pointer(void)
 {
diff --git a/arch/mn10300/include/asm/uaccess.h b/arch/mn10300/include/asm/uaccess.h
index 47e7951..679dee0 100644
--- a/arch/mn10300/include/asm/uaccess.h
+++ b/arch/mn10300/include/asm/uaccess.h
@@ -14,9 +14,8 @@
 /*
  * User space memory access functions
  */
-#include <linux/sched.h>
+#include <linux/thread_info.h>
 #include <asm/page.h>
-#include <asm/pgtable.h>
 #include <asm/errno.h>
 
 #define VERIFY_READ 0
@@ -29,7 +28,6 @@
  *
  * For historical reasons, these macros are grossly misnamed.
  */
-
 #define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
 
 #define KERNEL_XDS	MAKE_MM_SEG(0xBFFFFFFF)