[PATCH v7 3/3] arm64: Add do_softirq_own_stack() and enable irq_stacks
Catalin Marinas
catalin.marinas at arm.com
Fri Nov 27 09:38:16 PST 2015
On Sat, Nov 28, 2015 at 12:37:31AM +0900, Jungseok Lee wrote:
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 9ac16a4..a12f015 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -70,6 +70,7 @@ config ARM64
> select HAVE_FUNCTION_GRAPH_TRACER
> select HAVE_GENERIC_DMA_COHERENT
> select HAVE_HW_BREAKPOINT if PERF_EVENTS
> + select HAVE_IRQ_EXIT_ON_IRQ_STACK
I'm not convinced about this. See below.
> select HAVE_MEMBLOCK
> select HAVE_PATA_PLATFORM
> select HAVE_PERF_EVENTS
> diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
> index 23eb450..d4cbae6 100644
> --- a/arch/arm64/include/asm/irq.h
> +++ b/arch/arm64/include/asm/irq.h
> @@ -1,10 +1,26 @@
> #ifndef __ASM_IRQ_H
> #define __ASM_IRQ_H
>
> +#define IRQ_STACK_SIZE 16384
8K should be enough.
> +
> +#ifndef __ASSEMBLY__
> +
> #include <asm-generic/irq.h>
>
> +#define __ARCH_HAS_DO_SOFTIRQ
> +
> +struct irq_stack {
> + unsigned int count;
> + /*
> + * The stack must be quad-word aligned according to '5.2.2 The stack'
> + * of 'Procedure Call Standard for the ARM 64-bit Architecture'.
> + */
> + char stack[IRQ_STACK_SIZE] __aligned(16);
> +};
This looks fine.
> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
> index 25de8b2..f8b4df7 100644
> --- a/arch/arm64/kernel/asm-offsets.c
> +++ b/arch/arm64/kernel/asm-offsets.c
> @@ -41,6 +41,8 @@ int main(void)
> BLANK();
> DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context));
> BLANK();
> + DEFINE(IRQ_STACK, offsetof(struct irq_stack, stack));
> + BLANK();
> DEFINE(S_X0, offsetof(struct pt_regs, regs[0]));
> DEFINE(S_X1, offsetof(struct pt_regs, regs[1]));
> DEFINE(S_X2, offsetof(struct pt_regs, regs[2]));
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index fc87373..bc01102 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -27,9 +27,12 @@
> #include <asm/cpufeature.h>
> #include <asm/errno.h>
> #include <asm/esr.h>
> +#include <asm/irq.h>
> #include <asm/thread_info.h>
> #include <asm/unistd.h>
>
> +#define IRQ_STACK_START_SP (IRQ_STACK + IRQ_STACK_SIZE - 16)
> +
> /*
> * Context tracking subsystem. Used to instrument transitions
> * between user and kernel mode.
> @@ -175,6 +178,29 @@ alternative_endif
> mrs \rd, sp_el0
> .endm
>
> + .macro irq_stack_entry
> + adr_l x19, irq_stacks
> + mrs x20, tpidr_el1
> + add x20, x19, x20
> + mov x19, sp
> + ldr w23, [x20]
> + cbnz w23, 1f // check irq re-entrance
> + mov x24, #IRQ_STACK_START_SP
> + add x24, x20, x24 // x24 = top of irq stack
> + mov sp, x24
> +1: add w23, w23, #1
> + str w23, [x20]
> + .endm
> +
> + /*
> + * x19, x20, w23 are preserved between irq_stack_{entry|exit}.
> + */
> + .macro irq_stack_exit
> + sub w23, w23, #1
> + str w23, [x20]
> + mov sp, x19
> + .endm
With your approach to select HAVE_IRQ_EXIT_ON_IRQ_STACK you need to
always update the irq_count every time you enter or exit the IRQ. Since
presumably softirqs are rarer than hardirqs, I suggest that you only
increment/decrement irq_count via do_softirq_own_stack() and not select
HAVE_IRQ_EXIT_ON_IRQ_STACK. The only downside is having to check whether
SP is the IRQ stack (the irq_count) in this function before invoking
__do_softirq() rather than calling __do_softirq() directly. But it
doesn't look too bad.
> @@ -190,10 +216,11 @@ tsk .req x28 // current thread_info
> * Interrupt handling.
> */
> .macro irq_handler
> - adrp x1, handle_arch_irq
> - ldr x1, [x1, #:lo12:handle_arch_irq]
> + ldr_l x1, handle_arch_irq
> mov x0, sp
> + irq_stack_entry
> blr x1
> + irq_stack_exit
> .endm
>
> .text
> @@ -741,3 +768,25 @@ ENTRY(sys_rt_sigreturn_wrapper)
> mov x0, sp
> b sys_rt_sigreturn
> ENDPROC(sys_rt_sigreturn_wrapper)
> +
> +/*
> + * Softirq is handled on IRQ stack.
> + */
> +ENTRY(do_softirq_own_stack)
> + stp x29, lr, [sp, #-96]!
> + stp x19, x20, [sp, #16]
> + stp x21, x22, [sp, #32]
> + stp x23, x24, [sp, #48]
> + stp x25, x26, [sp, #64]
> + stp x27, x28, [sp, #80]
> + irq_stack_entry
> + bl __do_softirq
> + irq_stack_exit
> + ldp x19, x20, [sp, #16]
> + ldp x21, x22, [sp, #32]
> + ldp x23, x24, [sp, #48]
> + ldp x25, x26, [sp, #64]
> + ldp x27, x28, [sp, #80]
> + ldp x29, lr, [sp], #96
> + ret
> +ENDPROC(do_softirq_own_stack)
Since irq_stack_entry/exit shouldn't increment irq_count as I mentioned
above, you can hand-code the stack switching (or maybe parametrise the
irq_stack_* macros) to only use caller-saved registers and avoid too
many stp/ldp, probably just one for fp/lr.
--
Catalin
More information about the linux-arm-kernel
mailing list