aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2006-09-27 05:22:14 -0400
committerPaul Mundt <lethal@linux-sh.org>2006-09-27 05:22:14 -0400
commita6a31139897a5e539efe7ad3b7bd351fa9673ce8 (patch)
tree6e2ad11d93ab95214694038080c79284c6da30d6 /arch/sh
parent2cb7ce3bb384f30a377f66336c78546b834604df (diff)
sh: Add support for 4K stacks.
This enables support for 4K stacks on SH. Currently this depends on DEBUG_KERNEL, but likely all boards will switch to this as the default in the future. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-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
7 files changed, 170 insertions, 23 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
46 46
47 This option will slow down process creation somewhat. 47 This option will slow down process creation somewhat.
48 48
49config 4KSTACKS
50 bool "Use 4Kb for kernel stacks instead of 8Kb"
51 depends on DEBUG_KERNEL
52 help
53 If you say Y here the kernel will use a 4Kb stacksize for the
54 kernel stack attached to each process/thread. This facilitates
55 running more threads on a system and also reduces the pressure
56 on the VM subsystem for higher order allocations. This option
57 will also use IRQ stacks to compensate for the reduced stackspace.
58
49config KGDB 59config KGDB
50 bool "Include KGDB kernel debugger" 60 bool "Include KGDB kernel debugger"
51 select FRAME_POINTER 61 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)
190 /* Perform the machine specific initialisation */ 190 /* Perform the machine specific initialisation */
191 if (sh_mv.mv_init_irq != NULL) 191 if (sh_mv.mv_init_irq != NULL)
192 sh_mv.mv_init_irq(); 192 sh_mv.mv_init_irq();
193
194 irq_ctx_init(smp_processor_id());
193} 195}
194 196
195#if !defined(CONFIG_CPU_HAS_PINT_IRQ) 197#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)
716 bt/s 1f ! It's a kernel to kernel transition. 716 bt/s 1f ! It's a kernel to kernel transition.
717 mov r15, k0 ! save original stack to k0 717 mov r15, k0 ! save original stack to k0
718 /* User space to kernel */ 718 /* User space to kernel */
719 mov #0x20, k1 719 mov #(THREAD_SIZE >> 8), k1
720 shll8 k1 ! k1 := 8192 (== THREAD_SIZE) 720 shll8 k1 ! k1 := THREAD_SIZE
721 add current, k1 721 add current, k1
722 mov k1, r15 ! change to kernel stack 722 mov k1, r15 ! change to kernel stack
723 ! 723 !
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 @@
12 */ 12 */
13#include <linux/linkage.h> 13#include <linux/linkage.h>
14#include <asm/thread_info.h> 14#include <asm/thread_info.h>
15#include <asm/page.h>
16 15
17#ifdef CONFIG_CPU_SH4A 16#ifdef CONFIG_CPU_SH4A
18#define SYNCO() synco 17#define SYNCO() synco
@@ -69,8 +68,8 @@ ENTRY(_stext)
69 ! 68 !
70 mov.l 2f, r0 69 mov.l 2f, r0
71 mov r0, r15 ! Set initial r15 (stack pointer) 70 mov r0, r15 ! Set initial r15 (stack pointer)
72 mov #0x20, r1 ! 71 mov #(THREAD_SIZE >> 8), r1
73 shll8 r1 ! r1 = 8192 72 shll8 r1 ! r1 = THREAD_SIZE
74 sub r1, r0 ! 73 sub r1, r0 !
75 ldc r0, r7_bank ! ... and initial thread_info 74 ldc r0, r7_bank ! ... and initial thread_info
76 75
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 @@
1/* $Id: irq.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $ 1/*
2 *
3 * linux/arch/sh/kernel/irq.c 2 * linux/arch/sh/kernel/irq.c
4 * 3 *
5 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar 4 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
@@ -7,13 +6,15 @@
7 * 6 *
8 * SuperH version: Copyright (C) 1999 Niibe Yutaka 7 * SuperH version: Copyright (C) 1999 Niibe Yutaka
9 */ 8 */
10
11#include <linux/irq.h> 9#include <linux/irq.h>
12#include <linux/interrupt.h> 10#include <linux/interrupt.h>
11#include <linux/module.h>
13#include <linux/kernel_stat.h> 12#include <linux/kernel_stat.h>
14#include <linux/seq_file.h> 13#include <linux/seq_file.h>
15#include <asm/irq.h> 14#include <asm/irq.h>
16#include <asm/processor.h> 15#include <asm/processor.h>
16#include <asm/uaccess.h>
17#include <asm/thread_info.h>
17#include <asm/cpu/mmu_context.h> 18#include <asm/cpu/mmu_context.h>
18 19
19/* 20/*
@@ -60,11 +61,27 @@ unlock:
60} 61}
61#endif 62#endif
62 63
64#ifdef CONFIG_4KSTACKS
65/*
66 * per-CPU IRQ handling contexts (thread information and stack)
67 */
68union irq_ctx {
69 struct thread_info tinfo;
70 u32 stack[THREAD_SIZE/sizeof(u32)];
71};
72
73static union irq_ctx *hardirq_ctx[NR_CPUS];
74static union irq_ctx *softirq_ctx[NR_CPUS];
75#endif
76
63asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, 77asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
64 unsigned long r6, unsigned long r7, 78 unsigned long r6, unsigned long r7,
65 struct pt_regs regs) 79 struct pt_regs regs)
66{ 80{
67 int irq = r4; 81 int irq = r4;
82#ifdef CONFIG_4KSTACKS
83 union irq_ctx *curctx, *irqctx;
84#endif
68 85
69 irq_enter(); 86 irq_enter();
70 87
@@ -102,7 +119,135 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
102#endif 119#endif
103 120
104 irq = irq_demux(irq); 121 irq = irq_demux(irq);
105 __do_IRQ(irq, &regs); 122
123#ifdef CONFIG_4KSTACKS
124 curctx = (union irq_ctx *)current_thread_info();
125 irqctx = hardirq_ctx[smp_processor_id()];
126
127 /*
128 * this is where we switch to the IRQ stack. However, if we are
129 * already using the IRQ stack (because we interrupted a hardirq
130 * handler) we can't do that and just have to keep using the
131 * current stack (which is the irq stack already after all)
132 */
133 if (curctx != irqctx) {
134 u32 *isp;
135
136 isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
137 irqctx->tinfo.task = curctx->tinfo.task;
138 irqctx->tinfo.previous_sp = current_stack_pointer;
139
140 __asm__ __volatile__ (
141 "mov %0, r4 \n"
142 "mov %1, r5 \n"
143 "mov r15, r9 \n"
144 "jsr @%2 \n"
145 /* swith to the irq stack */
146 " mov %3, r15 \n"
147 /* restore the stack (ring zero) */
148 "mov r9, r15 \n"
149 : /* no outputs */
150 : "r" (irq), "r" (&regs), "r" (__do_IRQ), "r" (isp)
151 /* XXX: A somewhat excessive clobber list? -PFM */
152 : "memory", "r0", "r1", "r2", "r3", "r4",
153 "r5", "r6", "r7", "r8", "t", "pr"
154 );
155 } else
156#endif
157 __do_IRQ(irq, &regs);
158
106 irq_exit(); 159 irq_exit();
160
107 return 1; 161 return 1;
108} 162}
163
164#ifdef CONFIG_4KSTACKS
165/*
166 * These should really be __section__(".bss.page_aligned") as well, but
167 * gcc's 3.0 and earlier don't handle that correctly.
168 */
169static char softirq_stack[NR_CPUS * THREAD_SIZE]
170 __attribute__((__aligned__(THREAD_SIZE)));
171
172static char hardirq_stack[NR_CPUS * THREAD_SIZE]
173 __attribute__((__aligned__(THREAD_SIZE)));
174
175/*
176 * allocate per-cpu stacks for hardirq and for softirq processing
177 */
178void irq_ctx_init(int cpu)
179{
180 union irq_ctx *irqctx;
181
182 if (hardirq_ctx[cpu])
183 return;
184
185 irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE];
186 irqctx->tinfo.task = NULL;
187 irqctx->tinfo.exec_domain = NULL;
188 irqctx->tinfo.cpu = cpu;
189 irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
190 irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
191
192 hardirq_ctx[cpu] = irqctx;
193
194 irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE];
195 irqctx->tinfo.task = NULL;
196 irqctx->tinfo.exec_domain = NULL;
197 irqctx->tinfo.cpu = cpu;
198 irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET;
199 irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
200
201 softirq_ctx[cpu] = irqctx;
202
203 printk("CPU %u irqstacks, hard=%p soft=%p\n",
204 cpu, hardirq_ctx[cpu], softirq_ctx[cpu]);
205}
206
207void irq_ctx_exit(int cpu)
208{
209 hardirq_ctx[cpu] = NULL;
210}
211
212extern asmlinkage void __do_softirq(void);
213
214asmlinkage void do_softirq(void)
215{
216 unsigned long flags;
217 struct thread_info *curctx;
218 union irq_ctx *irqctx;
219 u32 *isp;
220
221 if (in_interrupt())
222 return;
223
224 local_irq_save(flags);
225
226 if (local_softirq_pending()) {
227 curctx = current_thread_info();
228 irqctx = softirq_ctx[smp_processor_id()];
229 irqctx->tinfo.task = curctx->task;
230 irqctx->tinfo.previous_sp = current_stack_pointer;
231
232 /* build the stack frame on the softirq stack */
233 isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
234
235 __asm__ __volatile__ (
236 "mov r15, r9 \n"
237 "jsr @%0 \n"
238 /* switch to the softirq stack */
239 " mov %1, r15 \n"
240 /* restore the thread stack */
241 "mov r9, r15 \n"
242 : /* no outputs */
243 : "r" (__do_softirq), "r" (isp)
244 /* XXX: A somewhat excessive clobber list? -PFM */
245 : "memory", "r0", "r1", "r2", "r3", "r4",
246 "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
247 );
248 }
249
250 local_irq_restore(flags);
251}
252EXPORT_SYMBOL(do_softirq);
253#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)
741 unsigned long module_end = VMALLOC_END; 741 unsigned long module_end = VMALLOC_END;
742 int i = 1; 742 int i = 1;
743 743
744 if (tsk && !sp) { 744 if (!tsk)
745 tsk = current;
746 if (tsk == current)
747 sp = (unsigned long *)current_stack_pointer;
748 else
745 sp = (unsigned long *)tsk->thread.sp; 749 sp = (unsigned long *)tsk->thread.sp;
746 }
747
748 if (!sp) {
749 __asm__ __volatile__ (
750 "mov r15, %0\n\t"
751 "stc r7_bank, %1\n\t"
752 : "=r" (module_start),
753 "=r" (module_end)
754 );
755
756 sp = (unsigned long *)module_start;
757 }
758 750
759 stack = sp; 751 stack = sp;
760 752
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 @@
3 * Written by Niibe Yutaka 3 * Written by Niibe Yutaka
4 */ 4 */
5#include <asm/thread_info.h> 5#include <asm/thread_info.h>
6#include <asm/page.h>
7#include <asm-generic/vmlinux.lds.h> 6#include <asm-generic/vmlinux.lds.h>
8 7
9#ifdef CONFIG_CPU_LITTLE_ENDIAN 8#ifdef CONFIG_CPU_LITTLE_ENDIAN