Files
xen/xen/arch/riscv/intc.c
T
Oleksii Kurochko a8b85fabf6 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>
2025-07-10 13:40:23 +02:00

70 lines
1.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
#include <xen/acpi.h>
#include <xen/bug.h>
#include <xen/device_tree.h>
#include <xen/init.h>
#include <xen/irq.h>
#include <xen/lib.h>
#include <xen/spinlock.h>
#include <asm/intc.h>
static const struct intc_hw_operations *__ro_after_init intc_hw_ops;
void __init register_intc_ops(const struct intc_hw_operations *ops)
{
intc_hw_ops = ops;
}
void __init intc_preinit(void)
{
if ( acpi_disabled )
intc_dt_preinit();
else
panic("ACPI interrupt controller preinit() isn't implemented\n");
}
void __init intc_init(void)
{
if ( intc_hw_ops->init() )
panic("Failed to initialize the interrupt controller drivers\n");
}
/* desc->irq needs to be disabled before calling this function */
static void intc_set_irq_type(struct irq_desc *desc, unsigned int type)
{
ASSERT(desc->status & IRQ_DISABLED);
ASSERT(spin_is_locked(&desc->lock));
ASSERT(type != IRQ_TYPE_INVALID);
if ( intc_hw_ops->set_irq_type )
intc_hw_ops->set_irq_type(desc, type);
}
static void intc_set_irq_priority(struct irq_desc *desc, unsigned int priority)
{
ASSERT(spin_is_locked(&desc->lock));
if ( intc_hw_ops->set_irq_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);
ASSERT(spin_is_locked(&desc->lock));
/* Can't route interrupts that don't exist */
ASSERT(intc_hw_ops && desc->irq < intc_hw_ops->info->num_irqs);
desc->handler = intc_hw_ops->host_irq_type;
intc_set_irq_type(desc, desc->arch.type);
intc_set_irq_priority(desc, priority);
}