Extend the GIC code to be able to generate a configuration with an ITS (`gicv5-its`). With this change, the guest is able to support MSIs. Note that the FDT changes to add the ITS node are made in a separate commit. Signed-off-by: Sascha Bischoff --- arm64/gic.c | 35 ++++++++++++++++++++++++----------- arm64/include/kvm/gic.h | 1 + arm64/pmu.c | 3 ++- arm64/timer.c | 3 ++- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/arm64/gic.c b/arm64/gic.c index 2152abf6..45dd2dab 100644 --- a/arm64/gic.c +++ b/arm64/gic.c @@ -51,6 +51,8 @@ int irqchip_parser(const struct option *opt, const char *arg, int unset) *type = IRQCHIP_GICV3_ITS; } else if (!strcmp(arg, "gicv5")) { *type = IRQCHIP_GICV5; + } else if (!strcmp(arg, "gicv5-its")) { + *type = IRQCHIP_GICV5_ITS; } else { pr_err("irqchip: unknown type \"%s\"\n", arg); return -1; @@ -107,15 +109,15 @@ static int irq__routing_init(struct kvm *kvm) return 0; } -static int gic__create_its_frame(struct kvm *kvm, u64 its_frame_addr) +static int gic__create_its_frame(struct kvm *kvm, u64 its_frame_addr, const bool v5) { struct kvm_create_device its_device = { - .type = KVM_DEV_TYPE_ARM_VGIC_ITS, + .type = v5 ? KVM_DEV_TYPE_ARM_VGIC_V5_ITS : KVM_DEV_TYPE_ARM_VGIC_ITS, .flags = 0, }; struct kvm_device_attr its_attr = { .group = KVM_DEV_ARM_VGIC_GRP_ADDR, - .attr = KVM_VGIC_ITS_ADDR_TYPE, + .attr = v5 ? KVM_VGIC_V5_ADDR_TYPE_ITS : KVM_VGIC_ITS_ADDR_TYPE, .addr = (u64)(unsigned long)&its_frame_addr, }; struct kvm_device_attr its_init_attr = { @@ -126,8 +128,9 @@ static int gic__create_its_frame(struct kvm *kvm, u64 its_frame_addr) err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &its_device); if (err) { - pr_err("GICv3 ITS requested, but kernel does not support it."); - pr_err("Try --irqchip=gicv3 instead"); + pr_err("GICv%c ITS requested, but kernel does not support it.", + v5 ? '5' : '3'); + pr_err("Try --irqchip=gicv%c instead", v5 ? '5' : '3'); return err; } @@ -152,7 +155,9 @@ static int gic__create_msi_frame(struct kvm *kvm, enum irqchip_type type, case IRQCHIP_GICV2M: return gic__create_gicv2m_frame(kvm, msi_frame_addr); case IRQCHIP_GICV3_ITS: - return gic__create_its_frame(kvm, msi_frame_addr); + return gic__create_its_frame(kvm, msi_frame_addr, false); + case IRQCHIP_GICV5_ITS: + return gic__create_its_frame(kvm, msi_frame_addr, true); default: /* No MSI frame needed */ return 0; } @@ -197,6 +202,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type) gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V3; dist_attr.attr = KVM_VGIC_V3_ADDR_TYPE_DIST; break; + case IRQCHIP_GICV5_ITS: case IRQCHIP_GICV5: gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V5; break; @@ -220,6 +226,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type) err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &redist_attr); break; case IRQCHIP_GICV5: + case IRQCHIP_GICV5_ITS: err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &gicv5_irs_attr); break; case IRQCHIP_AUTO: @@ -229,7 +236,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type) goto out_err; /* Only set the dist_attr for non-GICv5 */ - if (type != IRQCHIP_GICV5) { + if ((type != IRQCHIP_GICV5) && (type != IRQCHIP_GICV5_ITS)) { err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &dist_attr); if (err) goto out_err; @@ -244,7 +251,7 @@ static int gic__create_device(struct kvm *kvm, enum irqchip_type type) * and not at the legacy offset of 32. This must happen before any * interrupts are allocated. */ - if ((type == IRQCHIP_GICV5)) { + if ((type == IRQCHIP_GICV5) || (type == IRQCHIP_GICV5_ITS)) { err = irq__init_irq_offset(0); if (err) goto out_err; @@ -296,7 +303,7 @@ int gic__create(struct kvm *kvm, enum irqchip_type type) switch (type) { case IRQCHIP_AUTO: - for (try = IRQCHIP_GICV5; try >= IRQCHIP_GICV2; try--) { + for (try = IRQCHIP_GICV5_ITS; try >= IRQCHIP_GICV2; try--) { err = gic__create(kvm, try); if (!err) break; @@ -321,6 +328,10 @@ int gic__create(struct kvm *kvm, enum irqchip_type type) gic_redists_base = ARM_GIC_DIST_BASE - gic_redists_size; gic_msi_base = gic_redists_base - gic_msi_size; break; + case IRQCHIP_GICV5_ITS: + gic_msi_base = ARM_GICV5_ITS_BASE; + gic_msi_size = ARM_GICV5_ITS_SIZE; + /* fall through */ case IRQCHIP_GICV5: gicv5_irs_base = ARM_GICV5_IRS_BASE; gicv5_irs_size = ARM_GICV5_IRS_SIZE; @@ -348,7 +359,8 @@ static int gic__init_gic(struct kvm *kvm) u32 maint_irq = GIC_MAINT_IRQ + 16; /* PPI */ u32 nr_irqs; - if ((kvm->cfg.arch.irqchip != IRQCHIP_GICV5)) + if ((kvm->cfg.arch.irqchip != IRQCHIP_GICV5) && + (kvm->cfg.arch.irqchip != IRQCHIP_GICV5_ITS)) nr_irqs = ALIGN(lines, 32) + GIC_SPI_IRQ_BASE; else nr_irqs = roundup_pow_of_two(lines); @@ -525,7 +537,8 @@ u32 gic__get_fdt_irq_cpumask(struct kvm *kvm) /* Only for GICv2 */ if (kvm->cfg.arch.irqchip == IRQCHIP_GICV3 || kvm->cfg.arch.irqchip == IRQCHIP_GICV3_ITS || - kvm->cfg.arch.irqchip == IRQCHIP_GICV5) + kvm->cfg.arch.irqchip == IRQCHIP_GICV5 || + kvm->cfg.arch.irqchip == IRQCHIP_GICV5_ITS) return 0; if (kvm->nrcpus > 8) diff --git a/arm64/include/kvm/gic.h b/arm64/include/kvm/gic.h index 805f4247..0ef3aaa3 100644 --- a/arm64/include/kvm/gic.h +++ b/arm64/include/kvm/gic.h @@ -36,6 +36,7 @@ enum irqchip_type { IRQCHIP_GICV3, IRQCHIP_GICV3_ITS, IRQCHIP_GICV5, + IRQCHIP_GICV5_ITS, }; struct kvm; diff --git a/arm64/pmu.c b/arm64/pmu.c index 1720cc00..42cf81d3 100644 --- a/arm64/pmu.c +++ b/arm64/pmu.c @@ -200,7 +200,8 @@ void pmu__generate_fdt_nodes(void *fdt, struct kvm *kvm) u32 irq_prop[3]; u32 cpu_mask = gic__get_fdt_irq_cpumask(kvm); - if (kvm->cfg.arch.irqchip == IRQCHIP_GICV5) { + if (kvm->cfg.arch.irqchip == IRQCHIP_GICV5 || + kvm->cfg.arch.irqchip == IRQCHIP_GICV5_ITS) { irq_prop[0] = cpu_to_fdt32(GICV5_FDT_IRQ_TYPE_PPI); irq_prop[1] = cpu_to_fdt32(irq); /* For GICv5, encode the full intid by adding the type */ diff --git a/arm64/timer.c b/arm64/timer.c index 0945510d..20a4a808 100644 --- a/arm64/timer.c +++ b/arm64/timer.c @@ -17,7 +17,8 @@ void timer__generate_fdt_nodes(void *fdt, struct kvm *kvm) if (!kvm->cfg.arch.nested_virt) nr--; - if (kvm->cfg.arch.irqchip == IRQCHIP_GICV5) { + if (kvm->cfg.arch.irqchip == IRQCHIP_GICV5 || + kvm->cfg.arch.irqchip == IRQCHIP_GICV5_ITS) { type = GICV5_FDT_IRQ_TYPE_PPI; offset = 16; } else { -- 2.34.1