Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

irqchip/riscv-intc: Allow large non-standard interrupt number

Currently, the implementation of the RISC-V INTC driver uses the
interrupt cause as the hardware interrupt number, with a maximum of
64 interrupts. However, the platform can expand the interrupt number
further for custom local interrupts.

To fully utilize the available local interrupt sources, switch
to using irq_domain_create_tree() that creates the radix tree
map, add global variables (riscv_intc_nr_irqs, riscv_intc_custom_base
and riscv_intc_custom_nr_irqs) to determine the valid range of local
interrupt number (hwirq).

Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Randolph <randolph@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Link: https://lore.kernel.org/r/20240222083946.3977135-3-peterlin@andestech.com

authored by

Yu Chien Peter Lin and committed by
Thomas Gleixner
96303bcb 6613476e

+19 -7
+19 -7
drivers/irqchip/irq-riscv-intc.c
··· 19 19 #include <linux/smp.h> 20 20 21 21 static struct irq_domain *intc_domain; 22 + static unsigned int riscv_intc_nr_irqs __ro_after_init = BITS_PER_LONG; 23 + static unsigned int riscv_intc_custom_base __ro_after_init = BITS_PER_LONG; 24 + static unsigned int riscv_intc_custom_nr_irqs __ro_after_init; 22 25 23 26 static asmlinkage void riscv_intc_irq(struct pt_regs *regs) 24 27 { 25 28 unsigned long cause = regs->cause & ~CAUSE_IRQ_FLAG; 26 29 27 - if (unlikely(cause >= BITS_PER_LONG)) 28 - panic("unexpected interrupt cause"); 29 - 30 - generic_handle_domain_irq(intc_domain, cause); 30 + if (generic_handle_domain_irq(intc_domain, cause)) 31 + pr_warn_ratelimited("Failed to handle interrupt (cause: %ld)\n", cause); 31 32 } 32 33 33 34 /* ··· 94 93 if (ret) 95 94 return ret; 96 95 96 + /* 97 + * Only allow hwirq for which we have corresponding standard or 98 + * custom interrupt enable register. 99 + */ 100 + if ((hwirq >= riscv_intc_nr_irqs && hwirq < riscv_intc_custom_base) || 101 + (hwirq >= riscv_intc_custom_base + riscv_intc_custom_nr_irqs)) 102 + return -EINVAL; 103 + 97 104 for (i = 0; i < nr_irqs; i++) { 98 105 ret = riscv_intc_domain_map(domain, virq + i, hwirq + i); 99 106 if (ret) ··· 126 117 { 127 118 int rc; 128 119 129 - intc_domain = irq_domain_create_linear(fn, BITS_PER_LONG, 130 - &riscv_intc_domain_ops, NULL); 120 + intc_domain = irq_domain_create_tree(fn, &riscv_intc_domain_ops, NULL); 131 121 if (!intc_domain) { 132 122 pr_err("unable to add IRQ domain\n"); 133 123 return -ENXIO; ··· 140 132 141 133 riscv_set_intc_hwnode_fn(riscv_intc_hwnode); 142 134 143 - pr_info("%d local interrupts mapped\n", BITS_PER_LONG); 135 + pr_info("%d local interrupts mapped\n", riscv_intc_nr_irqs); 136 + if (riscv_intc_custom_nr_irqs) { 137 + pr_info("%d custom local interrupts mapped\n", 138 + riscv_intc_custom_nr_irqs); 139 + } 144 140 145 141 return 0; 146 142 }