]> xenbits.xensource.com Git - people/julieng/linux-arm.git/commitdiff
KVM: arm64: add data structures to model ITS interrupt translation
authorAndre Przywara <andre.przywara@arm.com>
Fri, 10 Jul 2015 14:21:46 +0000 (15:21 +0100)
committerJulien Grall <julien.grall@citrix.com>
Mon, 28 Sep 2015 11:05:12 +0000 (12:05 +0100)
The GICv3 Interrupt Translation Service (ITS) uses tables in memory
to allow a sophisticated interrupt routing. It features device tables,
an interrupt table per device and a table connecting "collections" to
actual CPUs (aka. redistributors in the GICv3 lingo).
Since the interrupt numbers for the LPIs are allocated quite sparsely
and the range can be quite huge (8192 LPIs being the minimum), using
bitmaps or arrays for storing information is a waste of memory.
We use linked lists instead, which we iterate linearily. This works
very well with the actual number of LPIs/MSIs in the guest being
quite low. Should the number of LPIs exceed the number where iterating
through lists seems acceptable, we can later revisit this and use more
efficient data structures.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev@caviumnetworks.com>
include/kvm/arm_vgic.h
virt/kvm/arm/its-emul.c

index b43205514b07b9aa4aeeacfdd1b4f12e9549cdf0..1648668171ac9499e34e168094d3090b11ac38f1 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <kvm/iodev.h>
+#include <linux/list.h>
 
 #define VGIC_NR_IRQS_LEGACY    256
 #define VGIC_NR_SGIS           16
@@ -162,6 +163,8 @@ struct vgic_its {
        u64                     cbaser;
        int                     creadr;
        int                     cwriter;
+       struct list_head        device_list;
+       struct list_head        collection_list;
 };
 
 struct vgic_dist {
index b498f06b124c9c235b44e1f55bedb2151c9380c0..7f217fa6ea07ac3869cacc7f287afe047196e537 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 
 #include <linux/irqchip/arm-gic-v3.h>
 #include <kvm/arm_vgic.h>
 #include "vgic.h"
 #include "its-emul.h"
 
+struct its_device {
+       struct list_head dev_list;
+       struct list_head itt;
+       u32 device_id;
+};
+
+struct its_collection {
+       struct list_head coll_list;
+       u32 collection_id;
+       u32 target_addr;
+};
+
+struct its_itte {
+       struct list_head itte_list;
+       struct its_collection *collection;
+       u32 lpi;
+       u32 event_id;
+};
+
 #define BASER_BASE_ADDRESS(x) ((x) & 0xfffffffff000ULL)
 
 /* The distributor lock is held by the VGIC MMIO handler. */
@@ -311,6 +331,9 @@ int vits_init(struct kvm *kvm)
 
        spin_lock_init(&its->lock);
 
+       INIT_LIST_HEAD(&its->device_list);
+       INIT_LIST_HEAD(&its->collection_list);
+
        its->enabled = false;
 
        return -ENXIO;
@@ -320,11 +343,36 @@ void vits_destroy(struct kvm *kvm)
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
        struct vgic_its *its = &dist->its;
+       struct its_device *dev;
+       struct its_itte *itte;
+       struct list_head *dev_cur, *dev_temp;
+       struct list_head *cur, *temp;
 
        if (!vgic_has_its(kvm))
                return;
 
+       if (!its->device_list.next)
+               return;
+
+       spin_lock(&its->lock);
+       list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
+               dev = container_of(dev_cur, struct its_device, dev_list);
+               list_for_each_safe(cur, temp, &dev->itt) {
+                       itte = (container_of(cur, struct its_itte, itte_list));
+                       list_del(cur);
+                       kfree(itte);
+               }
+               list_del(dev_cur);
+               kfree(dev);
+       }
+
+       list_for_each_safe(cur, temp, &its->collection_list) {
+               list_del(cur);
+               kfree(container_of(cur, struct its_collection, coll_list));
+       }
+
        kfree(dist->pendbaser);
 
        its->enabled = false;
+       spin_unlock(&its->lock);
 }