The IRS register IRS_MAP_L2_ISTR is used by software to tell the IRS that it has updated the address in an L1 IST entry to point to an L2 IST. The sequence of events here is: * software writes to L1_ISTE.L2_ADDR for some L1 ISTE which is not valid (i.e. where L1_ISTE.VALID is 0); it leaves VALID at 0 * software writes to IRS_MAP_L2_ISTR with some INTID that is inside the range for this L1 ISTE * the IRS sets IRS_IST_STATUSR.IDLE to 0 * the IRS takes note of this information * the IRS writes to the L1_ISTE to set VALID=1 * the IRS sets IRS_IST_STATUSR.IDLE to 1 to indicate that the update is complete
For QEMU, we're strictly synchronous, so (as with IRS_IST_BASER updates) we don't need to model the IDLE transitions and can have IRS_IST_STATUSR always return IDLE=1. We also don't currently cache anything for ISTE lookups, so we don't need to invalidate or update anything when software makes the L2 valid. Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 8572823edc..af27fb7e63 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -492,6 +492,44 @@ void gicv5_set_priority(GICv5Common *cs, uint32_t id, put_l2_iste(cs, cfg, &h); } +static void irs_map_l2_istr_write(GICv5 *s, GICv5Domain domain, uint64_t value) +{ + GICv5Common *cs = ARM_GICV5_COMMON(s); + GICv5ISTConfig *cfg = &s->phys_lpi_config[domain]; + uint32_t intid = FIELD_EX32(value, IRS_MAP_L2_ISTR, ID); + hwaddr l1_addr; + uint64_t l1_iste; + MemTxResult res; + + if (!FIELD_EX64(cs->irs_ist_baser[domain], IRS_IST_BASER, VALID) || + !cfg->structure) { + /* WI if no IST set up or it is not 2-level */ + return; + } + + /* Find the relevant L1 ISTE and set its VALID bit */ + l1_addr = l1_iste_addr(cs, cfg, intid); + + l1_iste = address_space_ldq_le(&cs->dma_as, l1_addr, cfg->txattrs, &res); + if (res != MEMTX_OK) { + goto txfail; + } + + l1_iste = FIELD_DP64(l1_iste, L1_ISTE, VALID, 1); + + address_space_stq_le(&cs->dma_as, l1_addr, l1_iste, cfg->txattrs, &res); + if (res != MEMTX_OK) { + goto txfail; + } + return; + +txfail: + /* Reportable with EC=0x0 if sw error reporting implemented */ + qemu_log_mask(LOG_GUEST_ERROR, "L1 ISTE update failed for ID 0x%x at " + "physical address 0x" HWADDR_FMT_plx "\n", intid, l1_addr); +} + + static void irs_ist_baser_write(GICv5 *s, GICv5Domain domain, uint64_t value) { GICv5Common *cs = ARM_GICV5_COMMON(s); @@ -675,6 +713,9 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset, cs->irs_ist_cfgr[domain] = data; } return true; + case A_IRS_MAP_L2_ISTR: + irs_map_l2_istr_write(s, domain, data); + return true; } return false; } -- 2.43.0
