autosleep.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * kernel/power/autosleep.c
  3. *
  4. * Opportunistic sleep support.
  5. *
  6. * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
  7. */
  8. #include <linux/device.h>
  9. #include <linux/mutex.h>
  10. #include <linux/pm_wakeup.h>
  11. #include "power.h"
  12. static suspend_state_t autosleep_state;
  13. static struct workqueue_struct *autosleep_wq;
  14. /*
  15. * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
  16. * is active, otherwise a deadlock with try_to_suspend() is possible.
  17. * Alternatively mutex_lock_interruptible() can be used. This will then fail
  18. * if an auto_sleep cycle tries to freeze processes.
  19. */
  20. static DEFINE_MUTEX(autosleep_lock);
  21. static struct wakeup_source *autosleep_ws;
  22. static void try_to_suspend(struct work_struct *work)
  23. {
  24. unsigned int initial_count, final_count;
  25. int error = 0;
  26. if (!pm_get_wakeup_count(&initial_count, true))
  27. goto out;
  28. mutex_lock(&autosleep_lock);
  29. if (!pm_save_wakeup_count(initial_count)) {
  30. mutex_unlock(&autosleep_lock);
  31. goto out;
  32. }
  33. if (autosleep_state == PM_SUSPEND_ON) {
  34. mutex_unlock(&autosleep_lock);
  35. return;
  36. }
  37. if (autosleep_state >= PM_SUSPEND_MAX)
  38. hibernate();
  39. else
  40. error = pm_suspend(autosleep_state);
  41. mutex_unlock(&autosleep_lock);
  42. #ifdef CONFIG_SEC_PM
  43. if (error)
  44. goto out;
  45. #endif
  46. if (!pm_get_wakeup_count(&final_count, false))
  47. goto out;
  48. /*
  49. * If the wakeup occured for an unknown reason, wait to prevent the
  50. * system from trying to suspend and waking up in a tight loop.
  51. */
  52. if (final_count == initial_count)
  53. schedule_timeout_uninterruptible(HZ / 2);
  54. out:
  55. #ifdef CONFIG_SEC_PM
  56. if (error) {
  57. pr_info("PM: suspend returned(%d)\n", error);
  58. schedule_timeout_uninterruptible(HZ / 2);
  59. }
  60. #endif
  61. queue_up_suspend_work();
  62. }
  63. static DECLARE_WORK(suspend_work, try_to_suspend);
  64. void queue_up_suspend_work(void)
  65. {
  66. if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON)
  67. queue_work(autosleep_wq, &suspend_work);
  68. }
  69. suspend_state_t pm_autosleep_state(void)
  70. {
  71. return autosleep_state;
  72. }
  73. int pm_autosleep_lock(void)
  74. {
  75. return mutex_lock_interruptible(&autosleep_lock);
  76. }
  77. void pm_autosleep_unlock(void)
  78. {
  79. mutex_unlock(&autosleep_lock);
  80. }
  81. int pm_autosleep_set_state(suspend_state_t state)
  82. {
  83. #ifndef CONFIG_HIBERNATION
  84. if (state >= PM_SUSPEND_MAX)
  85. return -EINVAL;
  86. #endif
  87. __pm_stay_awake(autosleep_ws);
  88. mutex_lock(&autosleep_lock);
  89. autosleep_state = state;
  90. __pm_relax(autosleep_ws);
  91. #ifdef CONFIG_SEC_PM_DEBUG
  92. wakeup_sources_stats_active();
  93. #endif
  94. if (state > PM_SUSPEND_ON) {
  95. pm_wakep_autosleep_enabled(true);
  96. queue_up_suspend_work();
  97. } else {
  98. pm_wakep_autosleep_enabled(false);
  99. }
  100. mutex_unlock(&autosleep_lock);
  101. return 0;
  102. }
  103. int __init pm_autosleep_init(void)
  104. {
  105. autosleep_ws = wakeup_source_register("autosleep");
  106. if (!autosleep_ws)
  107. return -ENOMEM;
  108. autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
  109. if (autosleep_wq)
  110. return 0;
  111. wakeup_source_unregister(autosleep_ws);
  112. return -ENOMEM;
  113. }