gicv3: Split EOI mode
Separate priority drop from deactivation so that when the kernel delegates interrupts to userlevel, they can be left in the active state until user level performs the ack invocation which deactivates them. This is more efficient than doing a disable and enable operation for each handled interrupt as it is core local and doesn't require sending operations to the GIC distributor.. Signed-off-by: Kent McLeod <kent@kry10.com>
This commit is contained in:
parent
97559a40b2
commit
a4b0c8d36a
4 changed files with 53 additions and 7 deletions
|
|
@ -306,14 +306,35 @@ static inline void maskInterrupt(bool_t disable, irq_t irq)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void deactivateInterrupt(irq_t irq)
|
||||
{
|
||||
word_t hw_irq = IRQT_TO_IRQ(irq);
|
||||
/* Perform deactivation of hw_irq */
|
||||
SYSTEM_WRITE_WORD(ICC_DIR_EL1, hw_irq);
|
||||
}
|
||||
|
||||
static inline void ackInterrupt(irq_t irq)
|
||||
{
|
||||
assert(IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()])
|
||||
&& (active_irq[CURRENT_CPU_INDEX()] & IRQ_MASK) == IRQT_TO_IRQ(irq));
|
||||
active_irq[CURRENT_CPU_INDEX()] = IRQ_NONE;
|
||||
|
||||
word_t hw_irq = IRQT_TO_IRQ(irq);
|
||||
|
||||
/* Set End of Interrupt for active IRQ: ICC_EOIR1_EL1 */
|
||||
SYSTEM_WRITE_WORD(ICC_EOIR1_EL1, active_irq[CURRENT_CPU_INDEX()]);
|
||||
active_irq[CURRENT_CPU_INDEX()] = IRQ_NONE;
|
||||
/* Perform priority drop for current IRQ */
|
||||
SYSTEM_WRITE_WORD(ICC_EOIR1_EL1, hw_irq);
|
||||
|
||||
// If the IRQ is not going to user level then we need to deactivate it too.
|
||||
if (unlikely(hw_irq > maxIRQ) ||
|
||||
intStateIRQTable[IRQT_TO_IDX(irq)] != IRQSignal) {
|
||||
/* There needs to be an isb() to ensure completion of the system
|
||||
* register write in ackInterrupt
|
||||
*/
|
||||
isb();
|
||||
deactivateInterrupt(irq);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,20 @@ static inline void maskInterrupt(bool_t disable, irq_t irq);
|
|||
*/
|
||||
static inline void ackInterrupt(irq_t irq);
|
||||
|
||||
/**
|
||||
* Deactivates the interrupt
|
||||
*
|
||||
* When the interrupt controller supports delegating the interrupt to a lower
|
||||
* privilege level, this function can be called to signal the completion of
|
||||
* interrupt processing so that the interrupt state machine can be moved out of
|
||||
* the active state.
|
||||
*
|
||||
* Currently only supported by gicv3 driver.
|
||||
*
|
||||
* @param[in] irq The interrupt request
|
||||
*/
|
||||
static inline void deactivateInterrupt(irq_t irq);
|
||||
|
||||
/**
|
||||
* Called when getActiveIRQ returns irqInvalid while the kernel is handling an
|
||||
* interrupt entry. An implementation is not required to do anything here, but
|
||||
|
|
@ -116,3 +130,7 @@ static inline void handleSpuriousIRQ(void);
|
|||
*/
|
||||
static inline void handleReservedIRQ(irq_t irq);
|
||||
|
||||
#ifndef CONFIG_ARM_GIC_V3_SUPPORT
|
||||
|
||||
static inline void deactivateInterrupt(irq_t irq) {}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -276,9 +276,9 @@ BOOT_CODE static void cpu_iface_init(void)
|
|||
/* Set priority mask register: ICC_PMR_EL1 */
|
||||
SYSTEM_WRITE_WORD(ICC_PMR_EL1, DEFAULT_PMR_VALUE);
|
||||
|
||||
/* EOI drops priority and deactivates the interrupt: ICC_CTLR_EL1 */
|
||||
/* EOI drops priority of the interrupt, deactivation happens separately: ICC_CTLR_EL1 */
|
||||
SYSTEM_READ_WORD(ICC_CTLR_EL1, icc_ctlr);
|
||||
icc_ctlr &= ~GICC_CTLR_EL1_EOImode_drop;
|
||||
icc_ctlr |= GICC_CTLR_EL1_EOImode_drop;
|
||||
SYSTEM_WRITE_WORD(ICC_CTLR_EL1, icc_ctlr);
|
||||
|
||||
/* Enable Group1 interrupts: ICC_IGRPEN1_EL1 */
|
||||
|
|
|
|||
|
|
@ -149,8 +149,12 @@ void invokeIRQHandler_AckIRQ(irq_t irq)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
maskInterrupt(false, irq);
|
||||
#endif
|
||||
if (config_set(CONFIG_ARM_GIC_V3_SUPPORT)) {
|
||||
deactivateInterrupt(irq);
|
||||
} else {
|
||||
maskInterrupt(false, irq);
|
||||
}
|
||||
#endif /* CONFIG_ARCH_RISCV */
|
||||
}
|
||||
|
||||
void invokeIRQHandler_SetIRQHandler(irq_t irq, cap_t cap, cte_t *slot)
|
||||
|
|
@ -218,8 +222,11 @@ void handleInterrupt(irq_t irq)
|
|||
#endif
|
||||
}
|
||||
#ifndef CONFIG_ARCH_RISCV
|
||||
maskInterrupt(true, irq);
|
||||
if (!config_set(CONFIG_ARM_GIC_V3_SUPPORT)) {
|
||||
maskInterrupt(true, irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue