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@microchip.com>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Oleksii Kurochko authored and Jan Beulich committed 2025-07-10 13:40:23 +02:00
1 parent d4676a1398
commit a8b85fabf6
8 files changed
+163 -1

No files matched your search

+73
View File
@@ -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;
}
+7
View File
@@ -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 {
+1
View File
@@ -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
+6
View File
@@ -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 */
+5 -1
View File
@@ -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 */
/*
+5
View File
@@ -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);
+47
View File
@@ -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();
}
+19
View File
@@ -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;
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.