Extend the GIC code to be able to generate a configuration with an IRS and 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 | 33 +++++++++++++++++++++++---------- arm64/include/kvm/gic.h | 1 + 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/arm64/gic.c b/arm64/gic.c index c144b42a..e0fb2547 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; @@ -223,6 +229,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: @@ -232,7 +239,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; @@ -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_PPI_IRQ_BASE + GIC_MAINT_IRQ; 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 f534ea5b..40ed500e 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; -- 2.34.1