#include <linux/dma-iommu.h>
 #include <linux/efi.h>
 #include <linux/interrupt.h>
+#include <linux/iopoll.h>
 #include <linux/irqdomain.h>
 #include <linux/list.h>
 #include <linux/log2.h>
        return IRQ_SET_MASK_OK_DONE;
 }
 
+static void its_wait_vpt_parse_complete(void)
+{
+       void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
+       u64 val;
+
+       if (!gic_rdists->has_vpend_valid_dirty)
+               return;
+
+       WARN_ON_ONCE(readq_relaxed_poll_timeout(vlpi_base + GICR_VPENDBASER,
+                                               val,
+                                               !(val & GICR_VPENDBASER_Dirty),
+                                               10, 500));
+}
+
 static void its_vpe_schedule(struct its_vpe *vpe)
 {
        void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
        val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0;
        val |= GICR_VPENDBASER_Valid;
        gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
+
+       its_wait_vpt_parse_complete();
 }
 
 static void its_vpe_deschedule(struct its_vpe *vpe)
        val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id);
 
        gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
+
+       its_wait_vpt_parse_complete();
 }
 
 static void its_vpe_4_1_deschedule(struct its_vpe *vpe,
 
        gic_data.rdists.has_rvpeid &= !!(typer & GICR_TYPER_RVPEID);
        gic_data.rdists.has_direct_lpi &= (!!(typer & GICR_TYPER_DirectLPIS) |
                                           gic_data.rdists.has_rvpeid);
+       gic_data.rdists.has_vpend_valid_dirty &= !!(typer & GICR_TYPER_DIRTY);
 
        /* Detect non-sensical configurations */
        if (WARN_ON_ONCE(gic_data.rdists.has_rvpeid && !gic_data.rdists.has_vlpis)) {
        if (WARN_ON(gic_data.ppi_nr == UINT_MAX))
                gic_data.ppi_nr = 0;
        pr_info("%d PPIs implemented\n", gic_data.ppi_nr);
-       pr_info("%sVLPI support, %sdirect LPI support, %sRVPEID support\n",
-               !gic_data.rdists.has_vlpis ? "no " : "",
-               !gic_data.rdists.has_direct_lpi ? "no " : "",
-               !gic_data.rdists.has_rvpeid ? "no " : "");
+       if (gic_data.rdists.has_vlpis)
+               pr_info("GICv4 features: %s%s%s\n",
+                       gic_data.rdists.has_direct_lpi ? "DirectLPI " : "",
+                       gic_data.rdists.has_rvpeid ? "RVPEID " : "",
+                       gic_data.rdists.has_vpend_valid_dirty ? "Valid+Dirty " : "");
 }
 
 /* Check whether it's single security state view */
        gic_data.rdists.has_rvpeid = true;
        gic_data.rdists.has_vlpis = true;
        gic_data.rdists.has_direct_lpi = true;
+       gic_data.rdists.has_vpend_valid_dirty = true;
 
        if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
                err = -ENOMEM;
 
 
 #define GICR_TYPER_PLPIS               (1U << 0)
 #define GICR_TYPER_VLPIS               (1U << 1)
+#define GICR_TYPER_DIRTY               (1U << 2)
 #define GICR_TYPER_DirectLPIS          (1U << 3)
 #define GICR_TYPER_LAST                        (1U << 4)
 #define GICR_TYPER_RVPEID              (1U << 7)
        bool                    has_vlpis;
        bool                    has_rvpeid;
        bool                    has_direct_lpi;
+       bool                    has_vpend_valid_dirty;
 };
 
 struct irq_domain;