pm.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /*
  2. * linux/kernel/irq/pm.c
  3. *
  4. * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
  5. *
  6. * This file contains power management functions related to interrupts.
  7. */
  8. #include <linux/irq.h>
  9. #include <linux/module.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/syscore_ops.h>
  12. #include <linux/wakeup_reason.h>
  13. #include "internals.h"
  14. /**
  15. * suspend_device_irqs - disable all currently enabled interrupt lines
  16. *
  17. * During system-wide suspend or hibernation device drivers need to be prevented
  18. * from receiving interrupts and this function is provided for this purpose.
  19. * It marks all interrupt lines in use, except for the timer ones, as disabled
  20. * and sets the IRQS_SUSPENDED flag for each of them.
  21. */
  22. void suspend_device_irqs(void)
  23. {
  24. struct irq_desc *desc;
  25. int irq;
  26. for_each_irq_desc(irq, desc) {
  27. unsigned long flags;
  28. raw_spin_lock_irqsave(&desc->lock, flags);
  29. __disable_irq(desc, irq, true);
  30. raw_spin_unlock_irqrestore(&desc->lock, flags);
  31. }
  32. for_each_irq_desc(irq, desc)
  33. if (desc->istate & IRQS_SUSPENDED)
  34. synchronize_irq(irq);
  35. }
  36. EXPORT_SYMBOL_GPL(suspend_device_irqs);
  37. static void resume_irqs(bool want_early)
  38. {
  39. struct irq_desc *desc;
  40. int irq;
  41. for_each_irq_desc_reverse(irq, desc) {
  42. unsigned long flags;
  43. bool is_early = desc->action &&
  44. desc->action->flags & IRQF_EARLY_RESUME;
  45. if (!is_early && want_early)
  46. continue;
  47. raw_spin_lock_irqsave(&desc->lock, flags);
  48. __enable_irq(desc, irq, true);
  49. raw_spin_unlock_irqrestore(&desc->lock, flags);
  50. }
  51. }
  52. /**
  53. * irq_pm_syscore_ops - enable interrupt lines early
  54. *
  55. * Enable all interrupt lines with %IRQF_EARLY_RESUME set.
  56. */
  57. static void irq_pm_syscore_resume(void)
  58. {
  59. resume_irqs(true);
  60. }
  61. static struct syscore_ops irq_pm_syscore_ops = {
  62. .resume = irq_pm_syscore_resume,
  63. };
  64. static int __init irq_pm_init_ops(void)
  65. {
  66. register_syscore_ops(&irq_pm_syscore_ops);
  67. return 0;
  68. }
  69. device_initcall(irq_pm_init_ops);
  70. /**
  71. * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs()
  72. *
  73. * Enable all non-%IRQF_EARLY_RESUME interrupt lines previously
  74. * disabled by suspend_device_irqs() that have the IRQS_SUSPENDED flag
  75. * set as well as those with %IRQF_FORCE_RESUME.
  76. */
  77. void resume_device_irqs(void)
  78. {
  79. resume_irqs(false);
  80. }
  81. EXPORT_SYMBOL_GPL(resume_device_irqs);
  82. /**
  83. * check_wakeup_irqs - check if any wake-up interrupts are pending
  84. */
  85. int check_wakeup_irqs(void)
  86. {
  87. struct irq_desc *desc;
  88. int irq;
  89. for_each_irq_desc(irq, desc) {
  90. if (irqd_is_wakeup_set(&desc->irq_data)) {
  91. if (desc->istate & IRQS_PENDING) {
  92. log_suspend_abort_reason("Wakeup IRQ %d %s pending",
  93. irq,
  94. desc->action && desc->action->name ?
  95. desc->action->name : "");
  96. pr_info("Wakeup IRQ %d %s pending, suspend aborted\n",
  97. irq,
  98. desc->action && desc->action->name ?
  99. desc->action->name : "");
  100. return -EBUSY;
  101. }
  102. continue;
  103. }
  104. /*
  105. * Check the non wakeup interrupts whether they need
  106. * to be masked before finally going into suspend
  107. * state. That's for hardware which has no wakeup
  108. * source configuration facility. The chip
  109. * implementation indicates that with
  110. * IRQCHIP_MASK_ON_SUSPEND.
  111. */
  112. if (desc->istate & IRQS_SUSPENDED &&
  113. irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
  114. mask_irq(desc);
  115. }
  116. return 0;
  117. }