diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
index 96f6669d38..fb27e440fc 100644
--- a/xen/arch/arm/vgic/vgic-init.c
+++ b/xen/arch/arm/vgic/vgic-init.c
@@ -18,6 +18,7 @@
 #include <xen/lib.h>
 #include <xen/sched.h>
 #include <asm/new_vgic.h>
+#include <asm/gic_v3_its.h>
 
 #include "vgic.h"
 
@@ -173,8 +174,14 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
     }
 
     INIT_LIST_HEAD(&dist->lpi_list_head);
+    INIT_LIST_HEAD(&dist->lpi_translation_cache);
+    dist->lpi_list_count=0;
     spin_lock_init(&dist->lpi_list_lock);
 
+    ret = vgic_v3_its_init_domain(d);
+    if ( ret )
+        return ret;
+
     if ( dist->version == GIC_V2 )
         ret = vgic_v2_map_resources(d);
     else
diff --git a/xen/arch/arm/vgic/vgic-its.c b/xen/arch/arm/vgic/vgic-its.c
index 9534b26334..3b097bd0c4 100644
--- a/xen/arch/arm/vgic/vgic-its.c
+++ b/xen/arch/arm/vgic/vgic-its.c
@@ -168,7 +168,7 @@ static int update_lpi_config(struct domain *d, struct vgic_irq *irq,
     return 0;
 }
 
-static int vgic_v3_lpi_sync_pending_status(struct domain *d, struct vgic_irq *irq)
+int vgic_v3_lpi_sync_pending_status(struct domain *d, struct vgic_irq *irq)
 {
     struct vcpu *vcpu;
     int byte_offset, bit_nr;
diff --git a/xen/arch/arm/vgic/vgic-mmio-v3.c b/xen/arch/arm/vgic/vgic-mmio-v3.c
index 0e3835d38a..84aa8568dc 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v3.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v3.c
@@ -29,7 +29,7 @@ bool vgic_has_its(struct domain *d)
     if ( dist->version != GIC_V3 )
         return false;
 
-    return false;
+    return dist->has_its;
 }
 
 static struct vcpu *mpidr_to_vcpu(struct domain *d, unsigned long mpidr)
@@ -211,6 +211,29 @@ bool vgic_v3_emulate_reg(struct cpu_user_regs *regs, union hsr hsr)
     }
 }
 
+void vgic_flush_pending_lpis(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+    struct vgic_irq *irq, *tmp;
+    unsigned long flags;
+
+    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
+
+    list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list)
+    {
+        if ( irq->intid >= VGIC_MIN_LPI )
+        {
+            spin_lock(&irq->irq_lock);
+            list_del(&irq->ap_list);
+            irq->vcpu = NULL;
+            spin_unlock(&irq->irq_lock);
+            vgic_put_irq(vcpu->domain, irq);
+        }
+    }
+
+    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
+}
+
 /*
  * The Revision field in the IIDR have the following meanings:
  *
@@ -234,7 +257,15 @@ static unsigned long vgic_mmio_read_v3_misc(struct vcpu *vcpu, paddr_t addr,
     case GICD_TYPER:
         value = vgic->nr_spis + VGIC_NR_PRIVATE_IRQS;
         value = (value >> 5) - 1;
-        value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+        if ( vgic_has_its(vcpu->domain) )
+        {
+            value |= (INTERRUPT_ID_BITS_ITS - 1) << 19;
+            value |= GICD_TYPE_LPIS;
+        }
+        else
+        {
+            value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+        }
         break;
     case GICD_TYPER2:
         break;
@@ -365,6 +396,9 @@ static unsigned long vgic_mmio_read_v3r_typer(struct vcpu *vcpu, paddr_t addr,
     value = (u64)(mpidr & GENMASK(23, 0)) << 32;
     value |= ((target_vcpu_id & 0xffff) << 8);
 
+    if ( vgic_has_its(vcpu->domain) )
+        value |= GICR_TYPER_PLPIS;
+
     if ( vgic_mmio_vcpu_rdist_is_last(vcpu) )
         value |= GICR_TYPER_LAST;
 
@@ -422,12 +456,18 @@ static void vgic_mmio_write_v3r_ctlr(struct vcpu *vcpu, paddr_t addr,
                               GICR_CTLR_RWP);
         if ( ctlr != GICR_CTLR_ENABLE_LPIS )
             return;
+
+        vgic_flush_pending_lpis(vcpu);
+        vgic_its_invalidate_cache(vcpu->domain);
+        atomic_set(&vgic_cpu->ctlr, 0);
     }
     else
     {
         ctlr = atomic_cmpxchg(&vgic_cpu->ctlr, 0, GICR_CTLR_ENABLE_LPIS);
         if ( ctlr != 0 )
             return;
+
+        vgic_enable_lpis(vcpu);
     }
 }
 
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index 12f4d690f6..32fc7a6ba2 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -156,6 +156,7 @@ uint64_t update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
 #ifdef CONFIG_HAS_ITS
 int vgic_its_inv_lpi(struct domain *d, struct vgic_irq *irq);
 int vgic_its_invall(struct vcpu *vcpu);
+void vgic_its_invalidate_cache(struct domain *d);
 #else
 static inline int vgic_its_inv_lpi(struct domain *d, struct vgic_irq *irq)
 {
@@ -166,6 +167,10 @@ static inline int vgic_its_invall(struct vcpu *vcpu)
 {
     return 0;
 }
+
+static inline void vgic_its_invalidate_cache(struct domain *d)
+{
+}
 #endif
 
 #endif
