For the GICv5, if the IRS has a potential virtual interrupt for a VPE which is not currently resident on some CPU, then it might need to "ring the doorbell" by triggering a physical LPI to tell the hypervisor that it ought to schedule the VPE so it can handle the virtual interrupt.
The conditions when we need to do this are defined in the spec by R_CWZMW: the VPE must be non-resident, have valid doorbell settings that request a doorbell, and the pending virtual interrupt must be high enough priority to satisfy the doorbell priority mask. We thus need to reconsider whether to ring the doorbell when the vHPPI for the VPE changes, when the VPE transitions between resident and non-resident, and when the doorbell settings are changed. Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 62 ++++++++++++++++++++++++++++++++++++-------- hw/intc/trace-events | 1 + 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index b3ce8a87e81..a1fe6a8a822 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -572,6 +572,53 @@ static hwaddr l1_vmte_addr(GICv5Common *cs, const GICv5VMTConfig *cfg, return cfg->base + (l1_index * 8); } +static void irs_maybe_ring_doorbell(GICv5 *s, VPE *vpe) +{ + /* + * Ring the doorbell for the VPE if required by the conditions + * defined in R_CWZMW: the VPE must be non-resident, and have + * valid doorbell settings that actually request a doorbell, and + * a doorbell priority mask that allows it. + */ + GICv5Common *cs = ARM_GICV5_COMMON(s); + GICv5ISTConfig *cfg; + L2_ISTE_Handle h; + uint32_t *l2_iste_p; + uint32_t iaffid; + + if (!vpe->valid || vpe->resident || !vpe->db_valid || !vpe->db_req) { + return; + } + if (vpe->vhppi.prio > vpe->dbpm) { + return; + } + trace_gicv5_irs_ring_doorbell(domain_name[vpe->vmte->domain], + vpe->vmte->vmid, vpe->db_intid); + /* + * Generate the doorbell event, and clear db_req so we only do it once. + * This is a SET_EDGE event for an LPI, so (R_HHKMN) it forces the + * LPI's handling mode to Edge ond its Pending state to Pending. + * If the LPI is unreachable (no LPI table, etc) then we would + * report it in IRS_SWERR_STATUSR if we implemented error reporting; + * the doorbell is marked as no-longer-requested regardless. + */ + vpe->db_req = false; + + cfg = &s->phys_lpi_config[vpe->vmte->domain]; + if (!cfg) { + return; + } + l2_iste_p = get_l2_iste(cs, cfg, vpe->db_intid, &h); + if (!l2_iste_p) { + return; + } + *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, PENDING, true); + *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, HM, GICV5_EDGE); + iaffid = FIELD_EX32(*l2_iste_p, L2_ISTE, IAFFID); + put_l2_iste(cs, cfg, &h); + irs_recalc_hppi(s, vpe->vmte->domain, iaffid); +} + static void irs_recalc_vhppi(GICv5 *s, VMTE *vmte, uint32_t iaffid) { /* @@ -612,7 +659,7 @@ static void irs_recalc_vhppi(GICv5 *s, VMTE *vmte, uint32_t iaffid) gicv5_forward_interrupt(cs->cpus[vpe->cpuidx], vmte->domain, true); } - /* TODO: we may need to generate a doorbell interrupt. */ + irs_maybe_ring_doorbell(s, vpe); } static void irs_recalc_all_vhppi_for_vm(GICv5 *s, VMTE *vmte) @@ -1428,11 +1475,7 @@ bool gicv5_set_resident(GICv5Common *cs, GICv5Domain domain, bool valid, trace_gicv5_set_non_resident(domain_name[domain], cpuidx, db, dbpm); - /* - * TODO: when we implement VPE doorbells, we should check whether - * we should immediately generate a doorbell for a VPE that has - * just been made non-resident. - */ + irs_maybe_ring_doorbell(s, vpe); } /* @@ -2369,11 +2412,8 @@ static void irs_vpe_dbr_write(GICv5 *s, GICv5Domain domain, uint64_t value) IRS_VPE_SELR, VPE_ID), vpe->dbpm, vpe->db_intid, vpe->db_req); - /* - * TODO: when we implement VPE doorbells, check here whether - * this config change means we should now generate a VPE - * doorbell event for this VPE. - */ + /* This config change might mean we now need to ring the doorbell */ + irs_maybe_ring_doorbell(s, vpe); } else { trace_gicv5_irs_vpe_dbr_write_nv(domain_name[domain], vpe->vmte->vmid, FIELD_EX64(cs->irs_vpe_selr[domain], diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 963fd75c13e..ddb7ab06207 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -260,6 +260,7 @@ gicv5_irs_vpe_dbr_write(const char *domain, uint32_t vmid, uint32_t vpeid, uint8 gicv5_irs_vpe_dbr_write_nv(const char *domain, uint32_t vmid, uint32_t vpeid) "GICv5 IRS %s VM ID %u VPE %u IRS_VPE_DBR doorbell info no longer valid" gicv5_set_resident(const char *domain, uint32_t vmid, uint32_t vpeid, uint32_t cpuidx) "GICv5 IRS %s VM ID %u VPE %u set_resident phys CPU idx %u: now resident" gicv5_set_non_resident(const char *domain, uint32_t cpuidx, bool db, uint8_t dbpm) "GICv5 IRS %s set_resident phys CPU idx %u: now no resident VPE; db_req %d dbpm %u" +gicv5_irs_ring_doorbell(const char *domain, uint32_t vmid, uint32_t db_intid) "GICv5 IRS %s VM ID %u: ringing doorbell LPI %u" # arm_gicv5_common.c gicv5_common_realize(uint32_t irsid, uint32_t num_cpus, uint32_t spi_base, uint32_t spi_irs_range, uint32_t spi_range) "GICv5 IRS realized: IRS ID %u, %u CPUs, SPI base %u, SPI IRS range %u, SPI range %u" -- 2.43.0
