[PATCH v7 3/3] arm64: Add do_softirq_own_stack() and enable irq_stacks
Jungseok Lee
jungseoklee85 at gmail.com
Sat Nov 28 08:04:50 PST 2015
On Nov 28, 2015, at 2:38 AM, Catalin Marinas wrote:
> 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.
Agree.
>> +
>> +#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.
Aha!!
I clearly understand why irq_count update in do_softirq_own_stack() is
a good approach. It would be really great to add the clause, "Since
presumably softirqs are rarer than hardirqs", to this commit message.
It explains why irq_count is updated in do_softirq_own_stack(), not elX_irq
context. IOW, I believe that it is a critical background on the design.
Now, I vote in favor of not selecting HAVE_IRQ_EXIT_ON_IRQ_STACK and this
lazy irq_count update.
>> @@ -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.
Agree. This part should be reworked under the lazy update approach.
Best Regards
Jungseok Lee
More information about the linux-arm-kernel
mailing list