]> Git Repo - linux.git/commitdiff
RISC-V: KVM: Fix APLIC setipnum_le/be write emulation
authorAnup Patel <[email protected]>
Thu, 21 Mar 2024 08:50:40 +0000 (14:20 +0530)
committerAnup Patel <[email protected]>
Mon, 25 Mar 2024 08:48:37 +0000 (14:18 +0530)
The writes to setipnum_le/be register for APLIC in MSI-mode have special
consideration for level-triggered interrupts as-per the section "4.9.2
Special consideration for level-sensitive interrupt sources" of the RISC-V
AIA specification.

Particularly, the below text from the RISC-V AIA specification defines
the behaviour of writes to setipnum_le/be register for level-triggered
interrupts:

"A second option is for the interrupt service routine to write the
APLIC’s source identity number for the interrupt to the domain’s
setipnum register just before exiting. This will cause the interrupt’s
pending bit to be set to one again if the source is still asserting
an interrupt, but not if the source is not asserting an interrupt."

Fix setipnum_le/be write emulation for in-kernel APLIC by implementing
the above behaviour in aplic_write_pending() function.

Cc: [email protected]
Fixes: 74967aa208e2 ("RISC-V: KVM: Add in-kernel emulation of AIA APLIC")
Signed-off-by: Anup Patel <[email protected]>
Signed-off-by: Anup Patel <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
arch/riscv/kvm/aia_aplic.c

index 39e72aa016a4cc2d96a4994a342762762f2189c2..5e842b92dc4610cf06d04edf95f73fa438131f0b 100644 (file)
@@ -137,11 +137,21 @@ static void aplic_write_pending(struct aplic *aplic, u32 irq, bool pending)
        raw_spin_lock_irqsave(&irqd->lock, flags);
 
        sm = irqd->sourcecfg & APLIC_SOURCECFG_SM_MASK;
-       if (!pending &&
-           ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) ||
-            (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)))
+       if (sm == APLIC_SOURCECFG_SM_INACTIVE)
                goto skip_write_pending;
 
+       if (sm == APLIC_SOURCECFG_SM_LEVEL_HIGH ||
+           sm == APLIC_SOURCECFG_SM_LEVEL_LOW) {
+               if (!pending)
+                       goto skip_write_pending;
+               if ((irqd->state & APLIC_IRQ_STATE_INPUT) &&
+                   sm == APLIC_SOURCECFG_SM_LEVEL_LOW)
+                       goto skip_write_pending;
+               if (!(irqd->state & APLIC_IRQ_STATE_INPUT) &&
+                   sm == APLIC_SOURCECFG_SM_LEVEL_HIGH)
+                       goto skip_write_pending;
+       }
+
        if (pending)
                irqd->state |= APLIC_IRQ_STATE_PENDING;
        else
This page took 0.057458 seconds and 4 git commands to generate.