On Mon, 23 Feb 2026 17:01:26 +0000
Peter Maydell <peter.maydell@linaro.org> wrote:
> 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 <peter.maydell@linaro.org>
One trivial thing inline.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
That's enough for today, not sure when I'll get back to the rest of the series.
So far very nice and clean. Makes reviewing pleasant!
J
> ---
> 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);
> +}
> +
I think other code is all one blank line between functions. Guessing no
particular reason for 2 here?
> +
> 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;
> }