KVM: arm/arm64: Enable MSI routing
authorEric Auger <eric.auger@redhat.com>
Fri, 22 Jul 2016 16:20:42 +0000 (16:20 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Fri, 22 Jul 2016 17:52:03 +0000 (18:52 +0100)
Up to now, only irqchip routing entries could be set. This patch
adds the capability to insert MSI routing entries.

For ARM64, let's also increase KVM_MAX_IRQ_ROUTES to 4096: this
include SPI irqchip routes plus MSI routes. In the future this
might be extended.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Documentation/virtual/kvm/api.txt
include/linux/kvm_host.h
virt/kvm/arm/vgic/vgic-irqfd.c
virt/kvm/irqchip.c

index 7e5f9afcc693ed21d08eb4eaa5f74a34ec73a808..7a04216d727854ed5666c9816f0ac51cf203dedd 100644 (file)
@@ -2381,6 +2381,9 @@ On arm/arm64, gsi routing being supported, the following can happen:
 - in case no routing entry is associated to this gsi, injection fails
 - in case the gsi is associated to an irqchip routing entry,
   irqchip.pin + 32 corresponds to the injected SPI ID.
+- in case the gsi is associated to an MSI routing entry, the MSI
+  message and device ID are translated into an LPI (support restricted
+  to GICv3 ITS in-kernel emulation).
 
 4.76 KVM_PPC_ALLOCATE_HTAB
 
index a7eb5c48251ecb9cfb49df65a6c0856645b7f136..a318c3b216084a85c24cba0f1ebec9452ddb5ae1 100644 (file)
@@ -1048,6 +1048,8 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
 
 #ifdef CONFIG_S390
 #define KVM_MAX_IRQ_ROUTES 4096 //FIXME: we can have more than that...
+#elif defined(CONFIG_ARM64)
+#define KVM_MAX_IRQ_ROUTES 4096
 #else
 #define KVM_MAX_IRQ_ROUTES 1024
 #endif
index 6e84d530d9f73c39754937f6f37ae5e9edf4ddcb..683a589711b074993dfed52c42883ea4d0985124 100644 (file)
@@ -59,6 +59,14 @@ int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
                    (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;
        }
index 0c000546aedc2badbee3bb22bc8d399f1211418e..c6202199e5056372ae52b7ae096c950b90e01091 100644 (file)
@@ -178,6 +178,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;
 
@@ -201,23 +202,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(new, e, ue);
-               if (r) {
-                       kfree(e);
-                       goto out;
-               }
+               if (r)
+                       goto free_entry;
                ++ue;
        }
 
@@ -234,7 +237,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);