summaryrefslogtreecommitdiff
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorAnup Patel <anup.patel@wdc.com>2020-05-18 12:14:40 +0300
committerMarc Zyngier <maz@kernel.org>2020-05-25 12:36:53 +0300
commit2234ae846ccb9ebdf4c391824cb79e73674dceda (patch)
tree8b38980639d35553face5c90abe5b966d54a0208 /drivers/irqchip
parent2458ed31e9b9ab40d78a452ab2650a0857556e85 (diff)
downloadlinux-2234ae846ccb9ebdf4c391824cb79e73674dceda.tar.xz
irqchip/sifive-plic: Setup cpuhp once after boot CPU handler is present
For multiple PLIC instances, the plic_init() is called once for each PLIC instance. Due to this we have two issues: 1. cpuhp_setup_state() is called multiple times 2. plic_starting_cpu() can crash for boot CPU if cpuhp_setup_state() is called before boot CPU PLIC handler is available. Address both issues by only initializing the HP notifiers when the boot CPU setup is complete. Fixes: f1ad1133b18f ("irqchip/sifive-plic: Add support for multiple PLICs") Signed-off-by: Anup Patel <anup.patel@wdc.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com> Acked-by: Palmer Dabbelt <palmerdabbelt@google.com> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200518091441.94843-3-anup.patel@wdc.com
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/irq-sifive-plic.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 9f7f8ce88c00..6c54abf5cc5e 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -76,6 +76,7 @@ struct plic_handler {
void __iomem *enable_base;
struct plic_priv *priv;
};
+static bool plic_cpuhp_setup_done;
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
static inline void plic_toggle(struct plic_handler *handler,
@@ -285,6 +286,7 @@ static int __init plic_init(struct device_node *node,
int error = 0, nr_contexts, nr_handlers = 0, i;
u32 nr_irqs;
struct plic_priv *priv;
+ struct plic_handler *handler;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -313,7 +315,6 @@ static int __init plic_init(struct device_node *node,
for (i = 0; i < nr_contexts; i++) {
struct of_phandle_args parent;
- struct plic_handler *handler;
irq_hw_number_t hwirq;
int cpu, hartid;
@@ -367,9 +368,18 @@ done:
nr_handlers++;
}
- cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
+ /*
+ * We can have multiple PLIC instances so setup cpuhp state only
+ * when context handler for current/boot CPU is present.
+ */
+ handler = this_cpu_ptr(&plic_handlers);
+ if (handler->present && !plic_cpuhp_setup_done) {
+ cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
"irqchip/sifive/plic:starting",
plic_starting_cpu, plic_dying_cpu);
+ plic_cpuhp_setup_done = true;
+ }
+
pr_info("mapped %d interrupts with %d handlers for %d contexts.\n",
nr_irqs, nr_handlers, nr_contexts);
set_handle_irq(plic_handle_irq);