diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-08-04 14:59:56 +0300 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-08-04 14:59:56 +0300 |
commit | 6f49b2f3414622d3e41135a65dac98968956662b (patch) | |
tree | efd4c358a40b9e6adb9dd35de3407bbf17bd2935 /virt | |
parent | abe9efa79be02cf2ba27f643b214b07877bb050b (diff) | |
parent | 89581f06b2bc225f0c9822fa52e714aa2e3810dd (diff) | |
download | linux-6f49b2f3414622d3e41135a65dac98968956662b.tar.xz |
Merge tag 'kvm-arm-for-4.8-take2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/ARM Changes for v4.8 - Take 2
Includes GSI routing support to go along with the new VGIC and a small fix that
has been cooking in -next for a while.
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/arm/vgic/vgic-init.c | 4 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-irqfd.c | 116 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic.c | 7 | ||||
-rw-r--r-- | virt/kvm/irqchip.c | 28 |
4 files changed, 120 insertions, 35 deletions
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c index 1e30ce08700d..fb4b0a79a950 100644 --- a/virt/kvm/arm/vgic/vgic-init.c +++ b/virt/kvm/arm/vgic/vgic-init.c @@ -264,6 +264,10 @@ int vgic_init(struct kvm *kvm) kvm_for_each_vcpu(i, vcpu, kvm) kvm_vgic_vcpu_init(vcpu); + ret = kvm_vgic_setup_default_irq_routing(kvm); + if (ret) + goto out; + dist->initialized = true; out: return ret; diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c index c675513270bb..b31a51a14efb 100644 --- a/virt/kvm/arm/vgic/vgic-irqfd.c +++ b/virt/kvm/arm/vgic/vgic-irqfd.c @@ -17,36 +17,116 @@ #include <linux/kvm.h> #include <linux/kvm_host.h> #include <trace/events/kvm.h> +#include <kvm/arm_vgic.h> +#include "vgic.h" -int kvm_irq_map_gsi(struct kvm *kvm, - struct kvm_kernel_irq_routing_entry *entries, - int gsi) +/** + * vgic_irqfd_set_irq: inject the IRQ corresponding to the + * irqchip routing entry + * + * This is the entry point for irqfd IRQ injection + */ +static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, + int level, bool line_status) { - return 0; + unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS; + + if (!vgic_valid_spi(kvm, spi_id)) + return -EINVAL; + return kvm_vgic_inject_irq(kvm, 0, spi_id, level); } -int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip, - unsigned int pin) +/** + * kvm_set_routing_entry: populate a kvm routing entry + * from a user routing entry + * + * @kvm: the VM this entry is applied to + * @e: kvm kernel routing entry handle + * @ue: user api routing entry handle + * return 0 on success, -EINVAL on errors. + */ +#ifdef KVM_CAP_X2APIC_API +int kvm_set_routing_entry(struct kvm *kvm, + struct kvm_kernel_irq_routing_entry *e, + const struct kvm_irq_routing_entry *ue) +#else +/* Remove this version and the ifdefery once merged into 4.8 */ +int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e, + const struct kvm_irq_routing_entry *ue) +#endif { - return pin; + int r = -EINVAL; + + switch (ue->type) { + case KVM_IRQ_ROUTING_IRQCHIP: + e->set = vgic_irqfd_set_irq; + e->irqchip.irqchip = ue->u.irqchip.irqchip; + e->irqchip.pin = ue->u.irqchip.pin; + if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) || + (e->irqchip.irqchip >= KVM_NR_IRQCHIPS)) + goto out; + break; + case KVM_IRQ_ROUTING_MSI: + e->set = kvm_set_msi; + e->msi.address_lo = ue->u.msi.address_lo; + e->msi.address_hi = ue->u.msi.address_hi; + e->msi.data = ue->u.msi.data; + e->msi.flags = ue->flags; + e->msi.devid = ue->u.msi.devid; + break; + default: + goto out; + } + r = 0; +out: + return r; } -int kvm_set_irq(struct kvm *kvm, int irq_source_id, - u32 irq, int level, bool line_status) +/** + * kvm_set_msi: inject the MSI corresponding to the + * MSI routing entry + * + * This is the entry point for irqfd MSI injection + * and userspace MSI injection. + */ +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, + int level, bool line_status) { - unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS; + struct kvm_msi msi; - trace_kvm_set_irq(irq, level, irq_source_id); + msi.address_lo = e->msi.address_lo; + msi.address_hi = e->msi.address_hi; + msi.data = e->msi.data; + msi.flags = e->msi.flags; + msi.devid = e->msi.devid; - BUG_ON(!vgic_initialized(kvm)); + if (!vgic_has_its(kvm)) + return -ENODEV; - return kvm_vgic_inject_irq(kvm, 0, spi, level); + return vgic_its_inject_msi(kvm, &msi); } -/* MSI not implemented yet */ -int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, - struct kvm *kvm, int irq_source_id, - int level, bool line_status) +int kvm_vgic_setup_default_irq_routing(struct kvm *kvm) { - return 0; + struct kvm_irq_routing_entry *entries; + struct vgic_dist *dist = &kvm->arch.vgic; + u32 nr = dist->nr_spis; + int i, ret; + + entries = kcalloc(nr, sizeof(struct kvm_kernel_irq_routing_entry), + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < nr; i++) { + entries[i].gsi = i; + entries[i].type = KVM_IRQ_ROUTING_IRQCHIP; + entries[i].u.irqchip.irqchip = 0; + entries[i].u.irqchip.pin = i; + } + ret = kvm_set_irq_routing(kvm, entries, nr, 0); + kfree(entries); + return ret; } diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c index 39f3358c6d91..e7aeac719e09 100644 --- a/virt/kvm/arm/vgic/vgic.c +++ b/virt/kvm/arm/vgic/vgic.c @@ -711,10 +711,3 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq) return map_is_active; } -int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) -{ - if (vgic_has_its(kvm)) - return vgic_its_inject_msi(kvm, msi); - else - return -ENODEV; -} diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index df99e9c3b64d..3bcc9990adf7 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -62,12 +62,14 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) { struct kvm_kernel_irq_routing_entry route; - if (!irqchip_in_kernel(kvm) || msi->flags != 0) + if (!irqchip_in_kernel(kvm) || (msi->flags & ~KVM_MSI_VALID_DEVID)) return -EINVAL; route.msi.address_lo = msi->address_lo; route.msi.address_hi = msi->address_hi; route.msi.data = msi->data; + route.msi.flags = msi->flags; + route.msi.devid = msi->devid; return kvm_set_msi(&route, kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 1, false); } @@ -177,6 +179,7 @@ int kvm_set_irq_routing(struct kvm *kvm, unsigned flags) { struct kvm_irq_routing_table *new, *old; + struct kvm_kernel_irq_routing_entry *e; u32 i, j, nr_rt_entries = 0; int r; @@ -200,23 +203,25 @@ int kvm_set_irq_routing(struct kvm *kvm, new->chip[i][j] = -1; for (i = 0; i < nr; ++i) { - struct kvm_kernel_irq_routing_entry *e; - r = -ENOMEM; e = kzalloc(sizeof(*e), GFP_KERNEL); if (!e) goto out; r = -EINVAL; - if (ue->flags) { - kfree(e); - goto out; + switch (ue->type) { + case KVM_IRQ_ROUTING_MSI: + if (ue->flags & ~KVM_MSI_VALID_DEVID) + goto free_entry; + break; + default: + if (ue->flags) + goto free_entry; + break; } r = setup_routing_entry(kvm, new, e, ue); - if (r) { - kfree(e); - goto out; - } + if (r) + goto free_entry; ++ue; } @@ -233,7 +238,10 @@ int kvm_set_irq_routing(struct kvm *kvm, new = old; r = 0; + goto out; +free_entry: + kfree(e); out: free_irq_routing_table(new); |