diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-04 15:18:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-04 15:18:01 -0500 |
commit | a572a1b999489efb591287632279c6c9eca3e4ed (patch) | |
tree | 9bcb859aec2cfce13a896c46f4b41d4abd881830 | |
parent | 24bc5fe716855e5e608c515340b3ceacfb143bcc (diff) | |
parent | aaaec6fc755447a1d056765b11b24d8ff2b81366 (diff) |
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
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/hpet.c | 1 | ||||
-rw-r--r-- | include/linux/irq.h | 17 | ||||
-rw-r--r-- | kernel/irq/irqdomain.c | 44 |
4 files changed, 50 insertions, 14 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 1e35dd06b090..52f352b063fd 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -2117,6 +2117,7 @@ static inline void __init check_timer(void) | |||
2117 | if (idx != -1 && irq_trigger(idx)) | 2117 | if (idx != -1 && irq_trigger(idx)) |
2118 | unmask_ioapic_irq(irq_get_chip_data(0)); | 2118 | unmask_ioapic_irq(irq_get_chip_data(0)); |
2119 | } | 2119 | } |
2120 | irq_domain_deactivate_irq(irq_data); | ||
2120 | irq_domain_activate_irq(irq_data); | 2121 | irq_domain_activate_irq(irq_data); |
2121 | if (timer_irq_works()) { | 2122 | if (timer_irq_works()) { |
2122 | if (disable_timer_pin_1 > 0) | 2123 | if (disable_timer_pin_1 > 0) |
@@ -2138,6 +2139,7 @@ static inline void __init check_timer(void) | |||
2138 | * legacy devices should be connected to IO APIC #0 | 2139 | * legacy devices should be connected to IO APIC #0 |
2139 | */ | 2140 | */ |
2140 | replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2); | 2141 | replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2); |
2142 | irq_domain_deactivate_irq(irq_data); | ||
2141 | irq_domain_activate_irq(irq_data); | 2143 | irq_domain_activate_irq(irq_data); |
2142 | legacy_pic->unmask(0); | 2144 | legacy_pic->unmask(0); |
2143 | if (timer_irq_works()) { | 2145 | if (timer_irq_works()) { |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 85e87b46c318..dc6ba5bda9fc 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
@@ -352,6 +352,7 @@ static int hpet_resume(struct clock_event_device *evt, int timer) | |||
352 | } else { | 352 | } else { |
353 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); | 353 | struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); |
354 | 354 | ||
355 | irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq)); | ||
355 | irq_domain_activate_irq(irq_get_irq_data(hdev->irq)); | 356 | irq_domain_activate_irq(irq_get_irq_data(hdev->irq)); |
356 | disable_irq(hdev->irq); | 357 | disable_irq(hdev->irq); |
357 | irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu)); | 358 | irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu)); |
diff --git a/include/linux/irq.h b/include/linux/irq.h index e79875574b39..39e3254e5769 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -184,6 +184,7 @@ struct irq_data { | |||
184 | * | 184 | * |
185 | * IRQD_TRIGGER_MASK - Mask for the trigger type bits | 185 | * IRQD_TRIGGER_MASK - Mask for the trigger type bits |
186 | * IRQD_SETAFFINITY_PENDING - Affinity setting is pending | 186 | * IRQD_SETAFFINITY_PENDING - Affinity setting is pending |
187 | * IRQD_ACTIVATED - Interrupt has already been activated | ||
187 | * IRQD_NO_BALANCING - Balancing disabled for this IRQ | 188 | * IRQD_NO_BALANCING - Balancing disabled for this IRQ |
188 | * IRQD_PER_CPU - Interrupt is per cpu | 189 | * IRQD_PER_CPU - Interrupt is per cpu |
189 | * IRQD_AFFINITY_SET - Interrupt affinity was set | 190 | * IRQD_AFFINITY_SET - Interrupt affinity was set |
@@ -202,6 +203,7 @@ struct irq_data { | |||
202 | enum { | 203 | enum { |
203 | IRQD_TRIGGER_MASK = 0xf, | 204 | IRQD_TRIGGER_MASK = 0xf, |
204 | IRQD_SETAFFINITY_PENDING = (1 << 8), | 205 | IRQD_SETAFFINITY_PENDING = (1 << 8), |
206 | IRQD_ACTIVATED = (1 << 9), | ||
205 | IRQD_NO_BALANCING = (1 << 10), | 207 | IRQD_NO_BALANCING = (1 << 10), |
206 | IRQD_PER_CPU = (1 << 11), | 208 | IRQD_PER_CPU = (1 << 11), |
207 | IRQD_AFFINITY_SET = (1 << 12), | 209 | IRQD_AFFINITY_SET = (1 << 12), |
@@ -312,6 +314,21 @@ static inline bool irqd_affinity_is_managed(struct irq_data *d) | |||
312 | return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED; | 314 | return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED; |
313 | } | 315 | } |
314 | 316 | ||
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 | |||
315 | #undef __irqd_to_state | 332 | #undef __irqd_to_state |
316 | 333 | ||
317 | static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) | 334 | static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) |
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8c0a0ae43521..b59e6768c5e9 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -1346,6 +1346,30 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain, | |||
1346 | } | 1346 | } |
1347 | EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent); | 1347 | EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent); |
1348 | 1348 | ||
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 | |||
1349 | /** | 1373 | /** |
1350 | * irq_domain_activate_irq - Call domain_ops->activate recursively to activate | 1374 | * irq_domain_activate_irq - Call domain_ops->activate recursively to activate |
1351 | * interrupt | 1375 | * interrupt |
@@ -1356,13 +1380,9 @@ EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent); | |||
1356 | */ | 1380 | */ |
1357 | void irq_domain_activate_irq(struct irq_data *irq_data) | 1381 | void irq_domain_activate_irq(struct irq_data *irq_data) |
1358 | { | 1382 | { |
1359 | if (irq_data && irq_data->domain) { | 1383 | if (!irqd_is_activated(irq_data)) { |
1360 | struct irq_domain *domain = irq_data->domain; | 1384 | __irq_domain_activate_irq(irq_data); |
1361 | 1385 | irqd_set_activated(irq_data); | |
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); | ||
1366 | } | 1386 | } |
1367 | } | 1387 | } |
1368 | 1388 | ||
@@ -1376,13 +1396,9 @@ void irq_domain_activate_irq(struct irq_data *irq_data) | |||
1376 | */ | 1396 | */ |
1377 | void irq_domain_deactivate_irq(struct irq_data *irq_data) | 1397 | void irq_domain_deactivate_irq(struct irq_data *irq_data) |
1378 | { | 1398 | { |
1379 | if (irq_data && irq_data->domain) { | 1399 | if (irqd_is_activated(irq_data)) { |
1380 | struct irq_domain *domain = irq_data->domain; | 1400 | __irq_domain_deactivate_irq(irq_data); |
1381 | 1401 | irqd_clr_activated(irq_data); | |
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); | ||
1386 | } | 1402 | } |
1387 | } | 1403 | } |
1388 | 1404 | ||