Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit d59b553

Browse files
author
Marc Zyngier
committed
Merge branch irq/lpi-resend into irq/irqchip-next
* irq/lpi-resend: : . : Patch series from James Gowans, working around an issue with : GICv3 LPIs that can fire concurrently on multiple CPUs. : . irqchip/gic-v3-its: Enable RESEND_WHEN_IN_PROGRESS for LPIs genirq: Allow fasteoi handler to resend interrupts on concurrent handling genirq: Expand doc for PENDING and REPLAY flags genirq: Use BIT() for the IRQD_* state flags Signed-off-by: Marc Zyngier <[email protected]>
2 parents 2b384e0 + 8f4b589 commit d59b553

File tree

5 files changed

+60
-26
lines changed

5 files changed

+60
-26
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3585,6 +3585,7 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
35853585
irqd = irq_get_irq_data(virq + i);
35863586
irqd_set_single_target(irqd);
35873587
irqd_set_affinity_on_activate(irqd);
3588+
irqd_set_resend_when_in_progress(irqd);
35883589
pr_debug("ID:%d pID:%d vID:%d\n",
35893590
(int)(hwirq + i - its_dev->event_map.lpi_base),
35903591
(int)(hwirq + i), virq + i);
@@ -4523,6 +4524,7 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq
45234524
irq_domain_set_hwirq_and_chip(domain, virq + i, i,
45244525
irqchip, vm->vpes[i]);
45254526
set_bit(i, bitmap);
4527+
irqd_set_resend_when_in_progress(irq_get_irq_data(virq + i));
45264528
}
45274529

45284530
if (err) {

include/linux/irq.h

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -223,32 +223,35 @@ struct irq_data {
223223
* irq_chip::irq_set_affinity() when deactivated.
224224
* IRQD_IRQ_ENABLED_ON_SUSPEND - Interrupt is enabled on suspend by irq pm if
225225
* irqchip have flag IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND set.
226+
* IRQD_RESEND_WHEN_IN_PROGRESS - Interrupt may fire when already in progress in which
227+
* case it must be resent at the next available opportunity.
226228
*/
227229
enum {
228230
IRQD_TRIGGER_MASK = 0xf,
229-
IRQD_SETAFFINITY_PENDING = (1 << 8),
230-
IRQD_ACTIVATED = (1 << 9),
231-
IRQD_NO_BALANCING = (1 << 10),
232-
IRQD_PER_CPU = (1 << 11),
233-
IRQD_AFFINITY_SET = (1 << 12),
234-
IRQD_LEVEL = (1 << 13),
235-
IRQD_WAKEUP_STATE = (1 << 14),
236-
IRQD_MOVE_PCNTXT = (1 << 15),
237-
IRQD_IRQ_DISABLED = (1 << 16),
238-
IRQD_IRQ_MASKED = (1 << 17),
239-
IRQD_IRQ_INPROGRESS = (1 << 18),
240-
IRQD_WAKEUP_ARMED = (1 << 19),
241-
IRQD_FORWARDED_TO_VCPU = (1 << 20),
242-
IRQD_AFFINITY_MANAGED = (1 << 21),
243-
IRQD_IRQ_STARTED = (1 << 22),
244-
IRQD_MANAGED_SHUTDOWN = (1 << 23),
245-
IRQD_SINGLE_TARGET = (1 << 24),
246-
IRQD_DEFAULT_TRIGGER_SET = (1 << 25),
247-
IRQD_CAN_RESERVE = (1 << 26),
248-
IRQD_MSI_NOMASK_QUIRK = (1 << 27),
249-
IRQD_HANDLE_ENFORCE_IRQCTX = (1 << 28),
250-
IRQD_AFFINITY_ON_ACTIVATE = (1 << 29),
251-
IRQD_IRQ_ENABLED_ON_SUSPEND = (1 << 30),
231+
IRQD_SETAFFINITY_PENDING = BIT(8),
232+
IRQD_ACTIVATED = BIT(9),
233+
IRQD_NO_BALANCING = BIT(10),
234+
IRQD_PER_CPU = BIT(11),
235+
IRQD_AFFINITY_SET = BIT(12),
236+
IRQD_LEVEL = BIT(13),
237+
IRQD_WAKEUP_STATE = BIT(14),
238+
IRQD_MOVE_PCNTXT = BIT(15),
239+
IRQD_IRQ_DISABLED = BIT(16),
240+
IRQD_IRQ_MASKED = BIT(17),
241+
IRQD_IRQ_INPROGRESS = BIT(18),
242+
IRQD_WAKEUP_ARMED = BIT(19),
243+
IRQD_FORWARDED_TO_VCPU = BIT(20),
244+
IRQD_AFFINITY_MANAGED = BIT(21),
245+
IRQD_IRQ_STARTED = BIT(22),
246+
IRQD_MANAGED_SHUTDOWN = BIT(23),
247+
IRQD_SINGLE_TARGET = BIT(24),
248+
IRQD_DEFAULT_TRIGGER_SET = BIT(25),
249+
IRQD_CAN_RESERVE = BIT(26),
250+
IRQD_MSI_NOMASK_QUIRK = BIT(27),
251+
IRQD_HANDLE_ENFORCE_IRQCTX = BIT(28),
252+
IRQD_AFFINITY_ON_ACTIVATE = BIT(29),
253+
IRQD_IRQ_ENABLED_ON_SUSPEND = BIT(30),
254+
IRQD_RESEND_WHEN_IN_PROGRESS = BIT(31),
252255
};
253256

254257
#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -448,6 +451,16 @@ static inline bool irqd_affinity_on_activate(struct irq_data *d)
448451
return __irqd_to_state(d) & IRQD_AFFINITY_ON_ACTIVATE;
449452
}
450453

454+
static inline void irqd_set_resend_when_in_progress(struct irq_data *d)
455+
{
456+
__irqd_to_state(d) |= IRQD_RESEND_WHEN_IN_PROGRESS;
457+
}
458+
459+
static inline bool irqd_needs_resend_when_in_progress(struct irq_data *d)
460+
{
461+
return __irqd_to_state(d) & IRQD_RESEND_WHEN_IN_PROGRESS;
462+
}
463+
451464
#undef __irqd_to_state
452465

453466
static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)

kernel/irq/chip.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,8 +692,16 @@ void handle_fasteoi_irq(struct irq_desc *desc)
692692

693693
raw_spin_lock(&desc->lock);
694694

695-
if (!irq_may_run(desc))
695+
/*
696+
* When an affinity change races with IRQ handling, the next interrupt
697+
* can arrive on the new CPU before the original CPU has completed
698+
* handling the previous one - it may need to be resent.
699+
*/
700+
if (!irq_may_run(desc)) {
701+
if (irqd_needs_resend_when_in_progress(&desc->irq_data))
702+
desc->istate |= IRQS_PENDING;
696703
goto out;
704+
}
697705

698706
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
699707

@@ -715,6 +723,12 @@ void handle_fasteoi_irq(struct irq_desc *desc)
715723

716724
cond_unmask_eoi_irq(desc, chip);
717725

726+
/*
727+
* When the race described above happens this will resend the interrupt.
728+
*/
729+
if (unlikely(desc->istate & IRQS_PENDING))
730+
check_irq_resend(desc, false);
731+
718732
raw_spin_unlock(&desc->lock);
719733
return;
720734
out:

kernel/irq/debugfs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ static const struct irq_bit_descr irqdata_states[] = {
133133
BIT_MASK_DESCR(IRQD_HANDLE_ENFORCE_IRQCTX),
134134

135135
BIT_MASK_DESCR(IRQD_IRQ_ENABLED_ON_SUSPEND),
136+
137+
BIT_MASK_DESCR(IRQD_RESEND_WHEN_IN_PROGRESS),
136138
};
137139

138140
static const struct irq_bit_descr irqdesc_states[] = {

kernel/irq/internals.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,12 @@ enum {
4747
* detection
4848
* IRQS_POLL_INPROGRESS - polling in progress
4949
* IRQS_ONESHOT - irq is not unmasked in primary handler
50-
* IRQS_REPLAY - irq is replayed
50+
* IRQS_REPLAY - irq has been resent and will not be resent
51+
* again until the handler has run and cleared
52+
* this flag.
5153
* IRQS_WAITING - irq is waiting
52-
* IRQS_PENDING - irq is pending and replayed later
54+
* IRQS_PENDING - irq needs to be resent and should be resent
55+
* at the next available opportunity.
5356
* IRQS_SUSPENDED - irq is suspended
5457
* IRQS_NMI - irq line is used to deliver NMIs
5558
* IRQS_SYSFS - descriptor has been added to sysfs

0 commit comments

Comments
 (0)