Skip to content

Commit a572a1b

Browse files
committed
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq fixes from Thomas Gleixner: - Prevent double activation of interrupt lines, which causes problems on certain interrupt controllers - Handle the fallout of the above because x86 (ab)uses the activation function to reconfigure interrupts under the hood. * 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/irq: Make irq activate operations symmetric irqdomain: Avoid activating interrupts more than once
2 parents 24bc5fe + aaaec6f commit a572a1b

File tree

4 files changed

+50
-14
lines changed

4 files changed

+50
-14
lines changed

arch/x86/kernel/apic/io_apic.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,6 +2117,7 @@ static inline void __init check_timer(void)
21172117
if (idx != -1 && irq_trigger(idx))
21182118
unmask_ioapic_irq(irq_get_chip_data(0));
21192119
}
2120+
irq_domain_deactivate_irq(irq_data);
21202121
irq_domain_activate_irq(irq_data);
21212122
if (timer_irq_works()) {
21222123
if (disable_timer_pin_1 > 0)
@@ -2138,6 +2139,7 @@ static inline void __init check_timer(void)
21382139
* legacy devices should be connected to IO APIC #0
21392140
*/
21402141
replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
2142+
irq_domain_deactivate_irq(irq_data);
21412143
irq_domain_activate_irq(irq_data);
21422144
legacy_pic->unmask(0);
21432145
if (timer_irq_works()) {

arch/x86/kernel/hpet.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ static int hpet_resume(struct clock_event_device *evt, int timer)
352352
} else {
353353
struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
354354

355+
irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq));
355356
irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
356357
disable_irq(hdev->irq);
357358
irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));

include/linux/irq.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ struct irq_data {
184184
*
185185
* IRQD_TRIGGER_MASK - Mask for the trigger type bits
186186
* IRQD_SETAFFINITY_PENDING - Affinity setting is pending
187+
* IRQD_ACTIVATED - Interrupt has already been activated
187188
* IRQD_NO_BALANCING - Balancing disabled for this IRQ
188189
* IRQD_PER_CPU - Interrupt is per cpu
189190
* IRQD_AFFINITY_SET - Interrupt affinity was set
@@ -202,6 +203,7 @@ struct irq_data {
202203
enum {
203204
IRQD_TRIGGER_MASK = 0xf,
204205
IRQD_SETAFFINITY_PENDING = (1 << 8),
206+
IRQD_ACTIVATED = (1 << 9),
205207
IRQD_NO_BALANCING = (1 << 10),
206208
IRQD_PER_CPU = (1 << 11),
207209
IRQD_AFFINITY_SET = (1 << 12),
@@ -312,6 +314,21 @@ static inline bool irqd_affinity_is_managed(struct irq_data *d)
312314
return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED;
313315
}
314316

317+
static inline bool irqd_is_activated(struct irq_data *d)
318+
{
319+
return __irqd_to_state(d) & IRQD_ACTIVATED;
320+
}
321+
322+
static inline void irqd_set_activated(struct irq_data *d)
323+
{
324+
__irqd_to_state(d) |= IRQD_ACTIVATED;
325+
}
326+
327+
static inline void irqd_clr_activated(struct irq_data *d)
328+
{
329+
__irqd_to_state(d) &= ~IRQD_ACTIVATED;
330+
}
331+
315332
#undef __irqd_to_state
316333

317334
static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)

kernel/irq/irqdomain.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,30 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain,
13461346
}
13471347
EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
13481348

1349+
static void __irq_domain_activate_irq(struct irq_data *irq_data)
1350+
{
1351+
if (irq_data && irq_data->domain) {
1352+
struct irq_domain *domain = irq_data->domain;
1353+
1354+
if (irq_data->parent_data)
1355+
__irq_domain_activate_irq(irq_data->parent_data);
1356+
if (domain->ops->activate)
1357+
domain->ops->activate(domain, irq_data);
1358+
}
1359+
}
1360+
1361+
static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
1362+
{
1363+
if (irq_data && irq_data->domain) {
1364+
struct irq_domain *domain = irq_data->domain;
1365+
1366+
if (domain->ops->deactivate)
1367+
domain->ops->deactivate(domain, irq_data);
1368+
if (irq_data->parent_data)
1369+
__irq_domain_deactivate_irq(irq_data->parent_data);
1370+
}
1371+
}
1372+
13491373
/**
13501374
* irq_domain_activate_irq - Call domain_ops->activate recursively to activate
13511375
* interrupt
@@ -1356,13 +1380,9 @@ EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
13561380
*/
13571381
void irq_domain_activate_irq(struct irq_data *irq_data)
13581382
{
1359-
if (irq_data && irq_data->domain) {
1360-
struct irq_domain *domain = irq_data->domain;
1361-
1362-
if (irq_data->parent_data)
1363-
irq_domain_activate_irq(irq_data->parent_data);
1364-
if (domain->ops->activate)
1365-
domain->ops->activate(domain, irq_data);
1383+
if (!irqd_is_activated(irq_data)) {
1384+
__irq_domain_activate_irq(irq_data);
1385+
irqd_set_activated(irq_data);
13661386
}
13671387
}
13681388

@@ -1376,13 +1396,9 @@ void irq_domain_activate_irq(struct irq_data *irq_data)
13761396
*/
13771397
void irq_domain_deactivate_irq(struct irq_data *irq_data)
13781398
{
1379-
if (irq_data && irq_data->domain) {
1380-
struct irq_domain *domain = irq_data->domain;
1381-
1382-
if (domain->ops->deactivate)
1383-
domain->ops->deactivate(domain, irq_data);
1384-
if (irq_data->parent_data)
1385-
irq_domain_deactivate_irq(irq_data->parent_data);
1399+
if (irqd_is_activated(irq_data)) {
1400+
__irq_domain_deactivate_irq(irq_data);
1401+
irqd_clr_activated(irq_data);
13861402
}
13871403
}
13881404

0 commit comments

Comments
 (0)