aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-04-08 15:15:40 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-04-22 14:44:53 +0100
commitd7d39749e671b5adde56b9d3b94f4c2f4ce86795 (patch)
tree9663c75500db417fb4b41c083645c843997e5139
parentb76eb5f4dbf9f43b1dcb543111ad983e22670efd (diff)
hw/intc/arm_gicv3_redist: Implement gicv3_redist_process_vlpi()
Implement the function gicv3_redist_process_vlpi(), which was left as just a stub earlier. This function deals with being handed a VLPI by the ITS. It must set the bit in the pending table. If the vCPU is currently resident we must recalculate the highest priority pending vLPI; otherwise we may need to ring a "doorbell" interrupt to let the hypervisor know it might want to reschedule the vCPU. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220408141550.1271295-32-peter.maydell@linaro.org
-rw-r--r--hw/intc/arm_gicv3_redist.c48
1 files changed, 44 insertions, 4 deletions
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index d54ed9a033..1ed251b87b 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -60,6 +60,19 @@ static uint32_t gicr_read_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
return reg;
}
+static bool vcpu_resident(GICv3CPUState *cs, uint64_t vptaddr)
+{
+ /*
+ * Return true if a vCPU is resident, which is defined by
+ * whether the GICR_VPENDBASER register is marked VALID and
+ * has the right virtual pending table address.
+ */
+ if (!FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, VALID)) {
+ return false;
+ }
+ return vptaddr == (cs->gicr_vpendbaser & R_GICR_VPENDBASER_PHYADDR_MASK);
+}
+
/**
* update_for_one_lpi: Update pending information if this LPI is better
*
@@ -1004,10 +1017,37 @@ void gicv3_redist_vlpi_pending(GICv3CPUState *cs, int irq, int level)
void gicv3_redist_process_vlpi(GICv3CPUState *cs, int irq, uint64_t vptaddr,
int doorbell, int level)
{
- /*
- * The redistributor handling for being handed a VLPI by the ITS
- * will be added in a subsequent commit.
- */
+ bool bit_changed;
+ bool resident = vcpu_resident(cs, vptaddr);
+ uint64_t ctbase;
+
+ if (resident) {
+ uint32_t idbits = FIELD_EX64(cs->gicr_vpropbaser, GICR_VPROPBASER, IDBITS);
+ if (irq >= (1ULL << (idbits + 1))) {
+ return;
+ }
+ }
+
+ bit_changed = set_pending_table_bit(cs, vptaddr, irq, level);
+ if (resident && bit_changed) {
+ if (level) {
+ /* Check whether this vLPI is now the best */
+ ctbase = cs->gicr_vpropbaser & R_GICR_VPROPBASER_PHYADDR_MASK;
+ update_for_one_lpi(cs, irq, ctbase, true, &cs->hppvlpi);
+ gicv3_cpuif_virt_irq_fiq_update(cs);
+ } else {
+ /* Only need to recalculate if this was previously the best vLPI */
+ if (irq == cs->hppvlpi.irq) {
+ gicv3_redist_update_vlpi(cs);
+ }
+ }
+ }
+
+ if (!resident && level && doorbell != INTID_SPURIOUS &&
+ (cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
+ /* vCPU is not currently resident: ring the doorbell */
+ gicv3_redist_process_lpi(cs, doorbell, 1);
+ }
}
void gicv3_redist_mov_vlpi(GICv3CPUState *src, uint64_t src_vptaddr,