summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arch/sh/Kconfig.debug10
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c2
-rw-r--r--arch/sh/kernel/entry.S4
-rw-r--r--arch/sh/kernel/head.S5
-rw-r--r--arch/sh/kernel/irq.c153
-rw-r--r--arch/sh/kernel/traps.c18
-rw-r--r--arch/sh/kernel/vmlinux.lds.S1
-rw-r--r--include/asm-sh/irq.h9
-rw-r--r--include/asm-sh/thread_info.h12
9 files changed, 190 insertions, 24 deletions
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index f0188e626be0..48479e014dac 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -46,6 +46,16 @@ config DEBUG_STACK_USAGE
 
 	  This option will slow down process creation somewhat.
 
+config 4KSTACKS
+	bool "Use 4Kb for kernel stacks instead of 8Kb"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here the kernel will use a 4Kb stacksize for the
+	  kernel stack attached to each process/thread. This facilitates
+	  running more threads on a system and also reduces the pressure
+	  on the VM subsystem for higher order allocations. This option
+	  will also use IRQ stacks to compensate for the reduced stackspace.
+
 config KGDB
 	bool "Include KGDB kernel debugger"
 	select FRAME_POINTER
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 4c4fd4118d1a..f785822cd5de 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -190,6 +190,8 @@ void __init init_IRQ(void)
 	/* Perform the machine specific initialisation */
 	if (sh_mv.mv_init_irq != NULL)
 		sh_mv.mv_init_irq();
+
+	irq_ctx_init(smp_processor_id());
 }
 
 #if !defined(CONFIG_CPU_HAS_PINT_IRQ)
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
index fd5fe2349f20..fe8221855b28 100644
--- a/arch/sh/kernel/entry.S
+++ b/arch/sh/kernel/entry.S
@@ -716,8 +716,8 @@ ENTRY(handle_exception)
 	bt/s	1f		! It's a kernel to kernel transition.
 	 mov	r15, k0		! save original stack to k0
 	/* User space to kernel */
-	mov	#0x20, k1
-	shll8	k1		! k1 := 8192 (== THREAD_SIZE)
+	mov	#(THREAD_SIZE >> 8), k1
+	shll8	k1		! k1 := THREAD_SIZE
 	add	current, k1
 	mov	k1, r15		! change to kernel stack
 	!
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 3e7d00b7985a..f5f53d14f245 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -12,7 +12,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
-#include <asm/page.h>
 
 #ifdef CONFIG_CPU_SH4A
 #define SYNCO()		synco
@@ -69,8 +68,8 @@ ENTRY(_stext)
 	!
 	mov.l	2f, r0
 	mov	r0, r15		! Set initial r15 (stack pointer)
-	mov	#0x20, r1	!
-	shll8	r1		! r1 = 8192
+	mov	#(THREAD_SIZE >> 8), r1
+	shll8	r1		! r1 = THREAD_SIZE
 	sub	r1, r0		!
 	ldc	r0, r7_bank	! ... and initial thread_info
 
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 7066611aeb72..c7ebd6aec951 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -1,5 +1,4 @@
-/* $Id: irq.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $
- *
+/*
  * linux/arch/sh/kernel/irq.c
  *
  *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
@@ -7,13 +6,15 @@
  *
  * SuperH version:  Copyright (C) 1999  Niibe Yutaka
  */
-
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <linux/kernel_stat.h>
 #include <linux/seq_file.h>
 #include <asm/irq.h>
 #include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/thread_info.h>
 #include <asm/cpu/mmu_context.h>
 
 /*
@@ -60,11 +61,27 @@ unlock:
 }
 #endif
 
+#ifdef CONFIG_4KSTACKS
+/*
+ * per-CPU IRQ handling contexts (thread information and stack)
+ */
+union irq_ctx {
+	struct thread_info	tinfo;
+	u32			stack[THREAD_SIZE/sizeof(u32)];
+};
+
+static union irq_ctx *hardirq_ctx[NR_CPUS];
+static union irq_ctx *softirq_ctx[NR_CPUS];
+#endif
+
 asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
 		      unsigned long r6, unsigned long r7,
 		      struct pt_regs regs)
 {
 	int irq = r4;
+#ifdef CONFIG_4KSTACKS
+	union irq_ctx *curctx, *irqctx;
+#endif
 
 	irq_enter();
 
@@ -102,7 +119,135 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
 #endif
 
 	irq = irq_demux(irq);
-	__do_IRQ(irq, &regs);
+
+#ifdef CONFIG_4KSTACKS
+	curctx = (union irq_ctx *)current_thread_info();
+	irqctx = hardirq_ctx[smp_processor_id()];
+
+	/*
+	 * this is where we switch to the IRQ stack. However, if we are
+	 * already using the IRQ stack (because we interrupted a hardirq
+	 * handler) we can't do that and just have to keep using the
+	 * current stack (which is the irq stack already after all)
+	 */
+	if (curctx != irqctx) {
+		u32 *isp;
+
+		isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
+		irqctx->tinfo.task = curctx->tinfo.task;
+		irqctx->tinfo.previous_sp = current_stack_pointer;
+
+		__asm__ __volatile__ (
+			"mov	%0, r4		\n"
+			"mov	%1, r5		\n"
+			"mov	r15, r9		\n"
+			"jsr	@%2		\n"
+			/* swith to the irq stack */
+			" mov	%3, r15		\n"
+			/* restore the stack (ring zero) */
+			"mov	r9, r15		\n"
+			: /* no outputs */
+			: "r" (irq), "r" (&regs), "r" (__do_IRQ), "r" (isp)
+			/* XXX: A somewhat excessive clobber list? -PFM */
+			: "memory", "r0", "r1", "r2", "r3", "r4",
+			  "r5", "r6", "r7", "r8", "t", "pr"
+		);
+	} else
+#endif
+		__do_IRQ(irq, &regs);
+
 	irq_exit();
+
 	return 1;
 }
+
+#ifdef CONFIG_4KSTACKS
+/*
+ * These should really be __section__(".bss.page_aligned") as well, but
+ * gcc's 3.0 and earlier don't handle that correctly.
+ */
+static char softirq_stack[NR_CPUS * THREAD_SIZE]
+		__attribute__((__aligned__(THREAD_SIZE)));
+
+static char hardirq_stack[NR_CPUS * THREAD_SIZE]
+		__attribute__((__aligned__(THREAD_SIZE)));
+
+/*
+ * allocate per-cpu stacks for hardirq and for softirq processing
+ */
+void irq_ctx_init(int cpu)
+{
+	union irq_ctx *irqctx;
+
+	if (hardirq_ctx[cpu])
+		return;
+
+	irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE];
+	irqctx->tinfo.task		= NULL;
+	irqctx->tinfo.exec_domain	= NULL;
+	irqctx->tinfo.cpu		= cpu;
+	irqctx->tinfo.preempt_count	= HARDIRQ_OFFSET;
+	irqctx->tinfo.addr_limit	= MAKE_MM_SEG(0);
+
+	hardirq_ctx[cpu] = irqctx;
+
+	irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE];
+	irqctx->tinfo.task		= NULL;
+	irqctx->tinfo.exec_domain	= NULL;
+	irqctx->tinfo.cpu		= cpu;
+	irqctx->tinfo.preempt_count	= SOFTIRQ_OFFSET;
+	irqctx->tinfo.addr_limit	= MAKE_MM_SEG(0);
+
+	softirq_ctx[cpu] = irqctx;
+
+	printk("CPU %u irqstacks, hard=%p soft=%p\n",
+		cpu, hardirq_ctx[cpu], softirq_ctx[cpu]);
+}
+
+void irq_ctx_exit(int cpu)
+{
+	hardirq_ctx[cpu] = NULL;
+}
+
+extern asmlinkage void __do_softirq(void);
+
+asmlinkage void do_softirq(void)
+{
+	unsigned long flags;
+	struct thread_info *curctx;
+	union irq_ctx *irqctx;
+	u32 *isp;
+
+	if (in_interrupt())
+		return;
+
+	local_irq_save(flags);
+
+	if (local_softirq_pending()) {
+		curctx = current_thread_info();
+		irqctx = softirq_ctx[smp_processor_id()];
+		irqctx->tinfo.task = curctx->task;
+		irqctx->tinfo.previous_sp = current_stack_pointer;
+
+		/* build the stack frame on the softirq stack */
+		isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
+
+		__asm__ __volatile__ (
+			"mov	r15, r9		\n"
+			"jsr	@%0		\n"
+			/* switch to the softirq stack */
+			" mov	%1, r15		\n"
+			/* restore the thread stack */
+			"mov	r9, r15		\n"
+			: /* no outputs */
+			: "r" (__do_softirq), "r" (isp)
+			/* XXX: A somewhat excessive clobber list? -PFM */
+			: "memory", "r0", "r1", "r2", "r3", "r4",
+			  "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
+		);
+	}
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(do_softirq);
+#endif
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 95c810b3c97e..c2c597e09482 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -741,20 +741,12 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
 	unsigned long module_end = VMALLOC_END;
 	int i = 1;
 
-	if (tsk && !sp) {
+	if (!tsk)
+		tsk = current;
+	if (tsk == current)
+		sp = (unsigned long *)current_stack_pointer;
+	else
 		sp = (unsigned long *)tsk->thread.sp;
-	}
-
-	if (!sp) {
-		__asm__ __volatile__ (
-			"mov r15, %0\n\t"
-			"stc r7_bank, %1\n\t"
-			: "=r" (module_start),
-			  "=r" (module_end)
-		);
-		
-		sp = (unsigned long *)module_start;
-	}
 
 	stack = sp;
 
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 0220d8a838a7..5eb930918186 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -3,7 +3,6 @@
  * Written by Niibe Yutaka
  */
 #include <asm/thread_info.h>
-#include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
 
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
index dd05e102fc0e..0e5f365aff70 100644
--- a/include/asm-sh/irq.h
+++ b/include/asm-sh/irq.h
@@ -719,6 +719,15 @@ static inline int generic_irq_demux(int irq)
 #define irq_canonicalize(irq)	(irq)
 #define irq_demux(irq)		__irq_demux(sh_mv.mv_irq_demux(irq))
 
+#ifdef CONFIG_4KSTACKS
+extern void irq_ctx_init(int cpu);
+extern void irq_ctx_exit(int cpu);
+# define __ARCH_HAS_DO_SOFTIRQ
+#else
+# define irq_ctx_init(cpu) do { } while (0)
+# define irq_ctx_exit(cpu) do { } while (0)
+#endif
+
 #if defined(CONFIG_CPU_SUBTYPE_SH73180)
 #include <asm/irq-sh73180.h>
 #endif
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
index 605259f88113..3ebc3f9039eb 100644
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -9,8 +9,8 @@
  *  Copyright (C) 2002  David Howells (dhowells@redhat.com)
  *  - Incorporating suggestions made by Linus Torvalds and Dave Miller
  */
-
 #ifdef __KERNEL__
+#include <asm/page.h>
 
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
@@ -23,13 +23,20 @@ struct thread_info {
 	int			preempt_count; /* 0 => preemptable, <0 => BUG */
 	mm_segment_t		addr_limit;	/* thread address space */
 	struct restart_block	restart_block;
+	unsigned long		previous_sp;	/* sp of previous stack in case
+						   of nested IRQ stacks */
 	__u8			supervisor_stack[0];
 };
 
 #endif
 
 #define PREEMPT_ACTIVE		0x10000000
+
+#ifdef CONFIG_4KSTACKS
+#define THREAD_SIZE		(PAGE_SIZE)
+#else
 #define THREAD_SIZE		(PAGE_SIZE * 2)
+#endif
 #define STACK_WARN		(THREAD_SIZE / 8)
 
 /*
@@ -52,6 +59,9 @@ struct thread_info {
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 
+/* how to get the current stack pointer from C */
+register unsigned long current_stack_pointer asm("r15") __attribute_used__;
+
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {