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
This commit is contained in:
parent
f76ba95a03
commit
a686e85d2b
@ -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)
|
||||
{
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user