]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
RISC-V: KVM: Fix APLIC in_clrip[x] read emulation
authorAnup Patel <apatel@ventanamicro.com>
Thu, 21 Mar 2024 08:50:41 +0000 (14:20 +0530)
committerAnup Patel <anup@brainfault.org>
Tue, 26 Mar 2024 04:10:55 +0000 (09:40 +0530)
The reads to APLIC in_clrip[x] registers returns rectified input values
of the interrupt sources.

A rectified input value of an interrupt source is defined by the section
"4.5.2 Source configurations (sourcecfg[1]–sourcecfg[1023])" of the
RISC-V AIA specification as:

    rectified input value = (incoming wire value) XOR (source is inverted)

Update the riscv_aplic_input() implementation to match the above.

Cc: stable@vger.kernel.org
Fixes: 74967aa208e2 ("RISC-V: KVM: Add in-kernel emulation of AIA APLIC")
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20240321085041.1955293-3-apatel@ventanamicro.com
arch/riscv/kvm/aia_aplic.c

index 5e842b92dc4610cf06d04edf95f73fa438131f0b..b467ba5ed9100024d0cbdd876917379ac343fc7a 100644 (file)
@@ -197,16 +197,31 @@ static void aplic_write_enabled(struct aplic *aplic, u32 irq, bool enabled)
 
 static bool aplic_read_input(struct aplic *aplic, u32 irq)
 {
-       bool ret;
-       unsigned long flags;
+       u32 sourcecfg, sm, raw_input, irq_inverted;
        struct aplic_irq *irqd;
+       unsigned long flags;
+       bool ret = false;
 
        if (!irq || aplic->nr_irqs <= irq)
                return false;
        irqd = &aplic->irqs[irq];
 
        raw_spin_lock_irqsave(&irqd->lock, flags);
-       ret = (irqd->state & APLIC_IRQ_STATE_INPUT) ? true : false;
+
+       sourcecfg = irqd->sourcecfg;
+       if (sourcecfg & APLIC_SOURCECFG_D)
+               goto skip;
+
+       sm = sourcecfg & APLIC_SOURCECFG_SM_MASK;
+       if (sm == APLIC_SOURCECFG_SM_INACTIVE)
+               goto skip;
+
+       raw_input = (irqd->state & APLIC_IRQ_STATE_INPUT) ? 1 : 0;
+       irq_inverted = (sm == APLIC_SOURCECFG_SM_LEVEL_LOW ||
+                       sm == APLIC_SOURCECFG_SM_EDGE_FALL) ? 1 : 0;
+       ret = !!(raw_input ^ irq_inverted);
+
+skip:
        raw_spin_unlock_irqrestore(&irqd->lock, flags);
 
        return ret;