Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] powerpc: Turn cpu_irq_down into kexec_cpu_down

We currently have a ppc_md member called cpu_irq_down, which disables IRQs
for the cpu in question. The only caller of cpu_irq_down is the kexec code.

On pSeries we need to do more than just teardown IRQs at kexec time, so rename
the ppc_md member to kexec_cpu_down and expand it. The pSeries code needs to
know, and other platforms might too, whether we're doing a crash shutdown (ie.
panicking) or a regular kexec, so add a flag for that.

The pSeries implementation of kexec_cpu_down does an unregister VPA call, which
tells the Hypervisor to stop writing stuff into our pacas. Without this we can
get weird memory corruption bugs when we kexec, caused by the Hypervisor
writing into the first kernel's pacas which happens to be somewhere interesting
in the second kernel's memory.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Michael Ellerman and committed by
Paul Mackerras
c5e24354 5cd16ee9

+33 -9
+24 -2
arch/powerpc/platforms/pseries/setup.c
··· 200 200 if (ppc64_interrupt_controller == IC_OPEN_PIC) { 201 201 ppc_md.init_IRQ = pSeries_init_mpic; 202 202 ppc_md.get_irq = mpic_get_irq; 203 - ppc_md.cpu_irq_down = mpic_teardown_this_cpu; 204 203 /* Allocate the mpic now, so that find_and_init_phbs() can 205 204 * fill the ISUs */ 206 205 pSeries_setup_mpic(); 207 206 } else { 208 207 ppc_md.init_IRQ = xics_init_IRQ; 209 208 ppc_md.get_irq = xics_get_irq; 210 - ppc_md.cpu_irq_down = xics_teardown_cpu; 211 209 } 212 210 213 211 #ifdef CONFIG_SMP ··· 593 595 return PCI_PROBE_NORMAL; 594 596 } 595 597 598 + #ifdef CONFIG_KEXEC 599 + static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) 600 + { 601 + /* Don't risk a hypervisor call if we're crashing */ 602 + if (!crash_shutdown) { 603 + unsigned long vpa = __pa(&get_paca()->lppaca); 604 + 605 + if (unregister_vpa(hard_smp_processor_id(), vpa)) { 606 + printk("VPA deregistration of cpu %u (hw_cpu_id %d) " 607 + "failed\n", smp_processor_id(), 608 + hard_smp_processor_id()); 609 + } 610 + } 611 + 612 + if (ppc64_interrupt_controller == IC_OPEN_PIC) 613 + mpic_teardown_this_cpu(secondary); 614 + else 615 + xics_teardown_cpu(secondary); 616 + } 617 + #endif 618 + 596 619 struct machdep_calls __initdata pSeries_md = { 597 620 .probe = pSeries_probe, 598 621 .setup_arch = pSeries_setup_arch, ··· 636 617 .check_legacy_ioport = pSeries_check_legacy_ioport, 637 618 .system_reset_exception = pSeries_system_reset_exception, 638 619 .machine_check_exception = pSeries_machine_check_exception, 620 + #ifdef CONFIG_KEXEC 621 + .kexec_cpu_down = pseries_kexec_cpu_down, 622 + #endif 639 623 };
+6 -6
arch/ppc64/kernel/machine_kexec.c
··· 185 185 */ 186 186 void kexec_smp_down(void *arg) 187 187 { 188 - if (ppc_md.cpu_irq_down) 189 - ppc_md.cpu_irq_down(1); 188 + if (ppc_md.kexec_cpu_down) 189 + ppc_md.kexec_cpu_down(0, 1); 190 190 191 191 local_irq_disable(); 192 192 kexec_smp_wait(); ··· 233 233 } 234 234 235 235 /* after we tell the others to go down */ 236 - if (ppc_md.cpu_irq_down) 237 - ppc_md.cpu_irq_down(0); 236 + if (ppc_md.kexec_cpu_down) 237 + ppc_md.kexec_cpu_down(0, 0); 238 238 239 239 put_cpu(); 240 240 ··· 255 255 * UP to an SMP kernel. 256 256 */ 257 257 smp_release_cpus(); 258 - if (ppc_md.cpu_irq_down) 259 - ppc_md.cpu_irq_down(0); 258 + if (ppc_md.kexec_cpu_down) 259 + ppc_md.kexec_cpu_down(0, 0); 260 260 local_irq_disable(); 261 261 } 262 262
+3 -1
include/asm-powerpc/machdep.h
··· 93 93 94 94 void (*init_IRQ)(void); 95 95 int (*get_irq)(struct pt_regs *); 96 - void (*cpu_irq_down)(int secondary); 96 + #ifdef CONFIG_KEXEC 97 + void (*kexec_cpu_down)(int crash_shutdown, int secondary); 98 + #endif 97 99 98 100 /* PCI stuff */ 99 101 /* Called after scanning the bus, before allocating resources */