obj-y += $(KVM)/arm/vgic/vgic-irqfd.o
 obj-y += $(KVM)/arm/vgic/vgic-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-v3.o
+obj-y += $(KVM)/arm/vgic/vgic-v4.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
 obj-y += $(KVM)/arm/vgic/vgic-mmio-v3.o
 
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-irqfd.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v4.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
 
 #include <linux/list.h>
 #include <linux/jump_label.h>
 
+#include <linux/irqchip/arm-gic-v4.h>
+
 #define VGIC_V3_MAX_CPUS       255
 #define VGIC_V2_MAX_CPUS       8
 #define VGIC_NR_IRQS_LEGACY     256
 
        /* used by vgic-debug */
        struct vgic_state_iter *iter;
+
+       /*
+        * GICv4 ITS per-VM data, containing the IRQ domain, the VPE
+        * array, the property table pointer as well as allocation
+        * data. This essentially ties the Linux IRQ core and ITS
+        * together, and avoids leaking KVM's data structures anywhere
+        * else.
+        */
+       struct its_vm           its_vm;
 };
 
 struct vgic_v2_cpu_if {
        u32             vgic_ap0r[4];
        u32             vgic_ap1r[4];
        u64             vgic_lr[VGIC_V3_MAX_LRS];
+
+       /*
+        * GICv4 ITS per-VPE data, containing the doorbell IRQ, the
+        * pending table pointer, the its_vm pointer and a few other
+        * HW specific things. As for the its_vm structure, this is
+        * linking the Linux IRQ subsystem and the ITS together.
+        */
+       struct its_vpe  its_vpe;
 };
 
 struct vgic_cpu {
 
        if (ret)
                goto out;
 
+       if (vgic_supports_direct_msis(kvm)) {
+               ret = vgic_v4_init(kvm);
+               if (ret)
+                       goto out;
+       }
+
        kvm_for_each_vcpu(i, vcpu, kvm)
                kvm_vgic_vcpu_enable(vcpu);
 
 
        kfree(dist->spis);
        dist->nr_spis = 0;
+
+       if (vgic_supports_direct_msis(kvm))
+               vgic_v4_teardown(kvm);
 }
 
 void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
 
        if (!its)
                return -ENOMEM;
 
+       if (vgic_initialized(dev->kvm)) {
+               int ret = vgic_v4_init(dev->kvm);
+               if (ret) {
+                       kfree(its);
+                       return ret;
+               }
+       }
+
        mutex_init(&its->its_lock);
        mutex_init(&its->cmd_lock);
 
 
--- /dev/null
+/*
+ * Copyright (C) 2017 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/kvm_host.h>
+
+#include "vgic.h"
+
+/**
+ * vgic_v4_init - Initialize the GICv4 data structures
+ * @kvm:       Pointer to the VM being initialized
+ *
+ * We may be called each time a vITS is created, or when the
+ * vgic is initialized. This relies on kvm->lock to be
+ * held. In both cases, the number of vcpus should now be
+ * fixed.
+ */
+int vgic_v4_init(struct kvm *kvm)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       struct kvm_vcpu *vcpu;
+       int i, nr_vcpus, ret;
+
+       if (dist->its_vm.vpes)
+               return 0;
+
+       nr_vcpus = atomic_read(&kvm->online_vcpus);
+
+       dist->its_vm.vpes = kzalloc(sizeof(*dist->its_vm.vpes) * nr_vcpus,
+                                   GFP_KERNEL);
+       if (!dist->its_vm.vpes)
+               return -ENOMEM;
+
+       dist->its_vm.nr_vpes = nr_vcpus;
+
+       kvm_for_each_vcpu(i, vcpu, kvm)
+               dist->its_vm.vpes[i] = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
+
+       ret = its_alloc_vcpu_irqs(&dist->its_vm);
+       if (ret < 0) {
+               kvm_err("VPE IRQ allocation failure\n");
+               kfree(dist->its_vm.vpes);
+               dist->its_vm.nr_vpes = 0;
+               dist->its_vm.vpes = NULL;
+               return ret;
+       }
+
+       return ret;
+}
+
+/**
+ * vgic_v4_teardown - Free the GICv4 data structures
+ * @kvm:       Pointer to the VM being destroyed
+ *
+ * Relies on kvm->lock to be held.
+ */
+void vgic_v4_teardown(struct kvm *kvm)
+{
+       struct its_vm *its_vm = &kvm->arch.vgic.its_vm;
+
+       if (!its_vm->vpes)
+               return;
+
+       its_free_vcpu_irqs(its_vm);
+       kfree(its_vm->vpes);
+       its_vm->nr_vpes = 0;
+       its_vm->vpes = NULL;
+}
 
 struct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi);
 
 bool vgic_supports_direct_msis(struct kvm *kvm);
+int vgic_v4_init(struct kvm *kvm);
+void vgic_v4_teardown(struct kvm *kvm);
 
 #endif