aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-02-04 15:18:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-04 15:18:01 -0500
commita572a1b999489efb591287632279c6c9eca3e4ed (patch)
tree9bcb859aec2cfce13a896c46f4b41d4abd881830
parent24bc5fe716855e5e608c515340b3ceacfb143bcc (diff)
parentaaaec6fc755447a1d056765b11b24d8ff2b81366 (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.c2
-rw-r--r--arch/x86/kernel/hpet.c1
-rw-r--r--include/linux/irq.h17
-rw-r--r--kernel/irq/irqdomain.c44
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 {
202enum { 203enum {
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
317static inline bool irqd_is_activated(struct irq_data *d)
318{
319 return __irqd_to_state(d) & IRQD_ACTIVATED;
320}
321
322static inline void irqd_set_activated(struct irq_data *d)
323{
324 __irqd_to_state(d) |= IRQD_ACTIVATED;
325}
326
327static 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
317static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) 334static 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}
1347EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent); 1347EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
1348 1348
1349static 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
1361static 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 */
1357void irq_domain_activate_irq(struct irq_data *irq_data) 1381void 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 */
1377void irq_domain_deactivate_irq(struct irq_data *irq_data) 1397void 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