diff options
author | Michael Ryleev <gmar@google.com> | 2022-08-09 12:15:12 -0700 |
---|---|---|
committer | Michael Ryleev <gmar@google.com> | 2022-08-12 17:50:54 -0700 |
commit | 19ccada9b97045fdb312f3b3e1864dcb2bf03397 (patch) | |
tree | 258db7c47002e3c2eb478cd67d990f84754bd042 /dev | |
parent | 3595dda0637998f13e61aa0a31f7899f22643e97 (diff) | |
download | common-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.c | 8 | ||||
-rw-r--r-- | dev/interrupt/arm_gic/gic_v3.c | 9 | ||||
-rw-r--r-- | dev/interrupt/arm_gic/gic_v3.h | 1 |
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); |