]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blobdiff - arch/powerpc/kernel/machine_kexec_64.c
powerpc/kexec: Switch to a static PACA on the way out
[mirror_ubuntu-focal-kernel.git] / arch / powerpc / kernel / machine_kexec_64.c
index 26f9900f773cb2e17634538f1674882c0cd7447b..022d2f613b7b4794bd2a785003494de5fcb40659 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/sections.h>      /* _end */
 #include <asm/prom.h>
 #include <asm/smp.h>
+#include <asm/hw_breakpoint.h>
 
 int default_machine_kexec_prepare(struct kimage *image)
 {
@@ -165,6 +166,7 @@ static void kexec_smp_down(void *arg)
        while(kexec_all_irq_disabled == 0)
                cpu_relax();
        mb(); /* make sure all irqs are disabled before this */
+       hw_breakpoint_disable();
        /*
         * Now every CPU has IRQs off, we can clear out any pending
         * IPIs and be sure that no more will come in after this.
@@ -180,30 +182,15 @@ static void kexec_prepare_cpus_wait(int wait_state)
 {
        int my_cpu, i, notified=-1;
 
+       hw_breakpoint_disable();
        my_cpu = get_cpu();
        /* Make sure each CPU has atleast made it to the state we need */
-       for (i=0; i < NR_CPUS; i++) {
+       for_each_online_cpu(i) {
                if (i == my_cpu)
                        continue;
 
                while (paca[i].kexec_state < wait_state) {
                        barrier();
-                       if (!cpu_possible(i)) {
-                               printk("kexec: cpu %d hw_cpu_id %d is not"
-                                               " possible, ignoring\n",
-                                               i, paca[i].hw_cpu_id);
-                               break;
-                       }
-                       if (!cpu_online(i)) {
-                               /* Fixme: this can be spinning in
-                                * pSeries_secondary_wait with a paca
-                                * waiting for it to go online.
-                                */
-                               printk("kexec: cpu %d hw_cpu_id %d is not"
-                                               " online, ignoring\n",
-                                               i, paca[i].hw_cpu_id);
-                               break;
-                       }
                        if (i != notified) {
                                printk( "kexec: waiting for cpu %d (physical"
                                                " %d) to enter %i state\n",
@@ -273,6 +260,12 @@ static void kexec_prepare_cpus(void)
 static union thread_union kexec_stack __init_task_data =
        { };
 
+/*
+ * For similar reasons to the stack above, the kexecing CPU needs to be on a
+ * static PACA; we switch to kexec_paca.
+ */
+struct paca_struct kexec_paca;
+
 /* Our assembly helper, in kexec_stub.S */
 extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
                                        void *image, void *control,
@@ -300,6 +293,20 @@ void default_machine_kexec(struct kimage *image)
        kexec_stack.thread_info.task = current_thread_info()->task;
        kexec_stack.thread_info.flags = 0;
 
+       /* We need a static PACA, too; copy this CPU's PACA over and switch to
+        * it.  Also poison per_cpu_offset to catch anyone using non-static
+        * data.
+        */
+       memcpy(&kexec_paca, get_paca(), sizeof(struct paca_struct));
+       kexec_paca.data_offset = 0xedeaddeadeeeeeeeUL;
+       paca = (struct paca_struct *)RELOC_HIDE(&kexec_paca, 0) -
+               kexec_paca.paca_index;
+       setup_paca(&kexec_paca);
+
+       /* XXX: If anyone does 'dynamic lppacas' this will also need to be
+        * switched to a static version!
+        */
+
        /* Some things are best done in assembly.  Finding globals with
         * a toc is easier in C, so pass in what we can.
         */