Commit cbc06f05 authored by Cédric Le Goater's avatar Cédric Le Goater Committed by Michael Ellerman

powerpc/xive: Do not skip CPU-less nodes when creating the IPIs

On PowerVM, CPU-less nodes can be populated with hot-plugged CPUs at
runtime. Today, the IPI is not created for such nodes, and hot-plugged
CPUs use a bogus IPI, which leads to soft lockups.

We can not directly allocate and request the IPI on demand because
bringup_up() is called under the IRQ sparse lock. The alternative is
to allocate the IPIs for all possible nodes at startup and to request
the mapping on demand when the first CPU of a node is brought up.

Fixes: 7dcc37b3 ("powerpc/xive: Map one IPI interrupt per node")
Cc: stable@vger.kernel.org # v5.13
Reported-by: default avatarGeetika Moolchandani <Geetika.Moolchandani1@ibm.com>
Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
Tested-by: default avatarSrikar Dronamraju <srikar@linux.vnet.ibm.com>
Tested-by: default avatarLaurent Vivier <lvivier@redhat.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210807072057.184698-1-clg@kaod.org
parent 01fcac8e
...@@ -67,6 +67,7 @@ static struct irq_domain *xive_irq_domain; ...@@ -67,6 +67,7 @@ static struct irq_domain *xive_irq_domain;
static struct xive_ipi_desc { static struct xive_ipi_desc {
unsigned int irq; unsigned int irq;
char name[16]; char name[16];
atomic_t started;
} *xive_ipis; } *xive_ipis;
/* /*
...@@ -1120,7 +1121,7 @@ static const struct irq_domain_ops xive_ipi_irq_domain_ops = { ...@@ -1120,7 +1121,7 @@ static const struct irq_domain_ops xive_ipi_irq_domain_ops = {
.alloc = xive_ipi_irq_domain_alloc, .alloc = xive_ipi_irq_domain_alloc,
}; };
static int __init xive_request_ipi(void) static int __init xive_init_ipis(void)
{ {
struct fwnode_handle *fwnode; struct fwnode_handle *fwnode;
struct irq_domain *ipi_domain; struct irq_domain *ipi_domain;
...@@ -1144,10 +1145,6 @@ static int __init xive_request_ipi(void) ...@@ -1144,10 +1145,6 @@ static int __init xive_request_ipi(void)
struct xive_ipi_desc *xid = &xive_ipis[node]; struct xive_ipi_desc *xid = &xive_ipis[node];
struct xive_ipi_alloc_info info = { node }; struct xive_ipi_alloc_info info = { node };
/* Skip nodes without CPUs */
if (cpumask_empty(cpumask_of_node(node)))
continue;
/* /*
* Map one IPI interrupt per node for all cpus of that node. * Map one IPI interrupt per node for all cpus of that node.
* Since the HW interrupt number doesn't have any meaning, * Since the HW interrupt number doesn't have any meaning,
...@@ -1159,11 +1156,6 @@ static int __init xive_request_ipi(void) ...@@ -1159,11 +1156,6 @@ static int __init xive_request_ipi(void)
xid->irq = ret; xid->irq = ret;
snprintf(xid->name, sizeof(xid->name), "IPI-%d", node); snprintf(xid->name, sizeof(xid->name), "IPI-%d", node);
ret = request_irq(xid->irq, xive_muxed_ipi_action,
IRQF_PERCPU | IRQF_NO_THREAD, xid->name, NULL);
WARN(ret < 0, "Failed to request IPI %d: %d\n", xid->irq, ret);
} }
return ret; return ret;
...@@ -1178,6 +1170,22 @@ static int __init xive_request_ipi(void) ...@@ -1178,6 +1170,22 @@ static int __init xive_request_ipi(void)
return ret; return ret;
} }
static int __init xive_request_ipi(unsigned int cpu)
{
struct xive_ipi_desc *xid = &xive_ipis[early_cpu_to_node(cpu)];
int ret;
if (atomic_inc_return(&xid->started) > 1)
return 0;
ret = request_irq(xid->irq, xive_muxed_ipi_action,
IRQF_PERCPU | IRQF_NO_THREAD,
xid->name, NULL);
WARN(ret < 0, "Failed to request IPI %d: %d\n", xid->irq, ret);
return ret;
}
static int xive_setup_cpu_ipi(unsigned int cpu) static int xive_setup_cpu_ipi(unsigned int cpu)
{ {
unsigned int xive_ipi_irq = xive_ipi_cpu_to_irq(cpu); unsigned int xive_ipi_irq = xive_ipi_cpu_to_irq(cpu);
...@@ -1192,6 +1200,9 @@ static int xive_setup_cpu_ipi(unsigned int cpu) ...@@ -1192,6 +1200,9 @@ static int xive_setup_cpu_ipi(unsigned int cpu)
if (xc->hw_ipi != XIVE_BAD_IRQ) if (xc->hw_ipi != XIVE_BAD_IRQ)
return 0; return 0;
/* Register the IPI */
xive_request_ipi(cpu);
/* Grab an IPI from the backend, this will populate xc->hw_ipi */ /* Grab an IPI from the backend, this will populate xc->hw_ipi */
if (xive_ops->get_ipi(cpu, xc)) if (xive_ops->get_ipi(cpu, xc))
return -EIO; return -EIO;
...@@ -1231,6 +1242,8 @@ static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc) ...@@ -1231,6 +1242,8 @@ static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
if (xc->hw_ipi == XIVE_BAD_IRQ) if (xc->hw_ipi == XIVE_BAD_IRQ)
return; return;
/* TODO: clear IPI mapping */
/* Mask the IPI */ /* Mask the IPI */
xive_do_source_set_mask(&xc->ipi_data, true); xive_do_source_set_mask(&xc->ipi_data, true);
...@@ -1253,7 +1266,7 @@ void __init xive_smp_probe(void) ...@@ -1253,7 +1266,7 @@ void __init xive_smp_probe(void)
smp_ops->cause_ipi = xive_cause_ipi; smp_ops->cause_ipi = xive_cause_ipi;
/* Register the IPI */ /* Register the IPI */
xive_request_ipi(); xive_init_ipis();
/* Allocate and setup IPI for the boot CPU */ /* Allocate and setup IPI for the boot CPU */
xive_setup_cpu_ipi(smp_processor_id()); xive_setup_cpu_ipi(smp_processor_id());
......
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