Refactor kvm_arm_gicv3_put and add auxiliary functions to implement batch
register access.
Auxiliary functions:
-kvm_arm_gic_batch_write_plpis: batch write to LPI
-kvm_arm_gic_batch_write_redist: batch write to Redistributor
-kvm_arm_gic_batch_write_cpuif: batch write to CPU Interface

Signed-off-by: Chuan Zheng <[email protected]>
Signed-off-by: Yize Wang <[email protected]>
---
 hw/intc/arm_gicv3_kvm.c | 524 ++++++++++++++++++++++++++++++++--------
 1 file changed, 425 insertions(+), 99 deletions(-)

diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
index ea6c8462c7..1fdc554fe0 100644
--- a/hw/intc/arm_gicv3_kvm.c
+++ b/hw/intc/arm_gicv3_kvm.c
@@ -34,6 +34,7 @@
 #include "migration/misc.h"
 #include "qom/object.h"
 #include "target/arm/cpregs.h"
+#include "exec/cpu-defs.h"
 
 
 #define TYPE_KVM_ARM_GICV3 "kvm-arm-gicv3"
@@ -409,11 +410,298 @@ static void kvm_arm_gicv3_check(GICv3State *s)
     }
 }
 
+/* Write to the LPI base address registers in batches */
+static void kvm_arm_gic_batch_write_plpis(GICv3State *s,
+                                          GICv3BatchEntry **entries,
+                                          uint64_t redist_typer,
+                                          int *batch_n,
+                                          int *batch_capacity)
+{
+    if (!(redist_typer & GICR_TYPER_PLPIS)) {
+        return;
+    }
+
+    /*
+     * Allocate temporary buffers for the LPI base addresses
+     * of all CPUs.
+     */
+    uint32_t *plpis = g_new(uint32_t, s->num_cpu * 4);
+
+    for (int ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+        GICv3CPUState *c = &s->cpu[ncpu];
+        int base = ncpu * 4;
+
+        /* Split the 64-bit base address into two 32-bit values. */
+        plpis[base]     = (uint32_t)c->gicr_propbaser;
+        plpis[base + 1] = (uint32_t)(c->gicr_propbaser >> 32);
+        plpis[base + 2] = (uint32_t)c->gicr_pendbaser;
+        plpis[base + 3] = (uint32_t)(c->gicr_pendbaser >> 32);
+
+        /* Add to batch queueing */
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_PROPBASER, c->gicr_typer),
+                              &plpis[base]);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_PROPBASER + 4, c->gicr_typer),
+                              &plpis[base + 1]);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_PENDBASER, c->gicr_typer),
+                              &plpis[base + 2]);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_PENDBASER + 4, c->gicr_typer),
+                              &plpis[base + 3]);
+    }
+
+    /*
+     * Submit the LPI base address immediately.
+     * Note: After submission, the caller is responsible for resetting batch_n
+     * to reuse the entries array.
+     */
+    kvm_arm_gic_batch_commit(s->dev_fd, *entries, *batch_n, true);
+    g_free(plpis);
+}
+
+/* Write to the Redistributor common registers in batches */
+static void kvm_arm_gic_batch_write_redist(GICv3State *s,
+                                           GICv3BatchEntry **entries,
+                                           int *batch_n,
+                                           int *batch_capacity)
+{
+    uint32_t clear_all = ~0;
+    uint32_t *redist_icfgr1 = g_new(uint32_t, s->num_cpu);
+    uint32_t *redist_priority = g_new(uint32_t,
+                    s->num_cpu * (GIC_INTERNAL / 4));
+
+    for (int ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+        GICv3CPUState *c = &s->cpu[ncpu];
+        int pri_base = ncpu * (GIC_INTERNAL / 4);
+
+        redist_icfgr1[ncpu] = half_shuffle32(c->edge_trigger >> 16) << 1;
+
+        /* control and status register */
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_CTLR, c->gicr_typer),
+                              &c->gicr_ctlr);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_STATUSR, c->gicr_typer),
+                              &c->gicr_statusr[GICV3_NS]);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_WAKER, c->gicr_typer),
+                              &c->gicr_waker);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_IGROUPR0, c->gicr_typer),
+                              &c->gicr_igroupr0);
+
+        /* Enable register (clear-set mode) */
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_ICENABLER0, c->gicr_typer),
+                              &clear_all);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_ISENABLER0, c->gicr_typer),
+                              &c->gicr_ienabler0);
+
+        /* Configure register */
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_ICFGR1, c->gicr_typer),
+                              &redist_icfgr1[ncpu]);
+
+        /* Level information */
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO,
+                              KVM_VGIC_ATTR(0, c->gicr_typer) |
+                              (VGIC_LEVEL_INFO_LINE_LEVEL <<
+                               KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT),
+                              &c->level);
+
+        /* Suspend register (Clear-Set mode) */
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_ICPENDR0, c->gicr_typer),
+                              &clear_all);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_ISPENDR0, c->gicr_typer),
+                              &c->gicr_ipendr0);
+
+        /* Activation register (Clear-Set mode) */
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_ICACTIVER0, c->gicr_typer),
+                              &clear_all);
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                              KVM_VGIC_ATTR(GICR_ISACTIVER0, c->gicr_typer),
+                              &c->gicr_iactiver0);
+
+        /* Priority register (written in packet mode) */
+        for (int i = 0; i < GIC_INTERNAL; i += 4) {
+            redist_priority[pri_base + i / 4] =
+                c->gicr_ipriorityr[i] |
+                (c->gicr_ipriorityr[i + 1] << 8) |
+                (c->gicr_ipriorityr[i + 2] << 16) |
+                (c->gicr_ipriorityr[i + 3] << 24);
+
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_REDIST_REGS,
+                                  KVM_VGIC_ATTR(GICR_IPRIORITYR + i,
+                                                c->gicr_typer),
+                                  &redist_priority[pri_base + i / 4]);
+        }
+    }
+
+    /* Submit all Redistributor statuses */
+    kvm_arm_gic_batch_commit(s->dev_fd, *entries, *batch_n, true);
+
+    g_free(redist_icfgr1);
+    g_free(redist_priority);
+}
+
+/* Batch Write to CPU Interface */
+static void kvm_arm_gic_batch_write_cpuif(GICv3State *s,
+                                          GICv3BatchEntry **entries,
+                                          int *batch_n,
+                                          int *batch_capacity)
+{
+    uint32_t *cpuif_sre = g_new0(uint32_t, s->num_cpu);
+    uint32_t *cpuif_ctlr = g_new0(uint32_t, s->num_cpu);
+    uint32_t *cpuif_igrpen0 = g_new0(uint32_t, s->num_cpu);
+    uint32_t *cpuif_igrpen1 = g_new0(uint32_t, s->num_cpu);
+    uint32_t *cpuif_pmr = g_new0(uint32_t, s->num_cpu);
+    uint32_t *cpuif_bpr0 = g_new0(uint32_t, s->num_cpu);
+    uint32_t *cpuif_bpr1 = g_new0(uint32_t, s->num_cpu);
+
+    for (int ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+        GICv3CPUState *c = &s->cpu[ncpu];
+        int num_pri_bits;
+
+        /* Basic system registers */
+        cpuif_sre[ncpu] = c->icc_sre_el1;
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                              KVM_VGIC_ATTR(ICC_SRE_EL1, c->gicr_typer),
+                              &cpuif_sre[ncpu]);
+
+        cpuif_ctlr[ncpu] = c->icc_ctlr_el1[GICV3_NS];
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                              KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer),
+                              &cpuif_ctlr[ncpu]);
+
+        cpuif_igrpen0[ncpu] = c->icc_igrpen[GICV3_G0];
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                              KVM_VGIC_ATTR(ICC_IGRPEN0_EL1, c->gicr_typer),
+                              &cpuif_igrpen0[ncpu]);
+
+        cpuif_igrpen1[ncpu] = c->icc_igrpen[GICV3_G1NS];
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                              KVM_VGIC_ATTR(ICC_IGRPEN1_EL1, c->gicr_typer),
+                              &cpuif_igrpen1[ncpu]);
+
+        cpuif_pmr[ncpu] = c->icc_pmr_el1;
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                              KVM_VGIC_ATTR(ICC_PMR_EL1, c->gicr_typer),
+                              &cpuif_pmr[ncpu]);
+
+        cpuif_bpr0[ncpu] = c->icc_bpr[GICV3_G0];
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                              KVM_VGIC_ATTR(ICC_BPR0_EL1, c->gicr_typer),
+                              &cpuif_bpr0[ncpu]);
+
+        cpuif_bpr1[ncpu] = c->icc_bpr[GICV3_G1NS];
+        kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                              KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                              KVM_VGIC_ATTR(ICC_BPR1_EL1, c->gicr_typer),
+                              &cpuif_bpr1[ncpu]);
+
+        /* Calculate the number of priority bits */
+        num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] &
+                        ICC_CTLR_EL1_PRIBITS_MASK) >>
+                        ICC_CTLR_EL1_PRIBITS_SHIFT) + 1;
+
+        /* Group 0 APR */
+        switch (num_pri_bits) {
+        case 7:
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP0R_EL1(3), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G0][3]);
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP0R_EL1(2), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G0][2]);
+            /* fall through */
+        case 6:
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP0R_EL1(1), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G0][1]);
+            /* fall through */
+        default:
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP0R_EL1(0), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G0][0]);
+        }
+
+        /* Group 1 APR */
+        switch (num_pri_bits) {
+        case 7:
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP1R_EL1(3), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G1NS][3]);
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP1R_EL1(2), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G1NS][2]);
+            /* fall through */
+        case 6:
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP1R_EL1(1), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G1NS][1]);
+            /* fall through */
+        default:
+            kvm_arm_gic_batch_add(entries, batch_n, batch_capacity,
+                                  KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS,
+                                  KVM_VGIC_ATTR(ICC_AP1R_EL1(0), 
c->gicr_typer),
+                                  (uint32_t *)&c->icc_apr[GICV3_G1NS][0]);
+        }
+    }
+
+    /* Submit all CPU Interface statuses */
+    kvm_arm_gic_batch_commit(s->dev_fd, *entries, *batch_n, true);
+
+    g_free(cpuif_sre);
+    g_free(cpuif_ctlr);
+    g_free(cpuif_igrpen0);
+    g_free(cpuif_igrpen1);
+    g_free(cpuif_pmr);
+    g_free(cpuif_bpr0);
+    g_free(cpuif_bpr1);
+}
+
 static void kvm_arm_gicv3_put(GICv3State *s)
 {
     uint32_t regl, regh, reg;
     uint64_t reg64, redist_typer;
     int ncpu, i;
+    bool batch_supported;
     int64_t start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 
     kvm_arm_gicv3_check(s);
@@ -425,71 +713,95 @@ static void kvm_arm_gicv3_put(GICv3State *s)
     reg = s->gicd_ctlr;
     kvm_gicd_access(s, GICD_CTLR, &reg, true);
 
-    if (redist_typer & GICR_TYPER_PLPIS) {
-        /*
-         * Restore base addresses before LPIs are potentially enabled by
-         * GICR_CTLR write
-         */
-        for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
-            GICv3CPUState *c = &s->cpu[ncpu];
+    batch_supported = kvm_arm_gic_batch_supported(s->dev_fd);
+
+    if (batch_supported) {
+        {
+            GICv3BatchEntry *entries = g_new(GICv3BatchEntry, 256);
+            int batch_n = 0;
+            int batch_capacity = 256;
+
+            /* write LPI */
+            kvm_arm_gic_batch_write_plpis(s, &entries, redist_typer,
+                                          &batch_n, &batch_capacity);
+
+            /* reset batch_n */
+            batch_n = 0;
+
+            /* write Redistributor status */
+            kvm_arm_gic_batch_write_redist(s, &entries, &batch_n,
+                                           &batch_capacity);
 
-            reg64 = c->gicr_propbaser;
-            regl = (uint32_t)reg64;
-            kvm_gicr_access(s, GICR_PROPBASER, ncpu, &regl, true);
-            regh = (uint32_t)(reg64 >> 32);
-            kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, &regh, true);
-
-            reg64 = c->gicr_pendbaser;
-            regl = (uint32_t)reg64;
-            kvm_gicr_access(s, GICR_PENDBASER, ncpu, &regl, true);
-            regh = (uint32_t)(reg64 >> 32);
-            kvm_gicr_access(s, GICR_PENDBASER + 4, ncpu, &regh, true);
+            g_free(entries);
+        }
+    } else {
+        if (redist_typer & GICR_TYPER_PLPIS) {
+            /*
+             * Restore base addresses before LPIs are potentially enabled by
+             * GICR_CTLR write
+             */
+            for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+                GICv3CPUState *c = &s->cpu[ncpu];
+
+                reg64 = c->gicr_propbaser;
+                regl = (uint32_t)reg64;
+                kvm_gicr_access(s, GICR_PROPBASER, ncpu, &regl, true);
+                regh = (uint32_t)(reg64 >> 32);
+                kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, &regh, true);
+
+                reg64 = c->gicr_pendbaser;
+                regl = (uint32_t)reg64;
+                kvm_gicr_access(s, GICR_PENDBASER, ncpu, &regl, true);
+                regh = (uint32_t)(reg64 >> 32);
+                kvm_gicr_access(s, GICR_PENDBASER + 4, ncpu, &regh, true);
+            }
         }
-    }
 
-    /* Redistributor state (one per CPU) */
+        /* Redistributor state (one per CPU) */
 
-    for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
-        GICv3CPUState *c = &s->cpu[ncpu];
+        for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+            GICv3CPUState *c = &s->cpu[ncpu];
+            uint32_t clear_all = ~0;
 
-        reg = c->gicr_ctlr;
-        kvm_gicr_access(s, GICR_CTLR, ncpu, &reg, true);
+            reg = c->gicr_ctlr;
+            kvm_gicr_access(s, GICR_CTLR, ncpu, &reg, true);
 
-        reg = c->gicr_statusr[GICV3_NS];
-        kvm_gicr_access(s, GICR_STATUSR, ncpu, &reg, true);
+            reg = c->gicr_statusr[GICV3_NS];
+            kvm_gicr_access(s, GICR_STATUSR, ncpu, &reg, true);
 
-        reg = c->gicr_waker;
-        kvm_gicr_access(s, GICR_WAKER, ncpu, &reg, true);
+            reg = c->gicr_waker;
+            kvm_gicr_access(s, GICR_WAKER, ncpu, &reg, true);
 
-        reg = c->gicr_igroupr0;
-        kvm_gicr_access(s, GICR_IGROUPR0, ncpu, &reg, true);
+            reg = c->gicr_igroupr0;
+            kvm_gicr_access(s, GICR_IGROUPR0, ncpu, &reg, true);
 
-        reg = ~0;
-        kvm_gicr_access(s, GICR_ICENABLER0, ncpu, &reg, true);
-        reg = c->gicr_ienabler0;
-        kvm_gicr_access(s, GICR_ISENABLER0, ncpu, &reg, true);
+            reg = clear_all;
+            kvm_gicr_access(s, GICR_ICENABLER0, ncpu, &reg, true);
+            reg = c->gicr_ienabler0;
+            kvm_gicr_access(s, GICR_ISENABLER0, ncpu, &reg, true);
 
-        /* Restore config before pending so we treat level/edge correctly */
-        reg = half_shuffle32(c->edge_trigger >> 16) << 1;
-        kvm_gicr_access(s, GICR_ICFGR1, ncpu, &reg, true);
+            /* Restore config before pending so we treat level/edge correctly 
*/
+            reg = half_shuffle32(c->edge_trigger >> 16) << 1;
+            kvm_gicr_access(s, GICR_ICFGR1, ncpu, &reg, true);
 
-        reg = c->level;
-        kvm_gic_line_level_access(s, 0, ncpu, &reg, true);
+            reg = c->level;
+            kvm_gic_line_level_access(s, 0, ncpu, &reg, true);
 
-        reg = c->gicr_ipendr0;
-        kvm_gicr_access(s, GICR_ISPENDR0, ncpu, &reg, true);
+            reg = c->gicr_ipendr0;
+            kvm_gicr_access(s, GICR_ISPENDR0, ncpu, &reg, true);
 
-        reg = ~0;
-        kvm_gicr_access(s, GICR_ICACTIVER0, ncpu, &reg, true);
-        reg = c->gicr_iactiver0;
-        kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, &reg, true);
+            reg = clear_all;
+            kvm_gicr_access(s, GICR_ICACTIVER0, ncpu, &reg, true);
+            reg = c->gicr_iactiver0;
+            kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, &reg, true);
 
-        for (i = 0; i < GIC_INTERNAL; i += 4) {
-            reg = c->gicr_ipriorityr[i] |
-                (c->gicr_ipriorityr[i + 1] << 8) |
-                (c->gicr_ipriorityr[i + 2] << 16) |
-                (c->gicr_ipriorityr[i + 3] << 24);
-            kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, &reg, true);
+            for (i = 0; i < GIC_INTERNAL; i += 4) {
+                reg = c->gicr_ipriorityr[i] |
+                    (c->gicr_ipriorityr[i + 1] << 8) |
+                    (c->gicr_ipriorityr[i + 2] << 16) |
+                    (c->gicr_ipriorityr[i + 3] << 24);
+                kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, &reg, true);
+            }
         }
     }
 
@@ -540,57 +852,71 @@ static void kvm_arm_gicv3_put(GICv3State *s)
     /* s->gicd_ipriority[] -> GICD_IPRIORITYRn */
     kvm_dist_put_priority(s, GICD_IPRIORITYR, s->gicd_ipriority);
 
-    /* CPU Interface state (one per CPU) */
-
-    for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
-        GICv3CPUState *c = &s->cpu[ncpu];
-        int num_pri_bits;
+    /* write CPU Interface status */
+    if (batch_supported) {
+        {
+            GICv3BatchEntry *entries = g_new(GICv3BatchEntry, 256);
+            int batch_n = 0;
+            int batch_capacity = 256;
 
-        kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true);
-        kvm_gicc_access(s, ICC_CTLR_EL1, ncpu,
-                        &c->icc_ctlr_el1[GICV3_NS], true);
-        kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu,
-                        &c->icc_igrpen[GICV3_G0], true);
-        kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu,
-                        &c->icc_igrpen[GICV3_G1NS], true);
-        kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, true);
-        kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], true);
-        kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS], true);
+            kvm_arm_gic_batch_write_cpuif(s, &entries, &batch_n,
+                                          &batch_capacity);
 
-        num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] &
-                        ICC_CTLR_EL1_PRIBITS_MASK) >>
-                        ICC_CTLR_EL1_PRIBITS_SHIFT) + 1;
-
-        switch (num_pri_bits) {
-        case 7:
-            reg64 = c->icc_apr[GICV3_G0][3];
-            kvm_gicc_access(s, ICC_AP0R_EL1(3), ncpu, &reg64, true);
-            reg64 = c->icc_apr[GICV3_G0][2];
-            kvm_gicc_access(s, ICC_AP0R_EL1(2), ncpu, &reg64, true);
-            /* fall through */
-        case 6:
-            reg64 = c->icc_apr[GICV3_G0][1];
-            kvm_gicc_access(s, ICC_AP0R_EL1(1), ncpu, &reg64, true);
-            /* fall through */
-        default:
-            reg64 = c->icc_apr[GICV3_G0][0];
-            kvm_gicc_access(s, ICC_AP0R_EL1(0), ncpu, &reg64, true);
+            g_free(entries);
         }
-
-        switch (num_pri_bits) {
-        case 7:
-            reg64 = c->icc_apr[GICV3_G1NS][3];
-            kvm_gicc_access(s, ICC_AP1R_EL1(3), ncpu, &reg64, true);
-            reg64 = c->icc_apr[GICV3_G1NS][2];
-            kvm_gicc_access(s, ICC_AP1R_EL1(2), ncpu, &reg64, true);
-            /* fall through */
-        case 6:
-            reg64 = c->icc_apr[GICV3_G1NS][1];
-            kvm_gicc_access(s, ICC_AP1R_EL1(1), ncpu, &reg64, true);
-            /* fall through */
-        default:
-            reg64 = c->icc_apr[GICV3_G1NS][0];
-            kvm_gicc_access(s, ICC_AP1R_EL1(0), ncpu, &reg64, true);
+    } else {
+        /* CPU Interface state (one per CPU) */
+        for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
+            GICv3CPUState *c = &s->cpu[ncpu];
+            int num_pri_bits;
+
+            kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true);
+            kvm_gicc_access(s, ICC_CTLR_EL1, ncpu,
+                            &c->icc_ctlr_el1[GICV3_NS], true);
+            kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu,
+                            &c->icc_igrpen[GICV3_G0], true);
+            kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu,
+                            &c->icc_igrpen[GICV3_G1NS], true);
+            kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, true);
+            kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], 
true);
+            kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS],
+                            true);
+
+            num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] &
+                            ICC_CTLR_EL1_PRIBITS_MASK) >>
+                            ICC_CTLR_EL1_PRIBITS_SHIFT) + 1;
+
+            switch (num_pri_bits) {
+            case 7:
+                reg64 = c->icc_apr[GICV3_G0][3];
+                kvm_gicc_access(s, ICC_AP0R_EL1(3), ncpu, &reg64, true);
+                reg64 = c->icc_apr[GICV3_G0][2];
+                kvm_gicc_access(s, ICC_AP0R_EL1(2), ncpu, &reg64, true);
+                /* fall through */
+            case 6:
+                reg64 = c->icc_apr[GICV3_G0][1];
+                kvm_gicc_access(s, ICC_AP0R_EL1(1), ncpu, &reg64, true);
+                /* fall through */
+            default:
+                reg64 = c->icc_apr[GICV3_G0][0];
+                kvm_gicc_access(s, ICC_AP0R_EL1(0), ncpu, &reg64, true);
+            }
+
+            switch (num_pri_bits) {
+            case 7:
+                reg64 = c->icc_apr[GICV3_G1NS][3];
+                kvm_gicc_access(s, ICC_AP1R_EL1(3), ncpu, &reg64, true);
+                reg64 = c->icc_apr[GICV3_G1NS][2];
+                kvm_gicc_access(s, ICC_AP1R_EL1(2), ncpu, &reg64, true);
+                /* fall through */
+            case 6:
+                reg64 = c->icc_apr[GICV3_G1NS][1];
+                kvm_gicc_access(s, ICC_AP1R_EL1(1), ncpu, &reg64, true);
+                /* fall through */
+            default:
+                reg64 = c->icc_apr[GICV3_G1NS][0];
+                kvm_gicc_access(s, ICC_AP1R_EL1(0), ncpu, &reg64, true);
+            }
         }
     }
     int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
-- 
2.43.0


Reply via email to