mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
irqchip/sifive-plic: Chain to parent IRQ after handlers are ready
commite306a894bd
upstream. Now that the PLIC uses a platform driver, the driver is probed later in the boot process, where interrupts from peripherals might already be pending. As a result, plic_handle_irq() may be called as early as the call to irq_set_chained_handler() completes. But this call happens before the per-context handler is completely set up, so there is a window where plic_handle_irq() can see incomplete per-context state and crash. Avoid this by delaying the call to irq_set_chained_handler() until all handlers from all PLICs are initialized. Fixes:8ec99b0331
("irqchip/sifive-plic: Convert PLIC driver into a platform driver") Reported-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Samuel Holland <samuel.holland@sifive.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Anup Patel <anup@brainfault.org> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240529215458.937817-1-samuel.holland@sifive.com Closes: https://lore.kernel.org/r/CAMuHMdVYFFR7K5SbHBLY-JHhb7YpgGMS_hnRWm8H0KD-wBo+4A@mail.gmail.com/ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a7854cea0f
commit
0215fc7246
1 changed files with 17 additions and 17 deletions
|
@ -85,7 +85,7 @@ struct plic_handler {
|
|||
struct plic_priv *priv;
|
||||
};
|
||||
static int plic_parent_irq __ro_after_init;
|
||||
static bool plic_cpuhp_setup_done __ro_after_init;
|
||||
static bool plic_global_setup_done __ro_after_init;
|
||||
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
|
||||
|
||||
static int plic_irq_set_type(struct irq_data *d, unsigned int type);
|
||||
|
@ -490,10 +490,8 @@ static int plic_probe(struct platform_device *pdev)
|
|||
unsigned long plic_quirks = 0;
|
||||
struct plic_handler *handler;
|
||||
u32 nr_irqs, parent_hwirq;
|
||||
struct irq_domain *domain;
|
||||
struct plic_priv *priv;
|
||||
irq_hw_number_t hwirq;
|
||||
bool cpuhp_setup;
|
||||
|
||||
if (is_of_node(dev->fwnode)) {
|
||||
const struct of_device_id *id;
|
||||
|
@ -552,14 +550,6 @@ static int plic_probe(struct platform_device *pdev)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Find parent domain and register chained handler */
|
||||
domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY);
|
||||
if (!plic_parent_irq && domain) {
|
||||
plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT);
|
||||
if (plic_parent_irq)
|
||||
irq_set_chained_handler(plic_parent_irq, plic_handle_irq);
|
||||
}
|
||||
|
||||
/*
|
||||
* When running in M-mode we need to ignore the S-mode handler.
|
||||
* Here we assume it always comes later, but that might be a
|
||||
|
@ -600,25 +590,35 @@ static int plic_probe(struct platform_device *pdev)
|
|||
goto fail_cleanup_contexts;
|
||||
|
||||
/*
|
||||
* We can have multiple PLIC instances so setup cpuhp state
|
||||
* We can have multiple PLIC instances so setup global state
|
||||
* and register syscore operations only once after context
|
||||
* handlers of all online CPUs are initialized.
|
||||
*/
|
||||
if (!plic_cpuhp_setup_done) {
|
||||
cpuhp_setup = true;
|
||||
if (!plic_global_setup_done) {
|
||||
struct irq_domain *domain;
|
||||
bool global_setup = true;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
handler = per_cpu_ptr(&plic_handlers, cpu);
|
||||
if (!handler->present) {
|
||||
cpuhp_setup = false;
|
||||
global_setup = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cpuhp_setup) {
|
||||
|
||||
if (global_setup) {
|
||||
/* Find parent domain and register chained handler */
|
||||
domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY);
|
||||
if (domain)
|
||||
plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT);
|
||||
if (plic_parent_irq)
|
||||
irq_set_chained_handler(plic_parent_irq, plic_handle_irq);
|
||||
|
||||
cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
|
||||
"irqchip/sifive/plic:starting",
|
||||
plic_starting_cpu, plic_dying_cpu);
|
||||
register_syscore_ops(&plic_irq_syscore_ops);
|
||||
plic_cpuhp_setup_done = true;
|
||||
plic_global_setup_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue