diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2022-04-08 15:15:25 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2022-04-22 14:43:24 +0100 |
| commit | 3851af45858a03391c74361bc69bf7a31ad30fbd (patch) | |
| tree | a9d86a612e2dbe66b11d34678bbea40e99f56dc7 /hw/intc/arm_gicv3_its.c | |
| parent | 7c087bd33073503914cd0c17084de459f68ac002 (diff) | |
| download | focaccia-qemu-3851af45858a03391c74361bc69bf7a31ad30fbd.tar.gz focaccia-qemu-3851af45858a03391c74361bc69bf7a31ad30fbd.zip | |
hw/intc/arm_gicv3_its: Implement VMOVP
Implement the GICv4 VMOVP command, which updates an entry in the vPE table to change its rdbase field. This command is unique in the ITS command set because its effects must be propagated to all the other ITSes connected to the same GIC as the ITS which executes the VMOVP command. The GICv4 spec allows two implementation choices for handling the propagation to other ITSes: * If GITS_TYPER.VMOVP is 1, the guest only needs to issue the command on one ITS, and the implementation handles the propagation to all ITSes * If GITS_TYPER.VMOVP is 0, the guest must issue the command on every ITS, and arrange for the ITSes to synchronize the updates with each other by setting ITSList and Sequence Number fields in the command packets We choose the GITS_TYPER.VMOVP = 1 approach, and synchronously execute the update on every ITS. For GICv4.1 this command has extra fields in the command packet and additional behaviour. We define the 4.1-only fields with the FIELD macro, but only implement the GICv4.0 version of the command. Note that we don't update the reported GITS_TYPER value here; we'll do that later in a commit which updates all the reported feature bit and ID register values for GICv4. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220408141550.1271295-17-peter.maydell@linaro.org [PMM: Moved gicv3_foreach_its() to arm_gicv3_its_common.h, for consistency with gicv3_add_its()]
Diffstat (limited to 'hw/intc/arm_gicv3_its.c')
| -rw-r--r-- | hw/intc/arm_gicv3_its.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 46d9e0169f..8bc93295fb 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -1012,6 +1012,78 @@ static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt) return update_vte(s, vpeid, &vte) ? CMD_CONTINUE_OK : CMD_STALL; } +typedef struct VmovpCallbackData { + uint64_t rdbase; + uint32_t vpeid; + /* + * Overall command result. If more than one callback finds an + * error, STALL beats CONTINUE. + */ + ItsCmdResult result; +} VmovpCallbackData; + +static void vmovp_callback(gpointer data, gpointer opaque) +{ + /* + * This function is called to update the VPEID field in a VPE + * table entry for this ITS. This might be because of a VMOVP + * command executed on any ITS that is connected to the same GIC + * as this ITS. We need to read the VPE table entry for the VPEID + * and update its RDBASE field. + */ + GICv3ITSState *s = data; + VmovpCallbackData *cbdata = opaque; + VTEntry vte; + ItsCmdResult cmdres; + + cmdres = lookup_vte(s, __func__, cbdata->vpeid, &vte); + switch (cmdres) { + case CMD_STALL: + cbdata->result = CMD_STALL; + return; + case CMD_CONTINUE: + if (cbdata->result != CMD_STALL) { + cbdata->result = CMD_CONTINUE; + } + return; + case CMD_CONTINUE_OK: + break; + } + + vte.rdbase = cbdata->rdbase; + if (!update_vte(s, cbdata->vpeid, &vte)) { + cbdata->result = CMD_STALL; + } +} + +static ItsCmdResult process_vmovp(GICv3ITSState *s, const uint64_t *cmdpkt) +{ + VmovpCallbackData cbdata; + + if (!its_feature_virtual(s)) { + return CMD_CONTINUE; + } + + cbdata.vpeid = FIELD_EX64(cmdpkt[1], VMOVP_1, VPEID); + cbdata.rdbase = FIELD_EX64(cmdpkt[2], VMOVP_2, RDBASE); + + trace_gicv3_its_cmd_vmovp(cbdata.vpeid, cbdata.rdbase); + + if (cbdata.rdbase >= s->gicv3->num_cpu) { + return CMD_CONTINUE; + } + + /* + * Our ITS implementation reports GITS_TYPER.VMOVP == 1, which means + * that when the VMOVP command is executed on an ITS to change the + * VPEID field in a VPE table entry the change must be propagated + * to all the ITSes connected to the same GIC. + */ + cbdata.result = CMD_CONTINUE_OK; + gicv3_foreach_its(s->gicv3, vmovp_callback, &cbdata); + return cbdata.result; +} + /* * Current implementation blocks until all * commands are processed @@ -1136,6 +1208,9 @@ static void process_cmdq(GICv3ITSState *s) case GITS_CMD_VMAPP: result = process_vmapp(s, cmdpkt); break; + case GITS_CMD_VMOVP: + result = process_vmovp(s, cmdpkt); + break; default: trace_gicv3_its_cmd_unknown(cmd); break; |