mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/riscv: create APLIC DT node for guest domains
Guests require a Device Tree description of the interrupt controller topology. Add support for creating an APLIC node when building the guest DT. Provide stub for imsic_make_dt_node() it will be introduced properly in follow-up patch. The value chosen for GUEST_APLIC_S_BASE is based on QEMU one. DT-building functions are marked __init because domain creation happens at boot time, before the init sections are freed. In a typical deployment libxl creates the interrupt controller node in userspace and hands the complete FDT to Xen, so these functions are only called during early domain construction. 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:
1 parent
3559e12585
commit
3ecc6da8d6
5 files changed
+106
No files matched your search
@@ -34,4 +34,17 @@ struct aplic_priv {
|
||||
const struct imsic_config *imsic_cfg;
|
||||
};
|
||||
|
||||
/*
|
||||
* Value is inspired by what QEMU is using for riscv,num-sources property for
|
||||
* APLIC node.
|
||||
*/
|
||||
#define GUEST_APLIC_MAX_SOURCES 96U
|
||||
|
||||
/*
|
||||
* Specifies the number of interrupt sources supported by guest APLIC domain.
|
||||
* Could be limited by host interrupt controller and is identical for every
|
||||
* domain for now.
|
||||
*/
|
||||
extern unsigned int guest_aplic_num_sources;
|
||||
|
||||
#endif /* ASM_RISCV_APLIC_PRIV_H */
|
||||
@@ -92,6 +92,8 @@ static int __init cf_check aplic_init(void)
|
||||
panic("%s: failed to get number of interrupt sources\n",
|
||||
node->full_name);
|
||||
|
||||
guest_aplic_num_sources = min(GUEST_APLIC_MAX_SOURCES, aplic_info.num_irqs);
|
||||
|
||||
if ( aplic_info.num_irqs > ARRAY_SIZE(aplic.regs->sourcecfg) )
|
||||
aplic_info.num_irqs = ARRAY_SIZE(aplic.regs->sourcecfg);
|
||||
|
||||
|
||||
@@ -34,6 +34,14 @@
|
||||
|
||||
#define APLIC_TARGET_HART_IDX_SHIFT 18
|
||||
|
||||
#define APLIC_IDC_SIZE 32
|
||||
|
||||
#define APLIC_MIN_SIZE 0x4000
|
||||
#define APLIC_SIZE_ALIGN(x) ROUNDUP(x, APLIC_MIN_SIZE)
|
||||
|
||||
#define APLIC_SIZE(nr_cpus) (APLIC_MIN_SIZE + \
|
||||
APLIC_SIZE_ALIGN(APLIC_IDC_SIZE * (nr_cpus)))
|
||||
|
||||
struct aplic_regs {
|
||||
uint32_t domaincfg; /* 0x0000 */
|
||||
uint32_t sourcecfg[1023]; /* 0x0004 */
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
|
||||
#include <public/xen.h>
|
||||
|
||||
/*
|
||||
* Base address of the guest's supervisor-mode APLIC. The value is the address
|
||||
* typically used for APLIC by QEMU.
|
||||
*/
|
||||
#define GUEST_APLIC_S_BASE _UL(0xd000000)
|
||||
|
||||
/*
|
||||
* Base address of the guest's supervisor-mode IMSIC. The value is the address
|
||||
* typically used for IMSIC by QEMU.
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
|
||||
#include <xen/errno.h>
|
||||
#include <xen/fdt-kernel.h>
|
||||
#include <xen/libfdt/libfdt.h>
|
||||
#include <xen/sched.h>
|
||||
#include <xen/xvmalloc.h>
|
||||
|
||||
@@ -19,6 +21,80 @@
|
||||
|
||||
#include "aplic-priv.h"
|
||||
|
||||
unsigned int __ro_after_init guest_aplic_num_sources;
|
||||
|
||||
#define VAPLIC_COMPATIBLE "riscv,aplic"
|
||||
|
||||
#define FDT_VAPLIC_INT_CELLS 2
|
||||
|
||||
static int __init cf_check vaplic_make_domu_dt_node(struct kernel_info *kinfo)
|
||||
{
|
||||
struct domain *d = kinfo->bd.d;
|
||||
int res;
|
||||
void *fdt = kinfo->fdt;
|
||||
unsigned int msi_parent_phandle;
|
||||
char vaplic_name[32];
|
||||
unsigned int aplic_size = APLIC_SIZE(d->max_vcpus);
|
||||
const __be32 reg[] = {
|
||||
cpu_to_be32(GUEST_APLIC_S_BASE >> 32),
|
||||
cpu_to_be32(GUEST_APLIC_S_BASE),
|
||||
cpu_to_be32(0),
|
||||
cpu_to_be32(aplic_size),
|
||||
};
|
||||
|
||||
BUILD_BUG_ON(APLIC_SIZE(MAX_VIRT_CPUS) > UINT_MAX);
|
||||
|
||||
res = snprintf(vaplic_name, ARRAY_SIZE(vaplic_name), "/soc/aplic@%lx",
|
||||
GUEST_APLIC_S_BASE);
|
||||
if ( res >= sizeof(vaplic_name) )
|
||||
{
|
||||
dprintk(XENLOG_DEBUG, "vaplic name is truncated\n");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
res = vimsic_make_domu_dt_node(kinfo, &msi_parent_phandle);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_begin_node(fdt, vaplic_name);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_property_cell(fdt, "#interrupt-cells", FDT_VAPLIC_INT_CELLS);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_property(fdt, "reg", reg, sizeof(reg));
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_property_cell(fdt, "riscv,num-sources", guest_aplic_num_sources);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_property(fdt, "interrupt-controller", NULL, 0);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_property_string(fdt, "compatible", VAPLIC_COMPATIBLE);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_property_cell(fdt, "msi-parent", msi_parent_phandle);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
res = fdt_property_cell(fdt, "phandle", kinfo->phandle_intc);
|
||||
if ( res )
|
||||
return res;
|
||||
|
||||
return fdt_end_node(fdt);
|
||||
}
|
||||
|
||||
static const struct vintc_init_ops __initconstrel init_ops = {
|
||||
.make_domu_dt_node = vaplic_make_domu_dt_node,
|
||||
};
|
||||
|
||||
static const struct vintc_ops vintc_ops = {
|
||||
.vcpu_init = vcpu_imsic_init,
|
||||
.vcpu_deinit = vcpu_imsic_deinit,
|
||||
@@ -33,6 +109,7 @@ int domain_vaplic_init(struct domain *d)
|
||||
|
||||
d->arch.vintc = &vaplic->vintc;
|
||||
d->arch.vintc->ops = &vintc_ops;
|
||||
d->arch.vintc->init_ops = &init_ops;
|
||||
|
||||
vaplic->regs.domaincfg = APLIC_DOMAINCFG_RO;
|
||||
|
||||
|
||||