aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2022-04-08 15:15:33 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-04-22 14:44:52 +0100
commit10337638bbaffa03f280a83ed23940aedc2de9ce (patch)
treef98bb565af91c5a337046cc0a1e848828f3125c6 /hw
parent641be69745c49d3c35efb62ee41d21d701b210ba (diff)
downloadqemu-10337638bbaffa03f280a83ed23940aedc2de9ce.zip
qemu-10337638bbaffa03f280a83ed23940aedc2de9ce.tar.gz
qemu-10337638bbaffa03f280a83ed23940aedc2de9ce.tar.bz2
hw/intc/arm_gicv3_cpuif: Split "update vIRQ/vFIQ" from gicv3_cpuif_virt_update()
The function gicv3_cpuif_virt_update() currently sets all of vIRQ, vFIQ and the maintenance interrupt. This implies that it has to be used quite carefully -- as the comment notes, setting the maintenance interrupt will typically cause the GIC code to be re-entered recursively. For handling vLPIs, we need the redistributor to be able to tell the cpuif to update the vIRQ and vFIQ lines when the highest priority pending vLPI changes. Since that change can't cause the maintenance interrupt state to change, we can pull the "update vIRQ/vFIQ" parts of gicv3_cpuif_virt_update() out into a separate function, which the redistributor can then call without having to worry about the reentrancy issue. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20220408141550.1271295-25-peter.maydell@linaro.org
Diffstat (limited to 'hw')
-rw-r--r--hw/intc/arm_gicv3_cpuif.c64
-rw-r--r--hw/intc/gicv3_internal.h11
-rw-r--r--hw/intc/trace-events3
3 files changed, 53 insertions, 25 deletions
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 1a3d440..5fb64d4 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -370,9 +370,45 @@ static uint32_t maintenance_interrupt_state(GICv3CPUState *cs)
return value;
}
+void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs)
+{
+ /*
+ * Tell the CPU about any pending virtual interrupts.
+ * This should only be called for changes that affect the
+ * vIRQ and vFIQ status and do not change the maintenance
+ * interrupt status. This means that unlike gicv3_cpuif_virt_update()
+ * this function won't recursively call back into the GIC code.
+ * The main use of this is when the redistributor has changed the
+ * highest priority pending virtual LPI.
+ */
+ int idx;
+ int irqlevel = 0;
+ int fiqlevel = 0;
+
+ idx = hppvi_index(cs);
+ trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx);
+ if (idx >= 0) {
+ uint64_t lr = cs->ich_lr_el2[idx];
+
+ if (icv_hppi_can_preempt(cs, lr)) {
+ /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */
+ if (lr & ICH_LR_EL2_GROUP) {
+ irqlevel = 1;
+ } else {
+ fiqlevel = 1;
+ }
+ }
+ }
+
+ trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel);
+ qemu_set_irq(cs->parent_vfiq, fiqlevel);
+ qemu_set_irq(cs->parent_virq, irqlevel);
+}
+
static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
{
- /* Tell the CPU about any pending virtual interrupts or
+ /*
+ * Tell the CPU about any pending virtual interrupts or
* maintenance interrupts, following a change to the state
* of the CPU interface relevant to virtual interrupts.
*
@@ -389,37 +425,17 @@ static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
* naturally as a result of there being no architectural
* linkage between the physical and virtual GIC logic.
*/
- int idx;
- int irqlevel = 0;
- int fiqlevel = 0;
- int maintlevel = 0;
ARMCPU *cpu = ARM_CPU(cs->cpu);
+ int maintlevel = 0;
- idx = hppvi_index(cs);
- trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx);
- if (idx >= 0) {
- uint64_t lr = cs->ich_lr_el2[idx];
-
- if (icv_hppi_can_preempt(cs, lr)) {
- /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */
- if (lr & ICH_LR_EL2_GROUP) {
- irqlevel = 1;
- } else {
- fiqlevel = 1;
- }
- }
- }
+ gicv3_cpuif_virt_irq_fiq_update(cs);
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_EN) &&
maintenance_interrupt_state(cs) != 0) {
maintlevel = 1;
}
- trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel,
- irqlevel, maintlevel);
-
- qemu_set_irq(cs->parent_vfiq, fiqlevel);
- qemu_set_irq(cs->parent_virq, irqlevel);
+ trace_gicv3_cpuif_virt_set_maint_irq(gicv3_redist_affid(cs), maintlevel);
qemu_set_irq(cpu->gicv3_maintenance_interrupt, maintlevel);
}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 8d2b428..052aa96 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -707,6 +707,17 @@ void gicv3_init_cpuif(GICv3State *s);
*/
void gicv3_cpuif_update(GICv3CPUState *cs);
+/*
+ * gicv3_cpuif_virt_irq_fiq_update:
+ * @cs: GICv3CPUState for the CPU to update
+ *
+ * Recalculate whether to assert the virtual IRQ or FIQ lines after
+ * a change to the current highest priority pending virtual interrupt.
+ * Note that this does not recalculate and change the maintenance
+ * interrupt status (for that, see gicv3_cpuif_virt_update()).
+ */
+void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs);
+
static inline uint32_t gicv3_iidr(void)
{
/* Return the Implementer Identification Register value
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 004a100..36c3fe4 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -152,7 +152,8 @@ gicv3_icv_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICV_DIR write cpu 0x%x va
gicv3_icv_iar_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IAR%d read cpu 0x%x value 0x%" PRIx64
gicv3_icv_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_EOIR%d write cpu 0x%x value 0x%" PRIx64
gicv3_cpuif_virt_update(uint32_t cpuid, int idx) "GICv3 CPU i/f 0x%x virt HPPI update LR index %d"
-gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel, int maintlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting FIQ %d IRQ %d maintenance-irq %d"
+gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting FIQ %d IRQ %d"
+gicv3_cpuif_virt_set_maint_irq(uint32_t cpuid, int maintlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting maintenance-irq %d"
# arm_gicv3_dist.c
gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"