aboutsummaryrefslogtreecommitdiff
path: root/dev
diff options
context:
space:
mode:
authorMichael Ryleev <gmar@google.com>2022-08-09 12:15:12 -0700
committerMichael Ryleev <gmar@google.com>2022-08-12 17:50:54 -0700
commit19ccada9b97045fdb312f3b3e1864dcb2bf03397 (patch)
tree258db7c47002e3c2eb478cd67d990f84754bd042 /dev
parent3595dda0637998f13e61aa0a31f7899f22643e97 (diff)
downloadcommon-19ccada9b97045fdb312f3b3e1864dcb2bf03397.tar.gz
[GICv3] Poll for RWP bit after updating GICD_ICENABLER<n>
According to GICV3 manual, in order to make sure that changes are visible to all parts of GIC, the caller needs to poll for RWP bit in GICD_CTRL register after writing to GICD_ICENABLER<n> register. https://developer.arm.com/documentation/ddi0595/2021-06/External-Registers/GICD-CTLR--Distributor-Control-Register Bug: 234053227 Change-Id: I3cbf60beb4a34f738db3c2223c06c0c54c78769e
Diffstat (limited to 'dev')
-rw-r--r--dev/interrupt/arm_gic/arm_gic.c8
-rw-r--r--dev/interrupt/arm_gic/gic_v3.c9
-rw-r--r--dev/interrupt/arm_gic/gic_v3.h1
3 files changed, 15 insertions, 3 deletions
diff --git a/dev/interrupt/arm_gic/arm_gic.c b/dev/interrupt/arm_gic/arm_gic.c
index c237cecd..a23d00c7 100644
--- a/dev/interrupt/arm_gic/arm_gic.c
+++ b/dev/interrupt/arm_gic/arm_gic.c
@@ -194,8 +194,14 @@ static void gic_set_enable(uint vector, bool enable)
#endif
if (enable)
GICDREG_WRITE(0, GICD_ISENABLER(reg), mask);
- else
+ else {
GICDREG_WRITE(0, GICD_ICENABLER(reg), mask);
+
+#if GIC_VERSION > 2
+ /* for GIC V3, make sure write is complete */
+ arm_gicv3_wait_for_write_complete();
+#endif
+ }
}
static void arm_gic_init_percpu(uint level)
diff --git a/dev/interrupt/arm_gic/gic_v3.c b/dev/interrupt/arm_gic/gic_v3.c
index d5e3c668..cc1005d1 100644
--- a/dev/interrupt/arm_gic/gic_v3.c
+++ b/dev/interrupt/arm_gic/gic_v3.c
@@ -108,13 +108,18 @@ static void gicv3_gicr_init(void) {
/* GICD_CTRL Register write pending bit */
#define GICD_CTLR_RWP (0x1U << 31)
+void arm_gicv3_wait_for_write_complete(void) {
+ /* wait until write complete */
+ while (GICDREG_READ(0, GICD_CTLR) & GICD_CTLR_RWP) {
+ }
+}
+
static void gicv3_gicd_ctrl_write(uint32_t val) {
/* write CTRL register */
GICDREG_WRITE(0, GICD_CTLR, val);
/* wait until write complete */
- while (GICDREG_READ(0, GICD_CTLR) & GICD_CTLR_RWP) {
- }
+ arm_gicv3_wait_for_write_complete();
}
static void gicv3_gicd_setup_irq_group(uint32_t vector, uint32_t grp) {
diff --git a/dev/interrupt/arm_gic/gic_v3.h b/dev/interrupt/arm_gic/gic_v3.h
index 6c3b74f6..0a327f7f 100644
--- a/dev/interrupt/arm_gic/gic_v3.h
+++ b/dev/interrupt/arm_gic/gic_v3.h
@@ -29,3 +29,4 @@ void arm_gicv3_configure_irq_locked(unsigned int cpu, unsigned int vector);
void arm_gicv3_suspend_cpu(unsigned int cpu);
void arm_gicv3_resume_cpu_locked(unsigned int cpu, bool gicd);
uint64_t arm_gicv3_sgir_val(u_int irq, size_t cpu_num);
+void arm_gicv3_wait_for_write_complete(void);