mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 17:48:54 +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_EOIR0_EL1 S3_0_C12_C8_1
|
||||||
#define ICC_EOIR1_EL1 S3_0_C12_C12_1
|
#define ICC_EOIR1_EL1 S3_0_C12_C12_1
|
||||||
#define ICC_SGI0R_EL1 S3_0_C12_C11_7
|
#define ICC_SGI0R_EL1 S3_0_C12_C11_7
|
||||||
|
#define ICC_DIR_EL1 S3_0_C12_C11_1
|
||||||
|
|
||||||
/* register constants */
|
/* register constants */
|
||||||
#define ICC_SRE_ELX_SRE_BIT BIT(0)
|
#define ICC_SRE_ELX_SRE_BIT BIT(0)
|
||||||
#define ICC_SRE_ELX_DFB_BIT BIT(1)
|
#define ICC_SRE_ELX_DFB_BIT BIT(1)
|
||||||
#define ICC_SRE_ELX_DIB_BIT BIT(2)
|
#define ICC_SRE_ELX_DIB_BIT BIT(2)
|
||||||
#define ICC_SRE_EL3_EN_BIT BIT(3)
|
#define ICC_SRE_EL3_EN_BIT BIT(3)
|
||||||
|
#define ICC_CTLR_EOIMODE_BIT BIT(1)
|
||||||
|
|
||||||
/* ICC SGI macros */
|
/* ICC SGI macros */
|
||||||
#define SGIR_TGT_MASK (0xffff)
|
#define SGIR_TGT_MASK (0xffff)
|
||||||
|
|||||||
@@ -86,6 +86,8 @@
|
|||||||
#define ICENABLER(base, n) (base + GIC_DIST_ICENABLER + (n) * 4)
|
#define ICENABLER(base, n) (base + GIC_DIST_ICENABLER + (n) * 4)
|
||||||
#define ISPENDR(base, n) (base + GIC_DIST_ISPENDR + (n) * 4)
|
#define ISPENDR(base, n) (base + GIC_DIST_ISPENDR + (n) * 4)
|
||||||
#define ICPENDR(base, n) (base + GIC_DIST_ICPENDR + (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 IPRIORITYR(base, n) (base + GIC_DIST_IPRIORITYR + n)
|
||||||
#define ITARGETSR(base, n) (base + GIC_DIST_ITARGETSR + (n) * 4)
|
#define ITARGETSR(base, n) (base + GIC_DIST_ITARGETSR + (n) * 4)
|
||||||
#define ICFGR(base, n) (base + GIC_DIST_ICFGR + (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)
|
static void gicv3_cpuif_init(void)
|
||||||
{
|
{
|
||||||
uint32_t icc_sre;
|
uint64_t icc_sre;
|
||||||
|
uint64_t icc_ctrl;
|
||||||
uint32_t intid;
|
uint32_t intid;
|
||||||
unsigned long base = gic_get_rdist() + GICR_SGI_BASE_OFF;
|
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));
|
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);
|
gic_wait_rwp(0);
|
||||||
|
|
||||||
/* Configure all SGIs/PPIs as G1S or G1NS depending on Zephyr
|
/* Clear pending and active SGI and PPI interrupts at GIC */
|
||||||
* is run in EL1S or EL1NS respectively.
|
|
||||||
* All interrupts will be delivered as irq
|
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(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. */
|
/* 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.
|
/* Check if system interface can be enabled.
|
||||||
* 'icc_sre_el3' needs to be configured at 'EL3'
|
* 'icc_sre_el3' needs to be configured at 'EL3'
|
||||||
* to allow access to 'icc_sre_el1' at 'EL1'
|
* 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);
|
icc_sre = read_sysreg(ICC_SRE_EL1);
|
||||||
@@ -590,22 +639,23 @@ static void gicv3_dist_init(void)
|
|||||||
|
|
||||||
/* Disable interrupt */
|
/* Disable interrupt */
|
||||||
|
|
||||||
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
|
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICENABLER(base, idx));
|
||||||
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(IGROUPR_VAL, IGROUPR(base, idx));
|
||||||
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG),
|
putreg32(0, IGROUPMODR(base, idx));
|
||||||
IGROUPMODR(base, idx));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wait for rwp on GICD */
|
|
||||||
|
|
||||||
gic_wait_rwp(GIC_SPI_INT_BASE);
|
|
||||||
|
|
||||||
/* Configure default priorities for all SPIs. */
|
/* Configure default priorities for all SPIs. */
|
||||||
|
|
||||||
for (intid = GIC_SPI_INT_BASE; intid < num_ints;
|
for (intid = GIC_SPI_INT_BASE; intid < num_ints;
|
||||||
|
|||||||
Reference in New Issue
Block a user