Implement gic_recalc_virt_ppi_hppi(), which calculates the current
HPPI PPI for the virtual interrupt domain, using similar logic to
gic_recalc_ppi_hppi().  We call this from everywhere where we update
the state of the virtual PPIs.

Signed-off-by: Peter Maydell <[email protected]>
---
 target/arm/cpu.h             |  2 ++
 target/arm/tcg/gicv5-cpuif.c | 51 ++++++++++++++++++++++++++++++++++++
 target/arm/tcg/trace-events  |  1 +
 3 files changed, 54 insertions(+)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 81fb68facb9..abaee5fc3a0 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -596,6 +596,8 @@ typedef struct CPUArchState {
 
         /* Cached highest-priority pending PPI for each domain */
         GICv5PendingIrq ppi_hppi[NUM_GICV5_DOMAINS];
+        /* And for the virtual interrupt domain */
+        GICv5PendingIrq virt_ppi_hppi;
 
         uint64_t ich_apr_el2;
         uint64_t ich_vctlr_el2;
diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index 96384c58726..0d38ed7b15b 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -298,6 +298,45 @@ static void gic_recalc_ppi_hppi(CPUARMState *env)
     gicv5_update_irq_fiq(env);
 }
 
+static void gic_recalc_virt_ppi_hppi(CPUARMState *env)
+{
+    /*
+     * Recalculate the HPPI PPI for the virtual interrupt domain: this is
+     * the best PPI which is enabled, pending and not active.
+     */
+    env->gicv5_cpuif.virt_ppi_hppi = GICV5_PENDING_IRQ_NONE;
+
+    for (int i = 0; i < ARRAY_SIZE(env->gicv5_cpuif.ich_ppi_active); i++) {
+        uint64_t en_pend_nact = env->gicv5_cpuif.ich_ppi_enable[i] &
+            env->gicv5_cpuif.ich_ppi_pend[i] &
+            ~env->gicv5_cpuif.ich_ppi_active[i];
+
+        while (en_pend_nact) {
+            uint8_t prio;
+            int ppi;
+            int bit = ctz64(en_pend_nact);
+
+            en_pend_nact &= ~(1ULL << bit);
+
+            ppi = i * 64 + bit;
+            prio = extract64(env->gicv5_cpuif.ich_ppi_priority[ppi / 8],
+                             (ppi & 7) * 8, 5);
+
+            if (prio < env->gicv5_cpuif.virt_ppi_hppi.prio) {
+                uint32_t intid = 0;
+
+                intid = FIELD_DP32(intid, INTID, ID, ppi);
+                intid = FIELD_DP32(intid, INTID, TYPE, GICV5_PPI);
+                env->gicv5_cpuif.virt_ppi_hppi.intid = intid;
+                env->gicv5_cpuif.virt_ppi_hppi.prio = prio;
+            }
+        }
+    }
+
+    trace_gicv5_recalc_virt_ppi_hppi(env->gicv5_cpuif.virt_ppi_hppi.intid,
+                                     env->gicv5_cpuif.virt_ppi_hppi.prio);
+}
+
 void gicv5_forward_interrupt(ARMCPU *cpu, GICv5Domain domain)
 {
     /*
@@ -460,6 +499,7 @@ static void gic_ppi_cactive_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
     if (gicv5_icv_access(env)) {
         value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1];
         env->gicv5_cpuif.ich_ppi_active[ri->opc2 & 1] &= ~value;
+        gic_recalc_virt_ppi_hppi(env);
     } else {
         uint64_t old = raw_read(env, ri);
         raw_write(env, ri, old & ~value);
@@ -473,6 +513,7 @@ static void gic_ppi_sactive_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
     if (gicv5_icv_access(env)) {
         value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1];
         env->gicv5_cpuif.ich_ppi_active[ri->opc2 & 1] |= value;
+        gic_recalc_virt_ppi_hppi(env);
     } else {
         uint64_t old = raw_read(env, ri);
         raw_write(env, ri, old | value);
@@ -502,6 +543,7 @@ static void gic_ppi_cpend_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
     if (gicv5_icv_access(env)) {
         value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1];
         env->gicv5_cpuif.ich_ppi_pend[ri->opc2 & 1] &= ~value;
+        gic_recalc_virt_ppi_hppi(env);
     } else {
         uint64_t old = raw_read(env, ri);
         raw_write(env, ri, old & ~value);
@@ -519,6 +561,7 @@ static void gic_ppi_spend_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
     if (gicv5_icv_access(env)) {
         value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1];
         env->gicv5_cpuif.ich_ppi_pend[ri->opc2 & 1] |= value;
+        gic_recalc_virt_ppi_hppi(env);
     } else {
         uint64_t old = raw_read(env, ri);
         raw_write(env, ri, old | value);
@@ -544,6 +587,7 @@ static void gic_ppi_enable_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
     if (gicv5_icv_access(env)) {
         value &= ~env->gicv5_cpuif.ich_ppi_hvi[ri->opc2 & 1];
         env->gicv5_cpuif.ich_ppi_enable[ri->opc2 & 1] = value;
+        gic_recalc_virt_ppi_hppi(env);
     } else {
         raw_write(env, ri, value);
         gic_recalc_ppi_hppi(env);
@@ -610,6 +654,7 @@ static void gic_ppi_priority_write(CPUARMState *env, const 
ARMCPRegInfo *ri,
         uint64_t hvi_mask = gic_ppi_prio_hvi_mask(env, idx);
 
         env->gicv5_cpuif.ich_ppi_priority[idx] = value & ~hvi_mask;
+        gic_recalc_virt_ppi_hppi(env);
     } else {
         raw_write(env, ri, value);
         gic_recalc_ppi_hppi(env);
@@ -620,36 +665,42 @@ static void gic_ich_ppi_enable_write(CPUARMState *env, 
const ARMCPRegInfo *ri,
                                      uint64_t value)
 {
     raw_write(env, ri, value);
+    gic_recalc_virt_ppi_hppi(env);
 }
 
 static void gic_ich_ppi_pend_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                    uint64_t value)
 {
     raw_write(env, ri, value);
+    gic_recalc_virt_ppi_hppi(env);
 }
 
 static void gic_ich_ppi_active_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                      uint64_t value)
 {
     raw_write(env, ri, value);
+    gic_recalc_virt_ppi_hppi(env);
 }
 
 static void gic_ich_ppi_priority_write(CPUARMState *env, const ARMCPRegInfo 
*ri,
                                        uint64_t value)
 {
     raw_write(env, ri, value);
+    gic_recalc_virt_ppi_hppi(env);
 }
 
 static void gic_ich_ppi_dvi_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                   uint64_t value)
 {
     raw_write(env, ri, value);
+    gic_recalc_virt_ppi_hppi(env);
 }
 
 static void gic_ich_ppi_hvi_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                   uint64_t value)
 {
     raw_write(env, ri, value);
+    gic_recalc_virt_ppi_hppi(env);
 }
 
 static void gic_ich_vctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
diff --git a/target/arm/tcg/trace-events b/target/arm/tcg/trace-events
index bf1803c8722..da25ec994cc 100644
--- a/target/arm/tcg/trace-events
+++ b/target/arm/tcg/trace-events
@@ -3,6 +3,7 @@
 
 # gicv5-cpuif.c
 gicv5_recalc_ppi_hppi(int domain, uint32_t id, uint8_t prio) "domain %d new 
PPI HPPI id 0x%x prio %u"
+gicv5_recalc_virt_ppi_hppi(uint32_t id, uint8_t prio) "virtual domain new PPI 
HPPI id 0x%x prio %u"
 gicv5_gicr_cdia_fail(int domain, const char *reason) "domain %d CDIA attempt 
failed: %s"
 gicv5_gicr_cdia(int domain, uint32_t id) "domain %d CDIA acknowledge of 
interrupt 0x%x"
 gicv5_cdeoi(int domain) "domain %d CDEOI performing priority drop"
-- 
2.43.0


Reply via email to