Commit 45b21cfe authored by Michael Ellerman's avatar Michael Ellerman

powerpc/powernv: Fix oops on P9 DD1 in cause_ipi()

Recently we merged the native xive support for Power9, and then separately some
reworks for doorbell IPI support. In isolation both series were OK, but the
merged result had a bug in one case.

On P9 DD1 we use pnv_p9_dd1_cause_ipi() which tries to use doorbells, and then
falls back to the interrupt controller. However the fallback is implemented by
calling icp_ops->cause_ipi. But now that xive support is merged we might be
using xive, in which case icp_ops is not initialised, it's a xics specific
structure. This leads to an oops such as:

  Unable to handle kernel paging request for data at address 0x00000028
  Oops: Kernel access of bad area, sig: 11 [#1]
  NIP pnv_p9_dd1_cause_ipi+0x74/0xe0
  LR smp_muxed_ipi_message_pass+0x54/0x70

To fix it, rather than using icp_ops which might be NULL, have both xics and
xive set smp_ops->cause_ipi, and then in the powernv code we save that as
ic_cause_ipi before overriding smp_ops->cause_ipi. For paranoia add a WARN_ON()
to check if somehow smp_ops->cause_ipi is NULL.

Fixes: b866cc21 ("powerpc: Change the doorbell IPI calling convention")
Tested-by: default avatarGautham R. Shenoy <ego@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 83c49190
...@@ -249,12 +249,15 @@ static int pnv_smp_prepare_cpu(int cpu) ...@@ -249,12 +249,15 @@ static int pnv_smp_prepare_cpu(int cpu)
return 0; return 0;
} }
/* Cause IPI as setup by the interrupt controller (xics or xive) */
static void (*ic_cause_ipi)(int cpu);
static void pnv_cause_ipi(int cpu) static void pnv_cause_ipi(int cpu)
{ {
if (doorbell_try_core_ipi(cpu)) if (doorbell_try_core_ipi(cpu))
return; return;
icp_ops->cause_ipi(cpu); ic_cause_ipi(cpu);
} }
static void pnv_p9_dd1_cause_ipi(int cpu) static void pnv_p9_dd1_cause_ipi(int cpu)
...@@ -269,7 +272,7 @@ static void pnv_p9_dd1_cause_ipi(int cpu) ...@@ -269,7 +272,7 @@ static void pnv_p9_dd1_cause_ipi(int cpu)
if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu)))
doorbell_global_ipi(cpu); doorbell_global_ipi(cpu);
else else
icp_ops->cause_ipi(cpu); ic_cause_ipi(cpu);
put_cpu(); put_cpu();
} }
...@@ -282,6 +285,9 @@ static void __init pnv_smp_probe(void) ...@@ -282,6 +285,9 @@ static void __init pnv_smp_probe(void)
xics_smp_probe(); xics_smp_probe();
if (cpu_has_feature(CPU_FTR_DBELL)) { if (cpu_has_feature(CPU_FTR_DBELL)) {
ic_cause_ipi = smp_ops->cause_ipi;
WARN_ON(!ic_cause_ipi);
if (cpu_has_feature(CPU_FTR_ARCH_300)) { if (cpu_has_feature(CPU_FTR_ARCH_300)) {
if (cpu_has_feature(CPU_FTR_POWER9_DD1)) if (cpu_has_feature(CPU_FTR_POWER9_DD1))
smp_ops->cause_ipi = pnv_p9_dd1_cause_ipi; smp_ops->cause_ipi = pnv_p9_dd1_cause_ipi;
...@@ -290,8 +296,6 @@ static void __init pnv_smp_probe(void) ...@@ -290,8 +296,6 @@ static void __init pnv_smp_probe(void)
} else { } else {
smp_ops->cause_ipi = pnv_cause_ipi; smp_ops->cause_ipi = pnv_cause_ipi;
} }
} else {
smp_ops->cause_ipi = icp_ops->cause_ipi;
} }
} }
......
...@@ -145,6 +145,9 @@ void __init xics_smp_probe(void) ...@@ -145,6 +145,9 @@ void __init xics_smp_probe(void)
{ {
/* Register all the IPIs */ /* Register all the IPIs */
xics_request_ipi(); xics_request_ipi();
/* Setup cause_ipi callback based on which ICP is used */
smp_ops->cause_ipi = icp_ops->cause_ipi;
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment