[kvm-unit-tests PATCH v4 02/11] lib: arm/arm64: gicv2: Document existing barriers when sending IPIs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



GICv2 generates IPIs with a MMIO write to the GICD_SGIR register. A common
pattern for IPI usage is for the IPI receiver to read data written to
memory by the sender. The armv7 and armv8 architectures implement a
weakly-ordered memory model, which means that barriers are required to make
sure that the expected values are observed.

Because the receiver CPU must observe the write to memory that generated
the IPI when reading the GICC_IAR MMIO register, we only need to ensure
ordering of memory accesses, and not completion. The same pattern can be
observed in the Linux GICv2 irqchip driver (more details in commit
8adbf57fc429 ("irqchip: gic: use dmb ishst instead of dsb when raising a
softirq")).

However, it turns out that no changes are needed to the way GICv2 sends
IPIs because of the implicit barriers in the MMIO writel and readl
functions. Writel executes a wmb() (DST ST) before the MMIO write, and
readl executes a rmb() (DST LD) after the MMIO read. According to  ARM DDI
0406C.d and ARM DDI 0487F.b, the DSB instruction:

"[..] acts as a stronger barrier than a DMB and all ordering that is
created by a DMB with specific options is also generated by a DSB with the
same options."

which means that the correct memory ordering is enforced.

It's not immediately obvious that the proper barriers are in place, so add
a comment explaining that correct memory synchronization is implemented.

Reviewed-by: Eric Auger <eric.auger@xxxxxxxxxx>
Signed-off-by: Alexandru Elisei <alexandru.elisei@xxxxxxx>
---
 lib/arm/gic-v2.c | 6 ++++++
 arm/gic.c        | 7 +++++++
 2 files changed, 13 insertions(+)

diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c
index dc6a97c600ec..786d6a4e4c6e 100644
--- a/lib/arm/gic-v2.c
+++ b/lib/arm/gic-v2.c
@@ -45,6 +45,11 @@ void gicv2_ipi_send_single(int irq, int cpu)
 {
 	assert(cpu < 8);
 	assert(irq < 16);
+	/*
+	 * The wmb() in writel and rmb() in readl() from gicv2_read_iar() are
+	 * sufficient for ensuring that stores that happen in program order
+	 * before the IPI will be visible after the interrupt is acknowledged.
+	 */
 	writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR);
 }
 
@@ -53,5 +58,6 @@ void gicv2_ipi_send_mask(int irq, const cpumask_t *dest)
 	u8 tlist = (u8)cpumask_bits(dest)[0];
 
 	assert(irq < 16);
+	/* No barriers needed, same situation as gicv2_ipi_send_single() */
 	writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR);
 }
diff --git a/arm/gic.c b/arm/gic.c
index fee48f9b4ccb..e2e053aeb823 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -260,11 +260,18 @@ static void check_lpi_hits(int *expected, const char *msg)
 
 static void gicv2_ipi_send_self(void)
 {
+	/*
+	 * The wmb() in writel and rmb() when acknowledging the interrupt are
+	 * sufficient for ensuring that writes that happen in program order
+	 * before the interrupt are observed in the interrupt handler after
+	 * acknowledging the interrupt.
+	 */
 	writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
 }
 
 static void gicv2_ipi_send_broadcast(void)
 {
+	/* No barriers are needed, same situation as gicv2_ipi_send_self() */
 	writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
 }
 
-- 
2.30.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux