summaryrefslogtreecommitdiffstats
path: root/hw/intc/arm_gicv3_its.c
diff options
context:
space:
mode:
authorPeter Maydell2022-04-08 16:15:27 +0200
committerPeter Maydell2022-04-22 15:44:52 +0200
commita686e85d2b4a3b95d97d01dfa3fd4607f1216cf0 (patch)
tree561e7e710e4be26e1734adf6c1de2683f3800add /hw/intc/arm_gicv3_its.c
parenthw/intc/arm_gicv3_its: Implement VSYNC (diff)
downloadqemu-a686e85d2b4a3b95d97d01dfa3fd4607f1216cf0.tar.gz
qemu-a686e85d2b4a3b95d97d01dfa3fd4607f1216cf0.tar.xz
qemu-a686e85d2b4a3b95d97d01dfa3fd4607f1216cf0.zip
hw/intc/arm_gicv3_its: Implement INV command properly
We were previously implementing INV (like INVALL) to just blow away cached highest-priority-pending-LPI information on all connected redistributors. For GICv4.0, this isn't going to be sufficient, because the LPI we are invalidating cached information for might be either physical or virtual, and the required action is different for those two cases. So we need to do the full process of looking up the ITE from the devid and eventid. This also means we can do the error checks that the spec lists for this command. Split out INV handling into a process_inv() function like our other command-processing functions. For the moment, stick to handling only physical LPIs; we will add the vLPI parts later. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220408141550.1271295-19-peter.maydell@linaro.org
Diffstat (limited to 'hw/intc/arm_gicv3_its.c')
-rw-r--r--hw/intc/arm_gicv3_its.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index a3f5bac551..aa0a62510e 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -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]);
}