diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 05:22:14 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 05:22:14 -0400 |
commit | a6a31139897a5e539efe7ad3b7bd351fa9673ce8 (patch) | |
tree | 6e2ad11d93ab95214694038080c79284c6da30d6 /arch/sh | |
parent | 2cb7ce3bb384f30a377f66336c78546b834604df (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.debug | 10 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/irq/ipr.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/entry.S | 4 | ||||
-rw-r--r-- | arch/sh/kernel/head.S | 5 | ||||
-rw-r--r-- | arch/sh/kernel/irq.c | 153 | ||||
-rw-r--r-- | arch/sh/kernel/traps.c | 18 | ||||
-rw-r--r-- | arch/sh/kernel/vmlinux.lds.S | 1 |
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 | ||
49 | config 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 | |||
49 | config KGDB | 59 | config 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 | */ | ||
68 | union irq_ctx { | ||
69 | struct thread_info tinfo; | ||
70 | u32 stack[THREAD_SIZE/sizeof(u32)]; | ||
71 | }; | ||
72 | |||
73 | static union irq_ctx *hardirq_ctx[NR_CPUS]; | ||
74 | static union irq_ctx *softirq_ctx[NR_CPUS]; | ||
75 | #endif | ||
76 | |||
63 | asmlinkage int do_IRQ(unsigned long r4, unsigned long r5, | 77 | asmlinkage 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, ®s); | 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" (®s), "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, ®s); | ||
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 | */ | ||
169 | static char softirq_stack[NR_CPUS * THREAD_SIZE] | ||
170 | __attribute__((__aligned__(THREAD_SIZE))); | ||
171 | |||
172 | static 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 | */ | ||
178 | void 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 | |||
207 | void irq_ctx_exit(int cpu) | ||
208 | { | ||
209 | hardirq_ctx[cpu] = NULL; | ||
210 | } | ||
211 | |||
212 | extern asmlinkage void __do_softirq(void); | ||
213 | |||
214 | asmlinkage 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 | } | ||
252 | EXPORT_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 |