[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 14/16] xen/riscv: add external interrupt handling for hypervisor mode
Implement functions necessarry to have working external interrupts in hypervisor mode. The following changes are done: - Add a common function intc_handle_external_irq() to call APLIC specific function to handle an interrupt. - Update do_trap() function to handle IRQ_S_EXT case; add the check to catch case when cause of trap is an interrupt. - Add handle_interrrupt() member to intc_hw_operations structure. - Enable local interrupt delivery for IMSIC by calling of imsic_ids_local_delivery() in imsic_init(); additionally introduce helper imsic_csr_write() to update IMSIC_EITHRESHOLD and IMSIC_EITHRESHOLD. - Enable hypervisor external interrupts. - Implement aplic_handler_interrupt() and use it to init ->handle_interrupt member of intc_hw_operations for APLIC. - Add implementation of do_IRQ() to dispatch the interrupt. The current patch is based on the code from [1]. [1] https://gitlab.com/xen-project/people/olkur/xen/-/commit/7390e2365828b83e27ead56b03114a56e3699dd5 Co-developed-by: Romain Caritey <Romain.Caritey@xxxxxxxxxxxxx> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx> --- Changes in V2: - use BIT() macros instead of 1UL << bit_num in aplic.c. - Drop passing of a cause to aplic_handle_interrupt() function. And update prototype of handle_interrupt() callback. - Drop ASSERT() in intc_handle_external_irqs() as it is useless. - Code style fixes. - Drop cause argument for intc_handle_external_irqs(). - Update the commit message: drop words that imsic_ids_local_delivery() is implemented in this patch, it is only called. - Add cf_check for aplic_handle_interrupt(), aplic_set_irq_type(). - Move forward declarations in asm/intc.h up. - Use plain C operator instead if {clear,set}_bit() for desc->status as it is always used under spinlock(). - use writel() for writing to APLIC's sourcecfg in aplic_set_irq_type(). --- xen/arch/riscv/aplic.c | 70 ++++++++++++++++++++++++++++++ xen/arch/riscv/include/asm/aplic.h | 7 +++ xen/arch/riscv/include/asm/imsic.h | 1 + xen/arch/riscv/include/asm/intc.h | 5 +++ xen/arch/riscv/include/asm/irq.h | 6 ++- xen/arch/riscv/intc.c | 5 +++ xen/arch/riscv/irq.c | 47 ++++++++++++++++++++ xen/arch/riscv/traps.c | 19 ++++++++ 8 files changed, 159 insertions(+), 1 deletion(-) diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c index e2bee7ad23..ef7fc2562d 100644 --- a/xen/arch/riscv/aplic.c +++ b/xen/arch/riscv/aplic.c @@ -9,6 +9,7 @@ * Copyright (c) 2024-2025 Vates */ +#include <xen/const.h> #include <xen/device_tree.h> #include <xen/errno.h> #include <xen/init.h> @@ -220,6 +221,70 @@ static void aplic_set_irq_affinity(struct irq_desc *desc, const cpumask_t *mask) spin_unlock(&aplic.lock); } +static void cf_check aplic_handle_interrupt(struct cpu_user_regs *regs) +{ + /* disable to avoid more external interrupts */ + csr_clear(CSR_SIE, BIT(IRQ_S_EXT, UL)); + + /* clear the pending bit */ + csr_clear(CSR_SIP, BIT(IRQ_S_EXT, UL)); + + /* dispatch the interrupt */ + do_IRQ(regs, csr_swap(CSR_STOPEI, 0) >> TOPI_IID_SHIFT); + + /* enable external interrupts */ + csr_set(CSR_SIE, BIT(IRQ_S_EXT, UL)); +} + +static void cf_check aplic_set_irq_type(struct irq_desc *desc, unsigned int type) +{ + /* + * Interrupt 0 isn't possible based on the spec: + * Each of an APLIC’s interrupt sources has a fixed unique identity number in the range 1 to N, + * where N is the total number of sources at the APLIC. The number zero is not a valid interrupt + * identity number at an APLIC. The maximum number of interrupt sources an APLIC may support + * is 1023. + * + * Thereby interrupt 1 will correspond to bit 0 in sourcecfg[] register, + * interrupt 2 ->sourcecfg[1] and so on. + * + * And that is the reason why we need -1. + */ + unsigned int irq_bit = desc->irq - 1; + + spin_lock(&aplic.lock); + + switch(type) + { + case IRQ_TYPE_EDGE_RISING: + writel(APLIC_SOURCECFG_SM_EDGE_RISE, &aplic.regs->sourcecfg[irq_bit]); + break; + + case IRQ_TYPE_EDGE_FALLING: + writel(APLIC_SOURCECFG_SM_EDGE_FALL, &aplic.regs->sourcecfg[irq_bit]); + break; + + case IRQ_TYPE_LEVEL_HIGH: + writel(APLIC_SOURCECFG_SM_LEVEL_HIGH, &aplic.regs->sourcecfg[irq_bit]); + break; + + case IRQ_TYPE_LEVEL_LOW: + writel(APLIC_SOURCECFG_SM_LEVEL_LOW, &aplic.regs->sourcecfg[irq_bit]); + break; + + case IRQ_TYPE_NONE: + fallthrough; + case IRQ_TYPE_INVALID: + writel(APLIC_SOURCECFG_SM_INACTIVE, &aplic.regs->sourcecfg[irq_bit]); + break; + + default: + panic("%s: APLIC doesnt support IRQ type: 0x%x?\n", __func__, type); + } + + spin_unlock(&aplic.lock); +} + static const hw_irq_controller aplic_xen_irq_type = { .typename = "aplic", .startup = aplic_irq_startup, @@ -233,6 +298,8 @@ static struct intc_hw_operations __ro_after_init aplic_ops = { .info = &aplic_info, .init = aplic_init, .host_irq_type = &aplic_xen_irq_type, + .handle_interrupt = aplic_handle_interrupt, + .set_irq_type = aplic_set_irq_type, }; static int cf_check aplic_irq_xlate(const uint32_t *intspec, @@ -274,6 +341,9 @@ static int __init aplic_preinit(struct dt_device_node *node, const void *dat) register_intc_ops(&aplic_ops); + /* Enable supervisor external interrupt */ + csr_set(CSR_SIE, BIT(IRQ_S_EXT, UL)); + return 0; } diff --git a/xen/arch/riscv/include/asm/aplic.h b/xen/arch/riscv/include/asm/aplic.h index dc4ccbb9aa..661d9f294f 100644 --- a/xen/arch/riscv/include/asm/aplic.h +++ b/xen/arch/riscv/include/asm/aplic.h @@ -18,6 +18,13 @@ #define APLIC_DOMAINCFG_IE BIT(8, UL) #define APLIC_DOMAINCFG_DM BIT(2, UL) +#define APLIC_SOURCECFG_SM_INACTIVE 0x0 +#define APLIC_SOURCECFG_SM_DETACH 0x1 +#define APLIC_SOURCECFG_SM_EDGE_RISE 0x4 +#define APLIC_SOURCECFG_SM_EDGE_FALL 0x5 +#define APLIC_SOURCECFG_SM_LEVEL_HIGH 0x6 +#define APLIC_SOURCECFG_SM_LEVEL_LOW 0x7 + #define APLIC_TARGET_HART_IDX_SHIFT 18 struct aplic_regs { diff --git a/xen/arch/riscv/include/asm/imsic.h b/xen/arch/riscv/include/asm/imsic.h index 1d6ab4d685..c765d3d8e4 100644 --- a/xen/arch/riscv/include/asm/imsic.h +++ b/xen/arch/riscv/include/asm/imsic.h @@ -12,6 +12,7 @@ #define ASM__RISCV__IMSIC_H #include <xen/spinlock.h> +#include <xen/stdbool.h> #include <xen/types.h> #define IMSIC_MMIO_PAGE_SHIFT 12 diff --git a/xen/arch/riscv/include/asm/intc.h b/xen/arch/riscv/include/asm/intc.h index 45a41147a6..1efa80fff6 100644 --- a/xen/arch/riscv/include/asm/intc.h +++ b/xen/arch/riscv/include/asm/intc.h @@ -22,6 +22,7 @@ struct intc_info { unsigned int num_irqs; }; +struct cpu_user_regs; struct irq_desc; struct intc_hw_operations { @@ -38,6 +39,8 @@ struct intc_hw_operations { /* Set IRQ priority */ void (*set_irq_priority)(struct irq_desc *desc, unsigned int priority); + /* handle external interrupt */ + void (*handle_interrupt)(struct cpu_user_regs *regs); }; void intc_preinit(void); @@ -48,4 +51,6 @@ void intc_init(void); void intc_route_irq_to_xen(struct irq_desc *desc, unsigned int priority); +void intc_handle_external_irqs(struct cpu_user_regs *regs); + #endif /* ASM__RISCV__INTERRUPT_CONTOLLER_H */ diff --git a/xen/arch/riscv/include/asm/irq.h b/xen/arch/riscv/include/asm/irq.h index 6223bbbed5..1a05c5ff88 100644 --- a/xen/arch/riscv/include/asm/irq.h +++ b/xen/arch/riscv/include/asm/irq.h @@ -25,16 +25,20 @@ struct arch_irq_desc { unsigned int type; }; +struct cpu_user_regs; +struct dt_device_node; + static inline void arch_move_irqs(struct vcpu *v) { BUG_ON("unimplemented"); } -struct dt_device_node; int platform_get_irq(const struct dt_device_node *device, int index); void init_IRQ(void); +void do_IRQ(struct cpu_user_regs *regs, unsigned int irq); + #endif /* ASM__RISCV__IRQ_H */ /* diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c index 15f358601d..478401cc74 100644 --- a/xen/arch/riscv/intc.c +++ b/xen/arch/riscv/intc.c @@ -54,6 +54,11 @@ static void intc_set_irq_priority(struct irq_desc *desc, unsigned int priority) intc_hw_ops->set_irq_priority(desc, priority); } +void intc_handle_external_irqs(struct cpu_user_regs *regs) +{ + intc_hw_ops->handle_interrupt(regs); +} + void intc_route_irq_to_xen(struct irq_desc *desc, unsigned int priority) { ASSERT(desc->status & IRQ_DISABLED); diff --git a/xen/arch/riscv/irq.c b/xen/arch/riscv/irq.c index 4c518bbd97..056bdf3ca8 100644 --- a/xen/arch/riscv/irq.c +++ b/xen/arch/riscv/irq.c @@ -11,6 +11,10 @@ #include <xen/errno.h> #include <xen/init.h> #include <xen/irq.h> +#include <xen/spinlock.h> + +#include <asm/hardirq.h> +#include <asm/intc.h> static irq_desc_t irq_desc[NR_IRQS]; @@ -85,3 +89,46 @@ void __init init_IRQ(void) if ( init_irq_data() < 0 ) panic("initialization of IRQ data failed\n"); } + +/* Dispatch an interrupt */ +void do_IRQ(struct cpu_user_regs *regs, unsigned int irq) +{ + struct irq_desc *desc = irq_to_desc(irq); + struct irqaction *action; + + irq_enter(); + + spin_lock(&desc->lock); + + if ( desc->handler->ack ) + desc->handler->ack(desc); + + if ( desc->status & IRQ_DISABLED ) + goto out; + + desc->status |= IRQ_INPROGRESS; + + action = desc->action; + + spin_unlock_irq(&desc->lock); + +#ifndef CONFIG_IRQ_HAS_MULTIPLE_ACTION + action->handler(irq, action->dev_id); +#else + do { + action->handler(irq, action->dev_id); + action = action->next; + } while ( action ); +#endif /* CONFIG_IRQ_HAS_MULTIPLE_ACTION */ + + spin_lock_irq(&desc->lock); + + desc->status &= ~IRQ_INPROGRESS; + + out: + if ( desc->handler->end ) + desc->handler->end(desc); + + spin_unlock(&desc->lock); + irq_exit(); +} diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index ea3638a54f..f061004d83 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -11,6 +11,7 @@ #include <xen/nospec.h> #include <xen/sched.h> +#include <asm/intc.h> #include <asm/processor.h> #include <asm/riscv_encoding.h> #include <asm/traps.h> @@ -128,6 +129,24 @@ void do_trap(struct cpu_user_regs *cpu_regs) } fallthrough; default: + if ( cause & CAUSE_IRQ_FLAG ) + { + /* Handle interrupt */ + unsigned long icause = cause & ~CAUSE_IRQ_FLAG; + + switch ( icause ) + { + case IRQ_S_EXT: + intc_handle_external_irqs(cpu_regs); + break; + + default: + break; + } + + break; + } + do_unexpected_trap(cpu_regs); break; } -- 2.49.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |