Support virtual=true in gicv5_set_target().  This is basically the
same approach as for the other gicv5_set_*() functions, with the
slight wrinkle that we will need to update the vHPPI for both the old
IAFFID and the new one, and that the comments and handling for (lack
of) 1-of-N routing apply equally to virtual interrupts as to physical
ones.

Signed-off-by: Peter Maydell <[email protected]>
---
 hw/intc/arm_gicv5.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c
index c07122fe6e4..7c68fd6cc2e 100644
--- a/hw/intc/arm_gicv5.c
+++ b/hw/intc/arm_gicv5.c
@@ -644,6 +644,7 @@ DEF_SET_FIELD_FOR_IST(priority, uint8_t, PRIORITY)
 DEF_SET_FIELD_FOR_IST(enabled, bool, ENABLE)
 DEF_SET_FIELD_FOR_IST(handling, bool, HM)
 DEF_SET_FIELD_FOR_IST(pending, bool, PENDING)
+DEF_SET_FIELD_FOR_IST(target, uint32_t, IAFFID)
 
 void gicv5_set_priority(GICv5Common *cs, uint32_t id, uint8_t priority,
                         GICv5Domain domain, GICv5IntType type, bool virtual,
@@ -878,11 +879,6 @@ void gicv5_set_target(GICv5Common *cs, uint32_t id, 
uint32_t iaffid,
 
     trace_gicv5_set_target(domain_name[domain], inttype_name(type), virtual,
                            id, iaffid, irm);
-    if (virtual) {
-        qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set "
-                      "target of a virtual interrupt\n");
-        return;
-    }
     if (irm != GICV5_TARGETED) {
         qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set "
                       "1-of-N routing\n");
@@ -893,24 +889,32 @@ void gicv5_set_target(GICv5Common *cs, uint32_t id, 
uint32_t iaffid,
          */
     }
 
+    /*
+     * For QEMU we do not implement 1-of-N routing, and so L2_ISTE.IRM
+     * is RES0.  We never read it, and we can skip explicitly writing
+     * it to zero: it's sufficient to update L2_ISTE.IAFFID alone via
+     * set_target_for_ist().
+     */
+
+    if (virtual) {
+        const GICv5ISTConfig *cfg = ist_for_vint(s, cs, domain, type, cpuidx);
+
+        if (!set_target_for_ist(cs, cfg, id, iaffid, &old_iaffid)) {
+            return;
+        }
+        irs_recalc_vhppi(s, s->res_vpe[cpuidx]->vmte, old_iaffid);
+        irs_recalc_vhppi(s, s->res_vpe[cpuidx]->vmte, iaffid);
+        return;
+    }
+
     switch (type) {
     case GICV5_LPI:
     {
         const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain];
-        L2_ISTE_Handle h;
-        uint32_t *l2_iste_p = get_l2_iste(cs, cfg, id, &h);
 
-        if (!l2_iste_p) {
+        if (!set_target_for_ist(cs, cfg, id, iaffid, &old_iaffid)) {
             return;
         }
-        /*
-         * For QEMU we do not implement 1-of-N routing, and so
-         * L2_ISTE.IRM is RES0.  We never read it, and we can skip
-         * explicitly writing it to zero here.
-         */
-        old_iaffid = FIELD_EX32(*l2_iste_p, L2_ISTE, IAFFID);
-        *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, IAFFID, iaffid);
-        put_l2_iste(cs, cfg, &h);
         break;
     }
     case GICV5_SPI:
-- 
2.43.0


Reply via email to