select PERF_USE_VMALLOC
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
-       select THREAD_INFO_IN_TASK if CURRENT_POINTER_IN_TPIDRURO
-       select HAVE_ARCH_VMAP_STACK if MMU && THREAD_INFO_IN_TASK && (!LD_IS_LLD || LLD_VERSION >= 140000)
+       select THREAD_INFO_IN_TASK
+       select HAVE_ARCH_VMAP_STACK if MMU && (!LD_IS_LLD || LLD_VERSION >= 140000)
        select TRACE_IRQFLAGS_SUPPORT if !CPU_V7M
        # Above selects are sorted alphabetically; please add new ones
        # according to that.  Thanks.
 
 config IRQSTACKS
        def_bool y
-       depends on THREAD_INFO_IN_TASK
+       depends on MMU
        select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_SOFTIRQ_ON_OWN_STACK
 
 
 config STACKPROTECTOR_PER_TASK
        bool "Use a unique stack canary value for each task"
-       depends on STACKPROTECTOR && THREAD_INFO_IN_TASK && !XIP_DEFLATED_DATA
+       depends on STACKPROTECTOR && CURRENT_POINTER_IN_TPIDRURO && !XIP_DEFLATED_DATA
        depends on GCC_PLUGINS || CC_HAVE_STACKPROTECTOR_TLS
        select GCC_PLUGIN_ARM_SSP_PER_TASK if !CC_HAVE_STACKPROTECTOR_TLS
        default y
 
        .endm
        .endr
 
-       .macro  get_current, rd
-#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO
-       mrc     p15, 0, \rd, c13, c0, 3         @ get TPIDRURO register
-#else
-       get_thread_info \rd
-       ldr     \rd, [\rd, #TI_TASK]
-#endif
-       .endm
-
-       .macro  set_current, rn
-#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO
-       mcr     p15, 0, \rn, c13, c0, 3         @ set TPIDRURO register
-#endif
-       .endm
-
-       .macro  reload_current, t1:req, t2:req
-#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO
-       ldr_this_cpu \t1, __entry_task, \t1, \t2
-       mcr     p15, 0, \t1, c13, c0, 3         @ store in TPIDRURO
-#endif
-       .endm
-
 /*
  * 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
 
 /*
 #endif
        .endm
 
+       /*
+        * set_current - store the task pointer of this CPU's current task
+        */
+       .macro          set_current, rn:req, tmp:req
+#if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP)
+9998:  mcr             p15, 0, \rn, c13, c0, 3         @ set TPIDRURO register
+#ifdef CONFIG_CPU_V6
+ALT_UP_B(.L0_\@)
+       .subsection     1
+.L0_\@: str_va         \rn, __current, \tmp
+       b               .L1_\@
+       .previous
+.L1_\@:
+#endif
+#else
+       str_va          \rn, __current, \tmp
+#endif
+       .endm
+
+       /*
+        * get_current - load the task pointer of this CPU's current task
+        */
+       .macro          get_current, rd:req
+#if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP)
+9998:  mrc             p15, 0, \rd, c13, c0, 3         @ get TPIDRURO register
+#ifdef CONFIG_CPU_V6
+ALT_UP_B(.L0_\@)
+       .subsection     1
+.L0_\@: ldr_va         \rd, __current
+       b               .L1_\@
+       .previous
+.L1_\@:
+#endif
+#else
+       ldr_va          \rd, __current
+#endif
+       .endm
+
+       /*
+        * reload_current - reload the task pointer of this CPU's current task
+        *                  into the TLS register
+        */
+       .macro          reload_current, t1:req, t2:req
+#if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP)
+#ifdef CONFIG_CPU_V6
+ALT_SMP(nop)
+ALT_UP_B(.L0_\@)
+#endif
+       ldr_this_cpu    \t1, __entry_task, \t1, \t2
+       mcr             p15, 0, \t1, c13, c0, 3         @ store in TPIDRURO
+.L0_\@:
+#endif
+       .endm
+
 /*
  * Instruction barrier
  */
 
 #define _ASM_ARM_CURRENT_H
 
 #ifndef __ASSEMBLY__
+#include <asm/insn.h>
 
 struct task_struct;
 
-static inline void set_current(struct task_struct *cur)
-{
-       if (!IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO))
-               return;
-
-       /* Set TPIDRURO */
-       asm("mcr p15, 0, %0, c13, c0, 3" :: "r"(cur) : "memory");
-}
+extern struct task_struct *__current;
 
-#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO
-
-static inline struct task_struct *get_current(void)
+static inline __attribute_const__ struct task_struct *get_current(void)
 {
        struct task_struct *cur;
 
 #if __has_builtin(__builtin_thread_pointer) && \
+    defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) && \
     !(defined(CONFIG_THUMB2_KERNEL) && \
       defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 130001)
        /*
         * https://github.com/ClangBuiltLinux/linux/issues/1485
         */
        cur = __builtin_thread_pointer();
+#elif defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP)
+       asm("0: mrc p15, 0, %0, c13, c0, 3                      \n\t"
+#ifdef CONFIG_CPU_V6
+           "1:                                                 \n\t"
+           "   .subsection 1                                   \n\t"
+           "2: " LOAD_SYM_ARMV6(%0, __current) "               \n\t"
+           "   b       1b                                      \n\t"
+           "   .previous                                       \n\t"
+           "   .pushsection \".alt.smp.init\", \"a\"           \n\t"
+           "   .long   0b - .                                  \n\t"
+           "   b       . + (2b - 0b)                           \n\t"
+           "   .popsection                                     \n\t"
+#endif
+           : "=r"(cur));
+#elif __LINUX_ARM_ARCH__>=7 || \
+      (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
+       cur = __current;
 #else
-       asm("mrc p15, 0, %0, c13, c0, 3" : "=r"(cur));
+       asm(LOAD_SYM_ARMV6(%0, __current) : "=r"(cur));
 #endif
        return cur;
 }
 
 #define current get_current()
-#else
-#include <asm-generic/current.h>
-#endif /* CONFIG_CURRENT_POINTER_IN_TPIDRURO */
 
 #endif /* __ASSEMBLY__ */
 
 
 do {                                                                   \
        __complete_pending_tlbi();                                      \
        set_ti_cpu(next);                                               \
-       if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO))             \
+       if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) ||           \
+           IS_ENABLED(CONFIG_SMP))                                     \
                __this_cpu_write(__entry_task, next);                   \
        last = __switch_to(prev,task_thread_info(prev), task_thread_info(next));        \
 } while (0)
 
 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 */
 
 #define INIT_THREAD_INFO(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)
-
 static inline struct task_struct *thread_task(struct thread_info* ti)
 {
        return (struct task_struct *)ti;
 }
 
-#else
-#define INIT_THREAD_INFO_TASK(tsk)     .task = &(tsk),
-
-static inline struct task_struct *thread_task(struct thread_info* ti)
-{
-       return ti->task;
-}
-
-/*
- * how to get the thread information struct from C
- */
-static inline struct thread_info *current_thread_info(void) __attribute_const__;
-
-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))
 #define thread_saved_sp(tsk)   \
 
   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));
 
        switch_tls r1, r4, r5, r3, r7
 #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP) && \
     !defined(CONFIG_STACKPROTECTOR_PER_TASK)
-       ldr     r9, [r2, #TI_TASK]
        ldr     r8, =__stack_chk_guard
        .if (TSK_STACK_CANARY > IMM12_MASK)
-       add     r9, r9, #TSK_STACK_CANARY & ~IMM12_MASK
-       .endif
+       add     r9, r2, #TSK_STACK_CANARY & ~IMM12_MASK
        ldr     r9, [r9, #TSK_STACK_CANARY & IMM12_MASK]
+       .else
+       ldr     r9, [r2, #TSK_STACK_CANARY & IMM12_MASK]
+       .endif
 #endif
        mov     r7, r2                          @ Preserve 'next'
 #ifdef CONFIG_CPU_USE_DOMAINS
 #endif
        mov     r0, r5
 #if !defined(CONFIG_THUMB2_KERNEL) && !defined(CONFIG_VMAP_STACK)
-       set_current r7
+       set_current r7, r8
        ldmia   r4, {r4 - sl, fp, sp, pc}       @ Load all regs saved previously
 #else
        mov     r1, r7
        @ switches us to another stack, with few other side effects. In order
        @ to prevent this distinction from causing any inconsistencies, let's
        @ keep the 'set_current' call as close as we can to the update of SP.
-       set_current r1
+       set_current r1, r2
        mov     sp, ip
        ret     lr
 #endif
 
        str     sp, [ip], #4
        str     lr, [ip], #4
        mov     r5, r0
+       mov     r6, r2                  @ Preserve 'next'
        add     r4, r2, #TI_CPU_SAVE
        ldr     r0, =thread_notify_head
        mov     r1, #THREAD_NOTIFY_SWITCH
        bl      atomic_notifier_call_chain
-       mov     ip, r4
        mov     r0, r5
-       ldmia   ip!, {r4 - r11}         @ Load all regs saved previously
-       ldr     sp, [ip]
-       ldr     pc, [ip, #4]!
+       mov     r1, r6
+       ldmia   r4, {r4 - r12, lr}      @ Load all regs saved previously
+       set_current r1, r2
+       mov     sp, ip
+       bx      lr
        .fnend
 ENDPROC(__switch_to)
 
 
        mov     r1, #0
        bl      __memset                        @ clear .bss
 
-#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO
        adr_l   r0, init_task                   @ get swapper task_struct
-       set_current r0
-#endif
+       set_current r0, r1
 
        ldmia   r4, {r0, r1, r2, r3}
        str     r9, [r0]                        @ Save processor ID
 
 
 #include "signal.h"
 
-#ifdef CONFIG_CURRENT_POINTER_IN_TPIDRURO
+#if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP)
 DEFINE_PER_CPU(struct task_struct *, __entry_task);
 #endif
 
 EXPORT_SYMBOL(__stack_chk_guard);
 #endif
 
+#ifndef CONFIG_CURRENT_POINTER_IN_TPIDRURO
+asmlinkage struct task_struct *__current;
+EXPORT_SYMBOL(__current);
+#endif
+
 static const char *processor_modes[] __maybe_unused = {
   "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
   "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
 
        check_cpu_icache_size(cpuid);
 }
 
+static void set_current(struct task_struct *cur)
+{
+       if (!IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) && !is_smp()) {
+               __current = cur;
+               return;
+       }
+
+       /* Set TPIDRURO */
+       asm("mcr p15, 0, %0, c13, c0, 3" :: "r"(cur) : "memory");
+}
+
 /*
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
 
 asmlinkage void handle_bad_stack(struct pt_regs *regs)
 {
        unsigned long tsk_stk = (unsigned long)current->stack;
+#ifdef CONFIG_IRQSTACKS
        unsigned long irq_stk = (unsigned long)this_cpu_read(irq_stack_ptr);
+#endif
        unsigned long ovf_stk = (unsigned long)this_cpu_read(overflow_stack_ptr);
 
        console_verbose();
 
        pr_emerg("Task stack:     [0x%08lx..0x%08lx]\n",
                 tsk_stk, tsk_stk + THREAD_SIZE);
+#ifdef CONFIG_IRQSTACKS
        pr_emerg("IRQ stack:      [0x%08lx..0x%08lx]\n",
                 irq_stk - THREAD_SIZE, irq_stk);
+#endif
        pr_emerg("Overflow stack: [0x%08lx..0x%08lx]\n",
                 ovf_stk - OVERFLOW_STACK_SIZE, ovf_stk);