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>
This commit is contained in:
Paul Mundt
2006-09-27 18:22:14 +09:00
parent 2cb7ce3bb3
commit a6a3113989
9 changed files with 190 additions and 24 deletions

View File

@@ -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)

View File

@@ -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
!

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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