Recalculate the highest priority pending virtual interrupt for a specified (VM, VPE) when we're called for interrupt state changes. Because vSPIs and vLPIs are both stored in ISTs, we can reuse our existing lpi_cache_get_hppi() function by making it take an extra type argument for which kind of interrupt it is working on.
The logic for generating a doorbell interrupt if necessary for a non-resident VPE will be added in a later commit. Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 43 ++++++++++++++++++++++++++++++++++++++++--- hw/intc/trace-events | 2 ++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 8f4d44b2b37..b4dbe7ce3e7 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -29,6 +29,7 @@ typedef struct VMTE VMTE; typedef struct VPE { VMTE *vmte; hwaddr vped_addr; + GICv5PendingIrq vhppi; /* vHPPI candidate, if any */ uint32_t cpuidx; /* CPU we're currently resident on */ uint32_t db_intid; /* doorbell interrupt ID */ uint8_t dbpm; /* doorbell priority mask */ @@ -192,6 +193,7 @@ static MemTxAttrs irs_txattrs(GICv5Common *cs, GICv5Domain domain) typedef struct GetHPPIUserData { GICv5PendingIrq *best; uint32_t iaffid; + GICv5IntType type; } GetHPPIUserData; static void lpi_cache_get_hppi(gpointer key, gpointer value, gpointer user_data) @@ -208,7 +210,7 @@ static void lpi_cache_get_hppi(gpointer key, gpointer value, gpointer user_data) prio = FIELD_EX32(l2_iste, L2_ISTE, PRIORITY); iaffid = FIELD_EX32(l2_iste, L2_ISTE, IAFFID); if (iaffid == ud->iaffid && prio < ud->best->prio) { - id = FIELD_DP32(id, INTID, TYPE, GICV5_LPI); + id = FIELD_DP32(id, INTID, TYPE, ud->type); ud->best->intid = id; ud->best->prio = prio; } @@ -257,6 +259,7 @@ static void irs_recalc_hppi(GICv5 *s, GICv5Domain domain, uint32_t iaffid) ud.best = &best; ud.iaffid = iaffid; + ud.type = GICV5_LPI; g_hash_table_foreach(s->phys_lpi_config[domain].lpi_cache, lpi_cache_get_hppi, &ud); } @@ -572,9 +575,42 @@ static void irs_recalc_vhppi(GICv5 *s, VMTE *vmte, uint32_t iaffid) /* * Recalculate the highest priority pending virtual interrupt for * the specified VM and vCPU. - * - * TODO: we will implement this in a future commit. */ + GICv5Common *cs = ARM_GICV5_COMMON(s); + GICv5PendingIrq best = GICV5_PENDING_IRQ_NONE; + GetHPPIUserData ud; + VPE *vpe = vpe_for_vpeid(vmte, iaffid); + + if (!vpe) { + trace_gicv5_irs_recalc_vhppi_fail(domain_name[vmte->domain], + vmte->vmid, iaffid, + "IAFFID doesn't match valid VPEID"); + return; + } + + ud.best = &best; + ud.iaffid = iaffid; + if (vmte->lpi_ist.valid) { + ud.type = GICV5_LPI; + g_hash_table_foreach(vmte->lpi_ist.lpi_cache, lpi_cache_get_hppi, &ud); + } + if (vmte->spi_ist.valid) { + ud.type = GICV5_SPI; + g_hash_table_foreach(vmte->spi_ist.lpi_cache, lpi_cache_get_hppi, &ud); + } + + trace_gicv5_irs_recalc_vhppi(domain_name[vmte->domain], vmte->vmid, + iaffid, best.intid, best.prio); + + vpe->vhppi = best; + + if (FIELD_EX32(cs->irs_cr0[vmte->domain], IRS_CR0, IRSEN) && + vpe->vhppi.prio != PRIO_IDLE && vpe->resident) { + /* R_VBPZM: tell the PE about this vHPPI */ + gicv5_forward_interrupt(cs->cpus[vpe->cpuidx], vmte->domain, true); + } + + /* TODO: we may need to generate a doorbell interrupt. */ } static const GICv5ISTConfig *ist_for_vint(GICv5 *s, @@ -1473,6 +1509,7 @@ static void init_vpe_from_vpete(VPE *vpe, VMTE *vmte, uint64_t vpete) vpe->vped_addr &= ~MAKE_64BIT_MASK(0, QEMU_GICV5_VPED_SZ); /* Doorbell settings always start invalid */ vpe->db_valid = false; + vpe->vhppi = GICV5_PENDING_IRQ_NONE; } } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 6d646eacaeb..963fd75c13e 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -246,6 +246,8 @@ gicv5_deactivate(const char *domain, const char *type, bool virtual, uint32_t id gicv5_spi_state(uint32_t spi_id, bool level, bool pending, bool active) "GICv5 IRS SPI ID %u now level %d pending %d active %d" gicv5_irs_recalc_hppi_fail(const char *domain, uint32_t iaffid, const char *reason) "GICv5 IRS %s IAFFID %u: no HPPI: %s" gicv5_irs_recalc_hppi(const char *domain, uint32_t iaffid, uint32_t id, uint8_t prio) "GICv5 IRS %s IAFFID %u: new HPPI ID 0x%x prio %u" +gicv5_irs_recalc_vhppi_fail(const char *domain, uint32_t vmid, uint32_t iaffid, const char *reason) "GICv5 IRS %s VMID %u IAFFID %u: no HPPI: %s" +gicv5_irs_recalc_vhppi(const char *domain, uint32_t vmid, uint32_t iaffid, uint32_t id, uint8_t prio) "GICv5 IRS %s VMID %u IAFFID %u: new HPPI ID 0x%x prio %u" gicv5_vmt_valid(const char *domain, uint64_t base, uint8_t vm_id_bits, bool structure) "GICv5 IRS %s VM table now valid: base 0x%" PRIx64 " vm_id_bits %u 2-level %d" gicv5_vmt_invalid(const char *domain) "GICv5 IRS %s VM table no longer valid" gicv5_vmap_l2_vmtr(const char *domain, uint32_t vmid) "GICv5 IRS %s VM ID %u now valid" -- 2.43.0
