Setup IPI_CALL_NMI_FUNC as a pseudo NMI using generic interrupt framework APIs. In case a plarform doesn't provide support for pseudo NMIs, switch back to IPI_CALL_NMI_FUNC being a normal interrupt.
Signed-off-by: Sumit Garg <sumit.g...@linaro.org> --- arch/arm64/kernel/smp.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 236784e..c5e42a1 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -68,6 +68,7 @@ struct secondary_data secondary_data; int cpus_stuck_in_kernel; static int ipi_irq_base; +static int ipi_nmi = -1; static int nr_ipi = NR_IPI; static struct irq_desc *ipi_desc[NR_IPI]; @@ -986,8 +987,14 @@ static void ipi_setup(int cpu) if (ipi_irq_base) { int i; - for (i = 0; i < nr_ipi; i++) - enable_percpu_irq(ipi_irq_base + i, 0); + for (i = 0; i < nr_ipi; i++) { + if (ipi_nmi == ipi_irq_base + i) { + if (!prepare_percpu_nmi(ipi_nmi)) + enable_percpu_nmi(ipi_nmi, 0); + } else { + enable_percpu_irq(ipi_irq_base + i, 0); + } + } } } @@ -997,23 +1004,33 @@ static void ipi_teardown(int cpu) int i; for (i = 0; i < nr_ipi; i++) - disable_percpu_irq(ipi_irq_base + i); + if (ipi_nmi == ipi_irq_base + i) { + disable_percpu_nmi(ipi_nmi); + teardown_percpu_nmi(ipi_nmi); + } else { + disable_percpu_irq(ipi_irq_base + i); + } } } void __init set_smp_ipi_range(int ipi_base, int n) { - int i; + int i, err; WARN_ON(n < NR_IPI); nr_ipi = min(n, NR_IPI); - for (i = 0; i < nr_ipi; i++) { - int err; + err = request_percpu_nmi(ipi_base + IPI_CALL_NMI_FUNC, + ipi_handler, "IPI", &irq_stat); + if (!err) + ipi_nmi = ipi_base + IPI_CALL_NMI_FUNC; - err = request_percpu_irq(ipi_base + i, ipi_handler, - "IPI", &irq_stat); - WARN_ON(err); + for (i = 0; i < nr_ipi; i++) { + if (ipi_base + i != ipi_nmi) { + err = request_percpu_irq(ipi_base + i, ipi_handler, + "IPI", &irq_stat); + WARN_ON(err); + } ipi_desc[i] = irq_to_desc(ipi_base + i); irq_set_status_flags(ipi_base + i, IRQ_NO_ACCOUNTING); -- 2.7.4