ARM: No special handling for edge-triggered IRQs

Clearing the pending state only has an effect if the IRQ state is
active-and-pending, which happens for edge-triggered interrupts if
another edge happens on the IRQ line for the currently active
interrupt. This window is small enough to ignore, at worst user
space will get another notification, which is harmless.

If unnecessary notifications are unwanted, the pending state should
be cleared during seL4_IRQHandler_Ack(), as that covers a much bigger
window. However, edge-triggered interrupts are not expected to happen
often. Making all interrupt handling slightly faster and the code
simpler is the better trade-off.

Reading the GIC config word is very slow for GICv2, see pull #1107.

Signed-off-by: Indan Zupancic <indan@nul.nu>
This commit is contained in:
Indan Zupancic
2023-10-26 11:34:51 +01:00
committed by GitHub
parent 908cac7202
commit b4592ebc97
2 changed files with 2 additions and 55 deletions

View File

@@ -126,21 +126,6 @@ extern volatile struct gic_dist_map *const gic_dist;
extern volatile struct gic_cpu_iface_map *const gic_cpuiface;
/* Helpers */
static inline int is_irq_edge_triggered(word_t irq)
{
int word = irq >> 4;
int bit = ((irq & 0xf) * 2);
return !!(gic_dist->config[word] & BIT(bit + 1));
}
static inline void dist_pending_clr(word_t irq)
{
int word = IRQ_REG(irq);
int bit = IRQ_BIT(irq);
/* Using |= here is detrimental to your health */
gic_dist->pending_clr[word] = BIT(bit);
}
static inline void dist_enable_clr(word_t irq)
{
int word = IRQ_REG(irq);
@@ -198,9 +183,6 @@ 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));
if (is_irq_edge_triggered(IRQT_TO_IRQ(irq))) {
dist_pending_clr(IRQT_TO_IRQ(irq));
}
gic_cpuiface->eoi = active_irq[CURRENT_CPU_INDEX()];
active_irq[CURRENT_CPU_INDEX()] = IRQ_NONE;

View File

@@ -234,37 +234,6 @@ extern volatile struct gic_rdist_map *gic_rdist_map[CONFIG_MAX_NUM_NODES];
extern volatile struct gic_rdist_sgi_ppi_map *gic_rdist_sgi_ppi_map[CONFIG_MAX_NUM_NODES];
/* Helpers */
static inline int is_irq_edge_triggered(word_t irq)
{
uint32_t icfgr = 0;
int word = irq >> 4;
int bit = ((irq & 0xf) * 2);
if (HW_IRQ_IS_SGI(irq)) {
return 0;
}
if (HW_IRQ_IS_PPI(irq)) {
icfgr = gic_rdist_sgi_ppi_map[CURRENT_CPU_INDEX()]->icfgr1;
} else {
icfgr = gic_dist->icfgrn[word];
}
return !!(icfgr & BIT(bit + 1));
}
static inline void gic_pending_clr(word_t irq)
{
int word = IRQ_REG(irq);
int bit = IRQ_BIT(irq);
/* Using |= here is detrimental to your health */
/* Applicable for SPI and PPIs */
if (irq < SPI_START) {
gic_rdist_sgi_ppi_map[CURRENT_CPU_INDEX()]->icpendr0 = BIT(bit);
} else {
gic_dist->icpendrn[word] = BIT(bit);
}
}
static inline void gic_enable_clr(word_t irq)
{
int word = IRQ_REG(irq);
@@ -340,12 +309,8 @@ static inline void maskInterrupt(bool_t disable, irq_t irq)
static inline void ackInterrupt(irq_t irq)
{
word_t hw_irq = IRQT_TO_IRQ(irq);
assert(IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()]) && (active_irq[CURRENT_CPU_INDEX()] & IRQ_MASK) == hw_irq);
if (is_irq_edge_triggered(hw_irq)) {
gic_pending_clr(hw_irq);
}
assert(IS_IRQ_VALID(active_irq[CURRENT_CPU_INDEX()])
&& (active_irq[CURRENT_CPU_INDEX()] & IRQ_MASK) == 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()]);