Skip to content

Commit af27e41

Browse files
author
Marc Zyngier
committed
irqchip/gic-v4: Wait for GICR_VPENDBASER.Dirty to clear before descheduling
The way KVM drives GICv4.{0,1} is as follows: - vcpu_load() makes the VPE resident, instructing the RD to start scanning for interrupts - just before entering the guest, we check that the RD has finished scanning and that we can start running the vcpu - on preemption, we deschedule the VPE by making it invalid on the RD However, we are preemptible between the first two steps. If it so happens *and* that the RD was still scanning, we nonetheless write to the GICR_VPENDBASER register while Dirty is set, and bad things happen (we're in UNPRED land). This affects both the 4.0 and 4.1 implementations. Make sure Dirty is cleared before performing the deschedule, meaning that its_clear_vpend_valid() becomes a sort of full VPE residency barrier. Reported-by: Jingyi Wang <wangjingyi11@huawei.com> Tested-by: Nianyao Tang <tangnianyao@huawei.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Fixes: 57e3ceb ("KVM: arm64: Delay the polling of the GICR_VPENDBASER.Dirty bit") Link: https://lore.kernel.org/r/4aae10ba-b39a-5f84-754b-69c2eb0a2c03@huawei.com
1 parent 76ff614 commit af27e41

File tree

1 file changed

+19
-9
lines changed

1 file changed

+19
-9
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3011,18 +3011,12 @@ static int __init allocate_lpi_tables(void)
30113011
return 0;
30123012
}
30133013

3014-
static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set)
3014+
static u64 read_vpend_dirty_clear(void __iomem *vlpi_base)
30153015
{
30163016
u32 count = 1000000; /* 1s! */
30173017
bool clean;
30183018
u64 val;
30193019

3020-
val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
3021-
val &= ~GICR_VPENDBASER_Valid;
3022-
val &= ~clr;
3023-
val |= set;
3024-
gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
3025-
30263020
do {
30273021
val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
30283022
clean = !(val & GICR_VPENDBASER_Dirty);
@@ -3033,10 +3027,26 @@ static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set)
30333027
}
30343028
} while (!clean && count);
30353029

3036-
if (unlikely(val & GICR_VPENDBASER_Dirty)) {
3030+
if (unlikely(!clean))
30373031
pr_err_ratelimited("ITS virtual pending table not cleaning\n");
3032+
3033+
return val;
3034+
}
3035+
3036+
static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set)
3037+
{
3038+
u64 val;
3039+
3040+
/* Make sure we wait until the RD is done with the initial scan */
3041+
val = read_vpend_dirty_clear(vlpi_base);
3042+
val &= ~GICR_VPENDBASER_Valid;
3043+
val &= ~clr;
3044+
val |= set;
3045+
gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
3046+
3047+
val = read_vpend_dirty_clear(vlpi_base);
3048+
if (unlikely(val & GICR_VPENDBASER_Dirty))
30383049
val |= GICR_VPENDBASER_PendingLast;
3039-
}
30403050

30413051
return val;
30423052
}

0 commit comments

Comments
 (0)