mirror of
https://github.com/apache/nuttx.git
synced 2026-05-23 23:28:29 +08:00
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:
committed by
Alan C. Assis
parent
80cb2cf9c6
commit
67d0b975a5
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user