|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen staging] xen/riscv: add external interrupt handling for hypervisor mode
commit a8b85fabf609067ab3105a2abfbf14eccea68b9d
Author: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
AuthorDate: Thu Jul 10 13:40:23 2025 +0200
Commit: Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Jul 10 13:40:23 2025 +0200
xen/riscv: add external interrupt handling for hypervisor mode
Implement functions necessary 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>
Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
---
xen/arch/riscv/aplic.c | 73 ++++++++++++++++++++++++++++++++++++++
xen/arch/riscv/include/asm/aplic.h | 7 ++++
xen/arch/riscv/include/asm/imsic.h | 1 +
xen/arch/riscv/include/asm/intc.h | 6 ++++
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, 163 insertions(+), 1 deletion(-)
diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c
index edf4db3113..739e8dab34 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>
@@ -227,6 +228,73 @@ static void cf_check aplic_set_irq_affinity(struct
irq_desc *desc, const cpumask
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;
+
+ ASSERT(spin_is_locked(&desc->lock));
+
+ 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:
+ 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,
@@ -240,6 +308,8 @@ static const struct intc_hw_operations 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,
@@ -279,6 +349,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 7d811d3522..b0724fe6f3 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, U)
#define APLIC_DOMAINCFG_DM BIT(2, U)
+#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 378e49d933..c6c59215df 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 a11b7aa55e..ecdc8a5e65 100644
--- a/xen/arch/riscv/include/asm/intc.h
+++ b/xen/arch/riscv/include/asm/intc.h
@@ -14,6 +14,7 @@ enum intc_version {
INTC_APLIC,
};
+struct cpu_user_regs;
struct irq_desc;
struct intc_info {
@@ -37,6 +38,9 @@ struct intc_hw_operations {
void (*set_irq_type)(struct irq_desc *desc, unsigned int type);
/* 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);
@@ -47,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 84c3c2904d..94151eb083 100644
--- a/xen/arch/riscv/include/asm/irq.h
+++ b/xen/arch/riscv/include/asm/irq.h
@@ -33,16 +33,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 f2823267a9..ea317aea5a 100644
--- a/xen/arch/riscv/intc.c
+++ b/xen/arch/riscv/intc.c
@@ -50,6 +50,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 669ef3ae9e..466f1b4ba9 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];
@@ -90,3 +94,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;
}
--
generated by git-patchbot for /home/xen/git/xen.git#staging
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |