Merge back reboot/poweroff notifiers rework for 5.19-rc1.
[linux-2.6-microblaze.git] / arch / arm64 / kernel / process.c
index 7fa97df..2f42123 100644 (file)
@@ -111,8 +111,7 @@ void machine_power_off(void)
 {
        local_irq_disable();
        smp_send_stop();
-       if (pm_power_off)
-               pm_power_off();
+       do_kernel_power_off();
 }
 
 /*
@@ -250,6 +249,8 @@ void show_regs(struct pt_regs *regs)
 static void tls_thread_flush(void)
 {
        write_sysreg(0, tpidr_el0);
+       if (system_supports_tpidr2())
+               write_sysreg_s(0, SYS_TPIDR2_EL0);
 
        if (is_compat_task()) {
                current->thread.uw.tp_value = 0;
@@ -298,16 +299,42 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 
        /*
         * Detach src's sve_state (if any) from dst so that it does not
-        * get erroneously used or freed prematurely.  dst's sve_state
+        * get erroneously used or freed prematurely.  dst's copies
         * will be allocated on demand later on if dst uses SVE.
         * For consistency, also clear TIF_SVE here: this could be done
         * later in copy_process(), but to avoid tripping up future
-        * maintainers it is best not to leave TIF_SVE and sve_state in
+        * maintainers it is best not to leave TIF flags and buffers in
         * an inconsistent state, even temporarily.
         */
        dst->thread.sve_state = NULL;
        clear_tsk_thread_flag(dst, TIF_SVE);
 
+       /*
+        * In the unlikely event that we create a new thread with ZA
+        * enabled we should retain the ZA state so duplicate it here.
+        * This may be shortly freed if we exec() or if CLONE_SETTLS
+        * but it's simpler to do it here. To avoid confusing the rest
+        * of the code ensure that we have a sve_state allocated
+        * whenever za_state is allocated.
+        */
+       if (thread_za_enabled(&src->thread)) {
+               dst->thread.sve_state = kzalloc(sve_state_size(src),
+                                               GFP_KERNEL);
+               if (!dst->thread.sve_state)
+                       return -ENOMEM;
+               dst->thread.za_state = kmemdup(src->thread.za_state,
+                                              za_state_size(src),
+                                              GFP_KERNEL);
+               if (!dst->thread.za_state) {
+                       kfree(dst->thread.sve_state);
+                       dst->thread.sve_state = NULL;
+                       return -ENOMEM;
+               }
+       } else {
+               dst->thread.za_state = NULL;
+               clear_tsk_thread_flag(dst, TIF_SME);
+       }
+
        /* clear any pending asynchronous tag fault raised by the parent */
        clear_tsk_thread_flag(dst, TIF_MTE_ASYNC_FAULT);
 
@@ -343,6 +370,8 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
                 * out-of-sync with the saved value.
                 */
                *task_user_tls(p) = read_sysreg(tpidr_el0);
+               if (system_supports_tpidr2())
+                       p->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
 
                if (stack_start) {
                        if (is_compat_thread(task_thread_info(p)))
@@ -353,10 +382,12 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
 
                /*
                 * If a TLS pointer was passed to clone, use it for the new
-                * thread.
+                * thread.  We also reset TPIDR2 if it's in use.
                 */
-               if (clone_flags & CLONE_SETTLS)
+               if (clone_flags & CLONE_SETTLS) {
                        p->thread.uw.tp_value = tls;
+                       p->thread.tpidr2_el0 = 0;
+               }
        } else {
                /*
                 * A kthread has no context to ERET to, so ensure any buggy
@@ -387,6 +418,8 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
 void tls_preserve_current_state(void)
 {
        *task_user_tls(current) = read_sysreg(tpidr_el0);
+       if (system_supports_tpidr2() && !is_compat_task())
+               current->thread.tpidr2_el0 = read_sysreg_s(SYS_TPIDR2_EL0);
 }
 
 static void tls_thread_switch(struct task_struct *next)
@@ -399,6 +432,8 @@ static void tls_thread_switch(struct task_struct *next)
                write_sysreg(0, tpidrro_el0);
 
        write_sysreg(*task_user_tls(next), tpidr_el0);
+       if (system_supports_tpidr2())
+               write_sysreg_s(next->thread.tpidr2_el0, SYS_TPIDR2_EL0);
 }
 
 /*