| From: Anders Roxell <anders.roxell@linaro.org> |
| Date: Thu, 14 May 2015 17:52:17 +0200 |
| Subject: arch/arm64: Add lazy preempt support |
| |
| arm64 is missing support for PREEMPT_RT. The main feature which is |
| lacking is support for lazy preemption. The arch-specific entry code, |
| thread information structure definitions, and associated data tables |
| have to be extended to provide this support. Then the Kconfig file has |
| to be extended to indicate the support is available, and also to |
| indicate that support for full RT preemption is now available. |
| |
| Signed-off-by: Anders Roxell <anders.roxell@linaro.org> |
| --- |
| arch/arm64/Kconfig | 1 + |
| arch/arm64/include/asm/thread_info.h | 7 +++++-- |
| arch/arm64/kernel/asm-offsets.c | 1 + |
| arch/arm64/kernel/entry.S | 12 +++++++++--- |
| arch/arm64/kernel/signal.c | 2 +- |
| 5 files changed, 17 insertions(+), 6 deletions(-) |
| |
| --- a/arch/arm64/Kconfig |
| +++ b/arch/arm64/Kconfig |
| @@ -96,6 +96,7 @@ config ARM64 |
| select HAVE_PERF_EVENTS |
| select HAVE_PERF_REGS |
| select HAVE_PERF_USER_STACK_DUMP |
| + select HAVE_PREEMPT_LAZY |
| select HAVE_REGS_AND_STACK_ACCESS_API |
| select HAVE_RCU_TABLE_FREE |
| select HAVE_SYSCALL_TRACEPOINTS |
| --- a/arch/arm64/include/asm/thread_info.h |
| +++ b/arch/arm64/include/asm/thread_info.h |
| @@ -51,6 +51,7 @@ struct thread_info { |
| u64 ttbr0; /* saved TTBR0_EL1 */ |
| #endif |
| int preempt_count; /* 0 => preemptable, <0 => bug */ |
| + int preempt_lazy_count; /* 0 => preemptable, <0 => bug */ |
| }; |
| |
| #define INIT_THREAD_INFO(tsk) \ |
| @@ -86,6 +87,7 @@ struct thread_info { |
| #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ |
| #define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */ |
| #define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */ |
| +#define TIF_NEED_RESCHED_LAZY 5 |
| #define TIF_NOHZ 7 |
| #define TIF_SYSCALL_TRACE 8 |
| #define TIF_SYSCALL_AUDIT 9 |
| @@ -101,6 +103,7 @@ struct thread_info { |
| #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
| #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) |
| #define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE) |
| +#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) |
| #define _TIF_NOHZ (1 << TIF_NOHZ) |
| #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
| #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) |
| @@ -111,8 +114,8 @@ struct thread_info { |
| |
| #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ |
| _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ |
| - _TIF_UPROBE) |
| - |
| + _TIF_UPROBE | _TIF_NEED_RESCHED_LAZY) |
| +#define _TIF_NEED_RESCHED_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY) |
| #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ |
| _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ |
| _TIF_NOHZ) |
| --- a/arch/arm64/kernel/asm-offsets.c |
| +++ b/arch/arm64/kernel/asm-offsets.c |
| @@ -38,6 +38,7 @@ int main(void) |
| BLANK(); |
| DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); |
| DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); |
| + DEFINE(TSK_TI_PREEMPT_LAZY, offsetof(struct task_struct, thread_info.preempt_lazy_count)); |
| DEFINE(TSK_TI_ADDR_LIMIT, offsetof(struct task_struct, thread_info.addr_limit)); |
| #ifdef CONFIG_ARM64_SW_TTBR0_PAN |
| DEFINE(TSK_TI_TTBR0, offsetof(struct task_struct, thread_info.ttbr0)); |
| --- a/arch/arm64/kernel/entry.S |
| +++ b/arch/arm64/kernel/entry.S |
| @@ -488,11 +488,16 @@ ENDPROC(el1_sync) |
| |
| #ifdef CONFIG_PREEMPT |
| ldr w24, [tsk, #TSK_TI_PREEMPT] // get preempt count |
| - cbnz w24, 1f // preempt count != 0 |
| + cbnz w24, 2f // preempt count != 0 |
| ldr x0, [tsk, #TSK_TI_FLAGS] // get flags |
| - tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? |
| - bl el1_preempt |
| + tbnz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? |
| + |
| + ldr w24, [tsk, #TSK_TI_PREEMPT_LAZY] // get preempt lazy count |
| + cbnz w24, 2f // preempt lazy count != 0 |
| + tbz x0, #TIF_NEED_RESCHED_LAZY, 2f // needs rescheduling? |
| 1: |
| + bl el1_preempt |
| +2: |
| #endif |
| #ifdef CONFIG_TRACE_IRQFLAGS |
| bl trace_hardirqs_on |
| @@ -506,6 +511,7 @@ ENDPROC(el1_irq) |
| 1: bl preempt_schedule_irq // irq en/disable is done inside |
| ldr x0, [tsk, #TSK_TI_FLAGS] // get new tasks TI_FLAGS |
| tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling? |
| + tbnz x0, #TIF_NEED_RESCHED_LAZY, 1b // needs rescheduling? |
| ret x24 |
| #endif |
| |
| --- a/arch/arm64/kernel/signal.c |
| +++ b/arch/arm64/kernel/signal.c |
| @@ -409,7 +409,7 @@ asmlinkage void do_notify_resume(struct |
| */ |
| trace_hardirqs_off(); |
| do { |
| - if (thread_flags & _TIF_NEED_RESCHED) { |
| + if (thread_flags & _TIF_NEED_RESCHED_MASK) { |
| schedule(); |
| } else { |
| local_irq_enable(); |