aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-03-11 15:22:14 -0500
committerThomas Gleixner <tglx@linutronix.de>2011-03-12 05:12:58 -0500
commitd209a699a0b975ad47f399d70ddc3791f1b84496 (patch)
tree225ee2dd5e51acc769cd272ce86d36405e933ed2
parentd9936bb3952a08d701f7b03f8f62d158f94d8085 (diff)
genirq: Add chip flag to force mask on suspend
On suspend we disable all interrupts in the core code, but this does not mask the interrupt line in the default implementation as we use a lazy disable approach. That means we mark the interrupt disabled, but leave the hardware unmasked. That's an optimization because we avoid the hardware access for the common case where no interrupt happens after we marked it disabled. If an interrupt happens, then the interrupt flow handler masks the line at the hardware level and marks it pending. Suspend makes use of this delayed disable as it "disables" all interrupts when preparing the suspend transition. Right before the system goes into hardware suspend state it checks whether one of the interrupts which is marked as a wakeup interrupt came in after disabling it. Most interrupt chips have a separate register which selects the interrupts which can wake up the system from suspend, so we don't have to mask any on the non wakeup interrupts. But now we have to deal with brilliant designed hardware which lacks such a wakeup configuration facility. For such hardware it's necessary to mask all non wakeup interrupts before going into suspend in order to avoid the wakeup from random interrupts. Rather than working around this in the affected interrupt chip implementations we can solve this elegant in the core code itself. Add a flag IRQCHIP_MASK_ON_SUSPEND which can be set by the irq chip implementation to indicate, that the interrupts which are not selected as wakeup sources must be masked in the suspend path. Mask them in the loop which checks the wakeup interrupts pending flag. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org> LKML-Reference: <alpine.LFD.2.00.1103112112310.2787@localhost6.localdomain6>
-rw-r--r--include/linux/irq.h2
-rw-r--r--kernel/irq/pm.c22
2 files changed, 20 insertions, 4 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h
index ff62d0145b8f..1d3577f30d45 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -330,10 +330,12 @@ struct irq_chip {
330 * 330 *
331 * IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type() 331 * IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type()
332 * IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled 332 * IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled
333 * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path
333 */ 334 */
334enum { 335enum {
335 IRQCHIP_SET_TYPE_MASKED = (1 << 0), 336 IRQCHIP_SET_TYPE_MASKED = (1 << 0),
336 IRQCHIP_EOI_IF_HANDLED = (1 << 1), 337 IRQCHIP_EOI_IF_HANDLED = (1 << 1),
338 IRQCHIP_MASK_ON_SUSPEND = (1 << 2),
337}; 339};
338 340
339/* This include will go away once we isolated irq_desc usage to core code */ 341/* This include will go away once we isolated irq_desc usage to core code */
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index 1329f0eff49e..f76fc00c9877 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -68,10 +68,24 @@ int check_wakeup_irqs(void)
68 struct irq_desc *desc; 68 struct irq_desc *desc;
69 int irq; 69 int irq;
70 70
71 for_each_irq_desc(irq, desc) 71 for_each_irq_desc(irq, desc) {
72 if (irqd_is_wakeup_set(&desc->irq_data) && 72 if (irqd_is_wakeup_set(&desc->irq_data)) {
73 (desc->istate & IRQS_PENDING)) 73 if (desc->istate & IRQS_PENDING)
74 return -EBUSY; 74 return -EBUSY;
75 continue;
76 }
77 /*
78 * Check the non wakeup interrupts whether they need
79 * to be masked before finally going into suspend
80 * state. That's for hardware which has no wakeup
81 * source configuration facility. The chip
82 * implementation indicates that with
83 * IRQCHIP_MASK_ON_SUSPEND.
84 */
85 if (desc->istate & IRQS_SUSPENDED &&
86 irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
87 mask_irq(desc);
88 }
75 89
76 return 0; 90 return 0;
77} 91}