Files
xen/xen/arch/riscv/intc.c
T
Oleksii Kurochko 68ca2185e0 xen/riscv: introduce (de)initialization helpers for vINTC
Add common helpers domain_vintc_init() and domain_vintc_deinit() to
allocate and deallocate a virtual interrupt controller (vINTC)
structure and initialize basic virtual interrupt controller registers.

domain_vintc_deinit() isn't called at the moment as arch_domain_destroy()
is implemented as stub at the moment.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
2026-09-21 10:08:47 +02:00

121 lines
2.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/fdt-kernel.h>
#include <xen/init.h>
#include <xen/irq.h>
#include <xen/lib.h>
#include <xen/spinlock.h>
#include <asm/aia.h>
#include <asm/intc.h>
#include <asm/vaplic.h>
static const struct intc_hw_operations *__ro_after_init intc_hw_ops;
static const struct intc_hw_init_ops *__initdata intc_hw_init_ops;
void __init register_intc_ops(const struct intc_hw_init_ops *init_ops)
{
intc_hw_ops = init_ops->ops;
intc_hw_init_ops = init_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)
{
ASSERT(intc_hw_init_ops && intc_hw_init_ops->init);
aia_init();
if ( intc_hw_init_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);
}
int __init make_intc_domU_node(struct kernel_info *kinfo)
{
const struct vintc *vintc = kinfo->bd.d->arch.vintc;
return vintc->init_ops->make_domu_dt_node(kinfo);
}
int domain_vintc_init(struct domain *d)
{
int ret = -EOPNOTSUPP;
const enum intc_variant variant = intc_hw_ops->info->hw_variant;
switch ( variant )
{
case INTC_APLIC:
ret = domain_vaplic_init(d);
break;
default:
printk_once("vintc (variant:%d) isn't implemented\n", variant);
break;
}
return ret;
}
void domain_vintc_deinit(struct domain *d)
{
const enum intc_variant variant = intc_hw_ops->info->hw_variant;
switch ( variant )
{
case INTC_APLIC:
domain_vaplic_deinit(d);
break;
default:
break;
}
}