diff options
-rw-r--r-- | Documentation/admin-guide/kernel-parameters.txt | 7 | ||||
-rw-r--r-- | drivers/irqchip/irq-riscv-imsic-early.c | 20 | ||||
-rw-r--r-- | drivers/irqchip/irq-riscv-imsic-state.c | 7 | ||||
-rw-r--r-- | drivers/irqchip/irq-riscv-imsic-state.h | 1 |
4 files changed, 31 insertions, 4 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index f1f2c0874da9..7f0e12d0d260 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2538,6 +2538,13 @@ requires the kernel to be built with CONFIG_ARM64_PSEUDO_NMI. + irqchip.riscv_imsic_noipi + [RISC-V,EARLY] + Force the kernel to not use IMSIC software injected MSIs + as IPIs. Intended for system where IMSIC is trap-n-emulated, + and thus want to reduce MMIO traps when triggering IPIs + to multiple harts. + irqfixup [HW] When an interrupt is not handled search all handlers for it. Intended to get systems with badly broken diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c index d9ae87808651..2709cacf4855 100644 --- a/drivers/irqchip/irq-riscv-imsic-early.c +++ b/drivers/irqchip/irq-riscv-imsic-early.c @@ -8,6 +8,7 @@ #include <linux/acpi.h> #include <linux/cpu.h> #include <linux/interrupt.h> +#include <linux/init.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/irqchip.h> @@ -21,6 +22,14 @@ #include "irq-riscv-imsic-state.h" static int imsic_parent_irq; +bool imsic_noipi __ro_after_init; + +static int __init imsic_noipi_cfg(char *buf) +{ + imsic_noipi = true; + return 0; +} +early_param("irqchip.riscv_imsic_noipi", imsic_noipi_cfg); #ifdef CONFIG_SMP static void imsic_ipi_send(unsigned int cpu) @@ -32,12 +41,18 @@ static void imsic_ipi_send(unsigned int cpu) static void imsic_ipi_starting_cpu(void) { + if (imsic_noipi) + return; + /* Enable IPIs for current CPU. */ __imsic_id_set_enable(IMSIC_IPI_ID); } static void imsic_ipi_dying_cpu(void) { + if (imsic_noipi) + return; + /* Disable IPIs for current CPU. */ __imsic_id_clear_enable(IMSIC_IPI_ID); } @@ -46,6 +61,9 @@ static int __init imsic_ipi_domain_init(void) { int virq; + if (imsic_noipi) + return 0; + /* Create IMSIC IPI multiplexing */ virq = ipi_mux_create(IMSIC_NR_IPI, imsic_ipi_send); if (virq <= 0) @@ -88,7 +106,7 @@ static void imsic_handle_irq(struct irq_desc *desc) while ((local_id = csr_swap(CSR_TOPEI, 0))) { local_id >>= TOPEI_ID_SHIFT; - if (local_id == IMSIC_IPI_ID) { + if (!imsic_noipi && local_id == IMSIC_IPI_ID) { if (IS_ENABLED(CONFIG_SMP)) ipi_mux_process(); continue; diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c index 77670dd645ac..dc95ad856d80 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.c +++ b/drivers/irqchip/irq-riscv-imsic-state.c @@ -134,7 +134,7 @@ static bool __imsic_local_sync(struct imsic_local_priv *lpriv) lockdep_assert_held(&lpriv->lock); for_each_set_bit(i, lpriv->dirty_bitmap, imsic->global.nr_ids + 1) { - if (!i || i == IMSIC_IPI_ID) + if (!i || (!imsic_noipi && i == IMSIC_IPI_ID)) goto skip; vec = &lpriv->vectors[i]; @@ -419,7 +419,7 @@ void imsic_vector_debug_show(struct seq_file *m, struct imsic_vector *vec, int i seq_printf(m, "%*starget_cpu : %5u\n", ind, "", vec->cpu); seq_printf(m, "%*starget_local_id : %5u\n", ind, "", vec->local_id); seq_printf(m, "%*sis_reserved : %5u\n", ind, "", - (vec->local_id <= IMSIC_IPI_ID) ? 1 : 0); + (!imsic_noipi && vec->local_id <= IMSIC_IPI_ID) ? 1 : 0); seq_printf(m, "%*sis_enabled : %5u\n", ind, "", is_enabled ? 1 : 0); seq_printf(m, "%*sis_move_pending : %5u\n", ind, "", mvec ? 1 : 0); if (mvec) { @@ -583,7 +583,8 @@ static int __init imsic_matrix_init(void) irq_matrix_assign_system(imsic->matrix, 0, false); /* Reserve IPI ID because it is special and used internally */ - irq_matrix_assign_system(imsic->matrix, IMSIC_IPI_ID, false); + if (!imsic_noipi) + irq_matrix_assign_system(imsic->matrix, IMSIC_IPI_ID, false); return 0; } diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h index 3202ffa4e849..57f951952b0c 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.h +++ b/drivers/irqchip/irq-riscv-imsic-state.h @@ -61,6 +61,7 @@ struct imsic_priv { struct irq_domain *base_domain; }; +extern bool imsic_noipi; extern struct imsic_priv *imsic; void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend, bool val); |