Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

genirq: Add IRQF_RESUME_EARLY and resume such IRQs earlier

This adds a mechanism to resume selected IRQs during syscore_resume
instead of dpm_resume_noirq.

Under Xen we need to resume IRQs associated with IPIs early enough
that the resched IPI is unmasked and we can therefore schedule
ourselves out of the stop_machine where the suspend/resume takes
place.

This issue was introduced by 676dc3cf5bc3 "xen: Use IRQF_FORCE_RESUME".

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Jeremy Fitzhardinge <Jeremy.Fitzhardinge@citrix.com>
Cc: xen-devel <xen-devel@lists.xensource.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Link: http://lkml.kernel.org/r/1318713254.11016.52.camel@dagon.hellion.org.uk
Cc: stable@kernel.org (at least to 2.6.32.y)
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by

Ian Campbell and committed by
Thomas Gleixner
9bab0b7f 32cffdde

+45 -8
+1 -1
drivers/xen/events.c
··· 1021 1021 if (irq < 0) 1022 1022 return irq; 1023 1023 1024 - irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME; 1024 + irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME | IRQF_EARLY_RESUME; 1025 1025 retval = request_irq(irq, handler, irqflags, devname, dev_id); 1026 1026 if (retval != 0) { 1027 1027 unbind_from_irq(irq);
+3
include/linux/interrupt.h
··· 59 59 * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend 60 60 * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set 61 61 * IRQF_NO_THREAD - Interrupt cannot be threaded 62 + * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device 63 + * resume time. 62 64 */ 63 65 #define IRQF_DISABLED 0x00000020 64 66 #define IRQF_SAMPLE_RANDOM 0x00000040 ··· 74 72 #define IRQF_NO_SUSPEND 0x00004000 75 73 #define IRQF_FORCE_RESUME 0x00008000 76 74 #define IRQF_NO_THREAD 0x00010000 75 + #define IRQF_EARLY_RESUME 0x00020000 77 76 78 77 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) 79 78
+41 -7
kernel/irq/pm.c
··· 9 9 #include <linux/irq.h> 10 10 #include <linux/module.h> 11 11 #include <linux/interrupt.h> 12 + #include <linux/syscore_ops.h> 12 13 13 14 #include "internals.h" 14 15 ··· 40 39 } 41 40 EXPORT_SYMBOL_GPL(suspend_device_irqs); 42 41 43 - /** 44 - * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs() 45 - * 46 - * Enable all interrupt lines previously disabled by suspend_device_irqs() that 47 - * have the IRQS_SUSPENDED flag set. 48 - */ 49 - void resume_device_irqs(void) 42 + static void resume_irqs(bool want_early) 50 43 { 51 44 struct irq_desc *desc; 52 45 int irq; 53 46 54 47 for_each_irq_desc(irq, desc) { 55 48 unsigned long flags; 49 + bool is_early = desc->action && 50 + desc->action->flags & IRQF_EARLY_RESUME; 51 + 52 + if (is_early != want_early) 53 + continue; 56 54 57 55 raw_spin_lock_irqsave(&desc->lock, flags); 58 56 __enable_irq(desc, irq, true); 59 57 raw_spin_unlock_irqrestore(&desc->lock, flags); 60 58 } 59 + } 60 + 61 + /** 62 + * irq_pm_syscore_ops - enable interrupt lines early 63 + * 64 + * Enable all interrupt lines with %IRQF_EARLY_RESUME set. 65 + */ 66 + static void irq_pm_syscore_resume(void) 67 + { 68 + resume_irqs(true); 69 + } 70 + 71 + static struct syscore_ops irq_pm_syscore_ops = { 72 + .resume = irq_pm_syscore_resume, 73 + }; 74 + 75 + static int __init irq_pm_init_ops(void) 76 + { 77 + register_syscore_ops(&irq_pm_syscore_ops); 78 + return 0; 79 + } 80 + 81 + device_initcall(irq_pm_init_ops); 82 + 83 + /** 84 + * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs() 85 + * 86 + * Enable all non-%IRQF_EARLY_RESUME interrupt lines previously 87 + * disabled by suspend_device_irqs() that have the IRQS_SUSPENDED flag 88 + * set as well as those with %IRQF_FORCE_RESUME. 89 + */ 90 + void resume_device_irqs(void) 91 + { 92 + resume_irqs(false); 61 93 } 62 94 EXPORT_SYMBOL_GPL(resume_device_irqs); 63 95