ARM: smp: Enable THREAD_INFO_IN_TASK
authorArd Biesheuvel <ardb@kernel.org>
Sat, 18 Sep 2021 08:44:38 +0000 (10:44 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Mon, 27 Sep 2021 14:54:02 +0000 (16:54 +0200)
Now that we no longer rely on thread_info living at the base of the task
stack to be able to access the 'current' pointer, we can wire up the
generic support for moving thread_info into the task struct itself.

Note that this requires us to update the cpu field in thread_info
explicitly, now that the core code no longer does so. Ideally, we would
switch the percpu code to access the cpu field in task_struct instead,
but this unleashes #include circular dependency hell.

Co-developed-by: Keith Packard <keithpac@amazon.com>
Signed-off-by: Keith Packard <keithpac@amazon.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Tested-by: Amit Daniel Kachhap <amit.kachhap@arm.com>
arch/arm/Kconfig
arch/arm/include/asm/assembler.h
arch/arm/include/asm/switch_to.h
arch/arm/include/asm/thread_info.h
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/smp.c

index cd195e6..4f61c97 100644 (file)
@@ -125,6 +125,7 @@ config ARM
        select PERF_USE_VMALLOC
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
+       select THREAD_INFO_IN_TASK if CURRENT_POINTER_IN_TPIDRURO
        select TRACE_IRQFLAGS_SUPPORT if !CPU_V7M
        # Above selects are sorted alphabetically; please add new ones
        # according to that.  Thanks.
index c1551de..7d23d4b 100644 (file)
  * Get current thread_info.
  */
        .macro  get_thread_info, rd
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+       /* thread_info is the first member of struct task_struct */
+       get_current \rd
+#else
  ARM(  mov     \rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT    )
  THUMB(        mov     \rd, sp                 )
  THUMB(        lsr     \rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT       )
        mov     \rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
+#endif
        .endm
 
 /*
index 61e4a3c..b55c7b2 100644 (file)
  */
 extern struct task_struct *__switch_to(struct task_struct *, struct thread_info *, struct thread_info *);
 
+static inline void set_ti_cpu(struct task_struct *p)
+{
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+       /*
+        * The core code no longer maintains the thread_info::cpu field once
+        * CONFIG_THREAD_INFO_IN_TASK is in effect, but we rely on it for
+        * raw_smp_processor_id(), which cannot access struct task_struct*
+        * directly for reasons of circular #inclusion hell.
+        */
+       task_thread_info(p)->cpu = task_cpu(p);
+#endif
+}
+
 #define switch_to(prev,next,last)                                      \
 do {                                                                   \
        __complete_pending_tlbi();                                      \
+       set_ti_cpu(next);                                               \
        if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO))             \
                __this_cpu_write(__entry_task, next);                   \
        last = __switch_to(prev,task_thread_info(prev), task_thread_info(next));        \
index 76b6fbd..7875113 100644 (file)
@@ -54,7 +54,9 @@ struct cpu_context_save {
 struct thread_info {
        unsigned long           flags;          /* low level flags */
        int                     preempt_count;  /* 0 => preemptable, <0 => bug */
+#ifndef CONFIG_THREAD_INFO_IN_TASK
        struct task_struct      *task;          /* main task structure */
+#endif
        __u32                   cpu;            /* cpu */
        __u32                   cpu_domain;     /* cpu domain */
        struct cpu_context_save cpu_context;    /* cpu context */
@@ -70,11 +72,16 @@ struct thread_info {
 
 #define INIT_THREAD_INFO(tsk)                                          \
 {                                                                      \
-       .task           = &tsk,                                         \
+       INIT_THREAD_INFO_TASK(tsk)                                      \
        .flags          = 0,                                            \
        .preempt_count  = INIT_PREEMPT_COUNT,                           \
 }
 
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+#define INIT_THREAD_INFO_TASK(tsk)
+#else
+#define INIT_THREAD_INFO_TASK(tsk)     .task = &(tsk),
+
 /*
  * how to get the thread information struct from C
  */
@@ -85,6 +92,7 @@ static inline struct thread_info *current_thread_info(void)
        return (struct thread_info *)
                (current_stack_pointer & ~(THREAD_SIZE - 1));
 }
+#endif
 
 #define thread_saved_pc(tsk)   \
        ((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
index 9c864ee..645845e 100644 (file)
@@ -43,7 +43,9 @@ int main(void)
   BLANK();
   DEFINE(TI_FLAGS,             offsetof(struct thread_info, flags));
   DEFINE(TI_PREEMPT,           offsetof(struct thread_info, preempt_count));
+#ifndef CONFIG_THREAD_INFO_IN_TASK
   DEFINE(TI_TASK,              offsetof(struct thread_info, task));
+#endif
   DEFINE(TI_CPU,               offsetof(struct thread_info, cpu));
   DEFINE(TI_CPU_DOMAIN,                offsetof(struct thread_info, cpu_domain));
   DEFINE(TI_CPU_SAVE,          offsetof(struct thread_info, cpu_context));
index 7263a45..a54b504 100644 (file)
@@ -765,7 +765,7 @@ ENTRY(__switch_to)
        .endif
        ldr     r7, [r7, #TSK_STACK_CANARY & IMM12_MASK]
 #elif defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO)
-       ldr     r7, [r2, #TI_TASK]
+       mov     r7, r2                          @ Preserve 'next'
 #endif
 #ifdef CONFIG_CPU_USE_DOMAINS
        mcr     p15, 0, r6, c3, c0, 0           @ Set domain register
index 97ee6b1..cde5b6d 100644 (file)
@@ -154,6 +154,9 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
        secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
 #endif
        secondary_data.task = idle;
+       if (IS_ENABLED(CONFIG_THREAD_INFO_IN_TASK))
+               task_thread_info(idle)->cpu = cpu;
+
        sync_cache_w(&secondary_data);
 
        /*