mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
5cd16ee934
commit
c5e24354ef
|
@ -200,14 +200,12 @@ static void __init pSeries_setup_arch(void)
|
||||||
if (ppc64_interrupt_controller == IC_OPEN_PIC) {
|
if (ppc64_interrupt_controller == IC_OPEN_PIC) {
|
||||||
ppc_md.init_IRQ = pSeries_init_mpic;
|
ppc_md.init_IRQ = pSeries_init_mpic;
|
||||||
ppc_md.get_irq = mpic_get_irq;
|
ppc_md.get_irq = mpic_get_irq;
|
||||||
ppc_md.cpu_irq_down = mpic_teardown_this_cpu;
|
|
||||||
/* Allocate the mpic now, so that find_and_init_phbs() can
|
/* Allocate the mpic now, so that find_and_init_phbs() can
|
||||||
* fill the ISUs */
|
* fill the ISUs */
|
||||||
pSeries_setup_mpic();
|
pSeries_setup_mpic();
|
||||||
} else {
|
} else {
|
||||||
ppc_md.init_IRQ = xics_init_IRQ;
|
ppc_md.init_IRQ = xics_init_IRQ;
|
||||||
ppc_md.get_irq = xics_get_irq;
|
ppc_md.get_irq = xics_get_irq;
|
||||||
ppc_md.cpu_irq_down = xics_teardown_cpu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
@ -595,6 +593,27 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus)
|
||||||
return PCI_PROBE_NORMAL;
|
return PCI_PROBE_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
|
||||||
|
{
|
||||||
|
/* Don't risk a hypervisor call if we're crashing */
|
||||||
|
if (!crash_shutdown) {
|
||||||
|
unsigned long vpa = __pa(&get_paca()->lppaca);
|
||||||
|
|
||||||
|
if (unregister_vpa(hard_smp_processor_id(), vpa)) {
|
||||||
|
printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
|
||||||
|
"failed\n", smp_processor_id(),
|
||||||
|
hard_smp_processor_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ppc64_interrupt_controller == IC_OPEN_PIC)
|
||||||
|
mpic_teardown_this_cpu(secondary);
|
||||||
|
else
|
||||||
|
xics_teardown_cpu(secondary);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct machdep_calls __initdata pSeries_md = {
|
struct machdep_calls __initdata pSeries_md = {
|
||||||
.probe = pSeries_probe,
|
.probe = pSeries_probe,
|
||||||
.setup_arch = pSeries_setup_arch,
|
.setup_arch = pSeries_setup_arch,
|
||||||
|
@ -617,4 +636,7 @@ struct machdep_calls __initdata pSeries_md = {
|
||||||
.check_legacy_ioport = pSeries_check_legacy_ioport,
|
.check_legacy_ioport = pSeries_check_legacy_ioport,
|
||||||
.system_reset_exception = pSeries_system_reset_exception,
|
.system_reset_exception = pSeries_system_reset_exception,
|
||||||
.machine_check_exception = pSeries_machine_check_exception,
|
.machine_check_exception = pSeries_machine_check_exception,
|
||||||
|
#ifdef CONFIG_KEXEC
|
||||||
|
.kexec_cpu_down = pseries_kexec_cpu_down,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -185,8 +185,8 @@ void kexec_copy_flush(struct kimage *image)
|
||||||
*/
|
*/
|
||||||
void kexec_smp_down(void *arg)
|
void kexec_smp_down(void *arg)
|
||||||
{
|
{
|
||||||
if (ppc_md.cpu_irq_down)
|
if (ppc_md.kexec_cpu_down)
|
||||||
ppc_md.cpu_irq_down(1);
|
ppc_md.kexec_cpu_down(0, 1);
|
||||||
|
|
||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
kexec_smp_wait();
|
kexec_smp_wait();
|
||||||
|
@ -233,8 +233,8 @@ static void kexec_prepare_cpus(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* after we tell the others to go down */
|
/* after we tell the others to go down */
|
||||||
if (ppc_md.cpu_irq_down)
|
if (ppc_md.kexec_cpu_down)
|
||||||
ppc_md.cpu_irq_down(0);
|
ppc_md.kexec_cpu_down(0, 0);
|
||||||
|
|
||||||
put_cpu();
|
put_cpu();
|
||||||
|
|
||||||
|
@ -255,8 +255,8 @@ static void kexec_prepare_cpus(void)
|
||||||
* UP to an SMP kernel.
|
* UP to an SMP kernel.
|
||||||
*/
|
*/
|
||||||
smp_release_cpus();
|
smp_release_cpus();
|
||||||
if (ppc_md.cpu_irq_down)
|
if (ppc_md.kexec_cpu_down)
|
||||||
ppc_md.cpu_irq_down(0);
|
ppc_md.kexec_cpu_down(0, 0);
|
||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,9 @@ struct machdep_calls {
|
||||||
|
|
||||||
void (*init_IRQ)(void);
|
void (*init_IRQ)(void);
|
||||||
int (*get_irq)(struct pt_regs *);
|
int (*get_irq)(struct pt_regs *);
|
||||||
void (*cpu_irq_down)(int secondary);
|
#ifdef CONFIG_KEXEC
|
||||||
|
void (*kexec_cpu_down)(int crash_shutdown, int secondary);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* PCI stuff */
|
/* PCI stuff */
|
||||||
/* Called after scanning the bus, before allocating resources */
|
/* Called after scanning the bus, before allocating resources */
|
||||||
|
|
Loading…
Reference in New Issue