aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2015-10-05 06:12:15 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-10-09 16:47:27 -0400
commite509bd7da149dc34916037484cd7545b2d48a2b0 (patch)
treec6f5acf97add574cdfa76ab64438fd6717c6ee9f /kernel/irq
parent9e7e2b0a6a005941a6854cdabae19c3d9e069dbe (diff)
genirq: Allow migration of chained interrupts by installing default action
When a CPU is offlined all interrupts that have an action are migrated to other still online CPUs. However, if the interrupt has chained handler installed this is not done. Chained handlers are used by GPIO drivers which support interrupts, for instance. When the affinity is not corrected properly we end up in situation where most interrupts are not arriving to the online CPUs anymore. For example on Intel Braswell system which has SD-card card detection signal connected to a GPIO the IO-APIC routing entries look like below after CPU1 is offlined: pin30, enabled , level, low , V(52), IRR(0), S(0), logical , D(03), M(1) pin31, enabled , level, low , V(42), IRR(0), S(0), logical , D(03), M(1) pin32, enabled , level, low , V(62), IRR(0), S(0), logical , D(03), M(1) pin5b, enabled , level, low , V(72), IRR(0), S(0), logical , D(03), M(1) The problem here is that the destination mask still contains both CPUs even if CPU1 is already offline. This means that the IO-APIC still routes interrupts to the other CPU as well. We solve the problem by providing a default action for chained interrupts. This action allows the migration code to correct affinity (as it finds desc->action != NULL). Also make the default action handler to emit a warning if for some reason a chained handler ends up calling it. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Cc: Jiang Liu <jiang.liu@linux.intel.com> Link: http://lkml.kernel.org/r/1444039935-30475-1-git-send-email-mika.westerberg@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/chip.c17
-rw-r--r--kernel/irq/internals.h2
-rw-r--r--kernel/irq/proc.c2
3 files changed, 20 insertions, 1 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 46f1fb505b16..4aa00d325b8c 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -21,6 +21,20 @@
21 21
22#include "internals.h" 22#include "internals.h"
23 23
24static irqreturn_t bad_chained_irq(int irq, void *dev_id)
25{
26 WARN_ONCE(1, "Chained irq %d should not call an action\n", irq);
27 return IRQ_NONE;
28}
29
30/*
31 * Chained handlers should never call action on their IRQ. This default
32 * action will emit warning if such thing happens.
33 */
34struct irqaction chained_action = {
35 .handler = bad_chained_irq,
36};
37
24/** 38/**
25 * irq_set_chip - set the irq chip for an irq 39 * irq_set_chip - set the irq chip for an irq
26 * @irq: irq number 40 * @irq: irq number
@@ -746,6 +760,8 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
746 if (desc->irq_data.chip != &no_irq_chip) 760 if (desc->irq_data.chip != &no_irq_chip)
747 mask_ack_irq(desc); 761 mask_ack_irq(desc);
748 irq_state_set_disabled(desc); 762 irq_state_set_disabled(desc);
763 if (is_chained)
764 desc->action = NULL;
749 desc->depth = 1; 765 desc->depth = 1;
750 } 766 }
751 desc->handle_irq = handle; 767 desc->handle_irq = handle;
@@ -755,6 +771,7 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
755 irq_settings_set_noprobe(desc); 771 irq_settings_set_noprobe(desc);
756 irq_settings_set_norequest(desc); 772 irq_settings_set_norequest(desc);
757 irq_settings_set_nothread(desc); 773 irq_settings_set_nothread(desc);
774 desc->action = &chained_action;
758 irq_startup(desc, true); 775 irq_startup(desc, true);
759 } 776 }
760} 777}
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index cd60bb48397f..05c2188271b8 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -18,6 +18,8 @@
18 18
19extern bool noirqdebug; 19extern bool noirqdebug;
20 20
21extern struct irqaction chained_action;
22
21/* 23/*
22 * Bits used by threaded handlers: 24 * Bits used by threaded handlers:
23 * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run 25 * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index e3a8c9577ba6..7d6090519630 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -460,7 +460,7 @@ int show_interrupts(struct seq_file *p, void *v)
460 for_each_online_cpu(j) 460 for_each_online_cpu(j)
461 any_count |= kstat_irqs_cpu(i, j); 461 any_count |= kstat_irqs_cpu(i, j);
462 action = desc->action; 462 action = desc->action;
463 if (!action && !any_count) 463 if ((!action || action == &chained_action) && !any_count)
464 goto out; 464 goto out;
465 465
466 seq_printf(p, "%*d: ", prec, i); 466 seq_printf(p, "%*d: ", prec, i);