@@ -373,6 +373,10 @@ FIELD(MOVI_0, DEVICEID, 32, 32)
FIELD(MOVI_1, EVENTID, 0, 32)
FIELD(MOVI_2, ICID, 0, 16)
+/* INV command fields */
+FIELD(INV_0, DEVICEID, 32, 32)
+FIELD(INV_1, EVENTID, 0, 32)
+
/* VMAPI, VMAPTI command fields */
FIELD(VMAPTI_0, DEVICEID, 32, 32)
FIELD(VMAPTI_1, EVENTID, 0, 32)
@@ -573,6 +577,14 @@ void gicv3_redist_update_lpi(GICv3CPUState *cs);
* an incoming migration has loaded new state.
*/
void gicv3_redist_update_lpi_only(GICv3CPUState *cs);
+/**
+ * gicv3_redist_inv_lpi:
+ * @cs: GICv3CPUState
+ * @irq: LPI to invalidate cached information for
+ *
+ * Forget or update any cached information associated with this LPI.
+ */
+void gicv3_redist_inv_lpi(GICv3CPUState *cs, int irq);
/**
* gicv3_redist_mov_lpi:
* @src: source redistributor
@@ -1084,6 +1084,50 @@ static ItsCmdResult process_vmovp(GICv3ITSState *s, const uint64_t *cmdpkt)
return cbdata.result;
}
+static ItsCmdResult process_inv(GICv3ITSState *s, const uint64_t *cmdpkt)
+{
+ uint32_t devid, eventid;
+ ITEntry ite;
+ DTEntry dte;
+ CTEntry cte;
+ ItsCmdResult cmdres;
+
+ devid = FIELD_EX64(cmdpkt[0], INV_0, DEVICEID);
+ eventid = FIELD_EX64(cmdpkt[1], INV_1, EVENTID);
+
+ trace_gicv3_its_cmd_inv(devid, eventid);
+
+ cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
+ if (cmdres != CMD_CONTINUE_OK) {
+ return cmdres;
+ }
+
+ switch (ite.inttype) {
+ case ITE_INTTYPE_PHYSICAL:
+ cmdres = lookup_cte(s, __func__, ite.icid, &cte);
+ if (cmdres != CMD_CONTINUE_OK) {
+ return cmdres;
+ }
+ gicv3_redist_inv_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid);
+ break;
+ case ITE_INTTYPE_VIRTUAL:
+ if (!its_feature_virtual(s)) {
+ /* Can't happen unless guest is illegally writing to table memory */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid type %d in ITE (table corrupted?)\n",
+ __func__, ite.inttype);
+ return CMD_CONTINUE;
+ }
+ /* We will implement the vLPI invalidation in a later commit */
+ g_assert_not_reached();
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return CMD_CONTINUE_OK;
+}
+
/*
* Current implementation blocks until all
* commands are processed
@@ -1192,14 +1236,18 @@ static void process_cmdq(GICv3ITSState *s)
result = process_its_cmd(s, cmdpkt, DISCARD);
break;
case GITS_CMD_INV:
+ result = process_inv(s, cmdpkt);
+ break;
case GITS_CMD_INVALL:
/*
* Current implementation doesn't cache any ITS tables,
* but the calculated lpi priority information. We only
* need to trigger lpi priority re-calculation to be in
* sync with LPI config table or pending table changes.
+ * INVALL operates on a collection specified by ICID so
+ * it only affects physical LPIs.
*/
- trace_gicv3_its_cmd_inv();
+ trace_gicv3_its_cmd_invall();
for (i = 0; i < s->gicv3->num_cpu; i++) {
gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
}
@@ -681,6 +681,17 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
gicv3_redist_lpi_pending(cs, irq, level);
}
+void gicv3_redist_inv_lpi(GICv3CPUState *cs, int irq)
+{
+ /*
+ * The only cached information for LPIs we have is the HPPLPI.
+ * We could be cleverer about identifying when we don't need
+ * to do a full rescan of the pending table, but until we find
+ * this is a performance issue, just always recalculate.
+ */
+ gicv3_redist_update_lpi(cs);
+}
+
void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq)
{
/*
@@ -184,7 +184,8 @@ gicv3_its_cmd_mapd(uint32_t devid, uint32_t size, uint64_t ittaddr, int valid) "
gicv3_its_cmd_mapc(uint32_t icid, uint64_t rdbase, int valid) "GICv3 ITS: command MAPC ICID 0x%x RDbase 0x%" PRIx64 " V %d"
gicv3_its_cmd_mapi(uint32_t devid, uint32_t eventid, uint32_t icid) "GICv3 ITS: command MAPI DeviceID 0x%x EventID 0x%x ICID 0x%x"
gicv3_its_cmd_mapti(uint32_t devid, uint32_t eventid, uint32_t icid, uint32_t intid) "GICv3 ITS: command MAPTI DeviceID 0x%x EventID 0x%x ICID 0x%x pINTID 0x%x"
-gicv3_its_cmd_inv(void) "GICv3 ITS: command INV or INVALL"
+gicv3_its_cmd_inv(uint32_t devid, uint32_t eventid) "GICv3 ITS: command INV DeviceID 0x%x EventID 0x%x"
+gicv3_its_cmd_invall(void) "GICv3 ITS: command INVALL"
gicv3_its_cmd_movall(uint64_t rd1, uint64_t rd2) "GICv3 ITS: command MOVALL RDbase1 0x%" PRIx64 " RDbase2 0x%" PRIx64
gicv3_its_cmd_movi(uint32_t devid, uint32_t eventid, uint32_t icid) "GICv3 ITS: command MOVI DeviceID 0x%x EventID 0x%x ICID 0x%x"
gicv3_its_cmd_vmapi(uint32_t devid, uint32_t eventid, uint32_t vpeid, uint32_t doorbell) "GICv3 ITS: command VMAPI DeviceID 0x%x EventID 0x%x vPEID 0x%x Dbell_pINTID 0x%x"