arch/arm64/gicv3: Improve initialization in warm reboot case

- In case of warm reboot, clear active and pending interrupts from GICv3
and also from the CPU interface.
- Fix default IGROUPMODR to the reset value (0)
- Move gic_wait_rwp calls to after modifying ICENABLER
- Improve some comments

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
Jukka Laitinen
2025-08-21 14:14:59 +03:00
committed by Alan C. Assis
parent 80cb2cf9c6
commit 67d0b975a5
3 changed files with 72 additions and 18 deletions
+2
View File
@@ -207,12 +207,14 @@
#define ICC_EOIR0_EL1 S3_0_C12_C8_1
#define ICC_EOIR1_EL1 S3_0_C12_C12_1
#define ICC_SGI0R_EL1 S3_0_C12_C11_7
#define ICC_DIR_EL1 S3_0_C12_C11_1
/* register constants */
#define ICC_SRE_ELX_SRE_BIT BIT(0)
#define ICC_SRE_ELX_DFB_BIT BIT(1)
#define ICC_SRE_ELX_DIB_BIT BIT(2)
#define ICC_SRE_EL3_EN_BIT BIT(3)
#define ICC_CTLR_EOIMODE_BIT BIT(1)
/* ICC SGI macros */
#define SGIR_TGT_MASK (0xffff)
+2
View File
@@ -86,6 +86,8 @@
#define ICENABLER(base, n) (base + GIC_DIST_ICENABLER + (n) * 4)
#define ISPENDR(base, n) (base + GIC_DIST_ISPENDR + (n) * 4)
#define ICPENDR(base, n) (base + GIC_DIST_ICPENDR + (n) * 4)
#define ISACTIVER(base, n) (base + GIC_DIST_ISACTIVER + (n) * 4)
#define ICACTIVER(base, n) (base + GIC_DIST_ICACTIVER + (n) * 4)
#define IPRIORITYR(base, n) (base + GIC_DIST_IPRIORITYR + n)
#define ITARGETSR(base, n) (base + GIC_DIST_ITARGETSR + (n) * 4)
#define ICFGR(base, n) (base + GIC_DIST_ICFGR + (n) * 4)
+68 -18
View File
@@ -482,11 +482,13 @@ static void gicv3_rdist_enable(unsigned long rdist)
static void gicv3_cpuif_init(void)
{
uint32_t icc_sre;
uint64_t icc_sre;
uint64_t icc_ctrl;
uint32_t intid;
unsigned long base = gic_get_rdist() + GICR_SGI_BASE_OFF;
bool eoi_mode;
/* Disable all sgi ppi */
/* Disable all SGI and PPI interrupts */
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICENABLER(base, 0));
@@ -494,13 +496,61 @@ static void gicv3_cpuif_init(void)
gic_wait_rwp(0);
/* Configure all SGIs/PPIs as G1S or G1NS depending on Zephyr
* is run in EL1S or EL1NS respectively.
* All interrupts will be delivered as irq
/* Clear pending and active SGI and PPI interrupts at GIC */
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICPENDR(base, 0));
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICACTIVER(base, 0));
/* Configure all SGIs/PPIs as G1S or G1NS depending on NuttX is run in
* EL1S or EL1NS respectively. All interrupts will be delivered as irq.
*/
putreg32(IGROUPR_SGI_VAL, IGROUPR(base, 0));
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), IGROUPMODR(base, 0));
putreg32(0, IGROUPMODR(base, 0));
/* Clear any active IRQs in the CPU interface */
icc_ctrl = read_sysreg(ICC_CTLR_EL1);
UP_DSB();
eoi_mode = (icc_ctrl & ICC_CTLR_EOIMODE_BIT) != 0;
/* If the SW has crashed / warm-rebooted right after reading the
* ICC_IAR1_EL1, but before acking it in EOIR1, the irq is still
* active, but not any longer readable from the IAR1.
*
* Just ack all IRQs to clear such state. Invalid writes are ignored by
* the architecture.
*/
for (intid = 0; intid < NR_IRQS; intid++)
{
#ifdef CONFIG_ARM64_DECODEFIQ
write_sysreg(intid, ICC_EOIR0_EL1);
#endif
write_sysreg(intid, ICC_EOIR1_EL1);
if (eoi_mode)
{
write_sysreg(intid, ICC_DIR_EL1);
}
}
/* Now, if the SW has crashed / warm rebooted when interrupts are
* activated, but before reading the ICC_IAR1_EL1, disable the
* interrupts normally
*/
while ((intid = arm64_gic_get_active_irq()) < NR_IRQS)
{
#ifdef CONFIG_ARM64_DECODEFIQ
write_sysreg(intid, ICC_EOIR0_EL1);
#endif
write_sysreg(intid, ICC_EOIR1_EL1);
if (eoi_mode)
{
write_sysreg(intid, ICC_DIR_EL1);
}
}
/* Configure default priorities for SGI 0:15 and PPI 0:15. */
@@ -517,7 +567,6 @@ static void gicv3_cpuif_init(void)
/* Check if system interface can be enabled.
* 'icc_sre_el3' needs to be configured at 'EL3'
* to allow access to 'icc_sre_el1' at 'EL1'
* eg: z_arch_el3_plat_init can be used by platform.
*/
icc_sre = read_sysreg(ICC_SRE_EL1);
@@ -590,22 +639,23 @@ static void gicv3_dist_init(void)
/* Disable interrupt */
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
ICENABLER(base, idx));
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICENABLER(base, idx));
/* Clear pending */
/* Wait for rwp on GICD */
gic_wait_rwp(intid);
/* Clear pending and active SPIs */
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICPENDR(base, idx));
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICACTIVER(base, idx));
/* Configure groups to default values */
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
ICPENDR(base, idx));
putreg32(IGROUPR_VAL, IGROUPR(base, idx));
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
IGROUPMODR(base, idx));
putreg32(0, IGROUPMODR(base, idx));
}
/* wait for rwp on GICD */
gic_wait_rwp(GIC_SPI_INT_BASE);
/* Configure default priorities for all SPIs. */
for (intid = GIC_SPI_INT_BASE; intid < num_ints;