autosleep.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. system_state != SYSTEM_RUNNING) {
  31. mutex_unlock(&autosleep_lock);
  32. goto out;
  33. }
  34. if (autosleep_state == PM_SUSPEND_ON) {
  35. mutex_unlock(&autosleep_lock);
  36. return;
  37. }
  38. if (autosleep_state >= PM_SUSPEND_MAX)
  39. hibernate();
  40. else
  41. error = pm_suspend(autosleep_state);
  42. mutex_unlock(&autosleep_lock);
  43. #ifdef CONFIG_SEC_PM
  44. if (error)
  45. goto out;
  46. #endif
  47. if (!pm_get_wakeup_count(&final_count, false))
  48. goto out;
  49. /*
  50. * If the wakeup occured for an unknown reason, wait to prevent the
  51. * system from trying to suspend and waking up in a tight loop.
  52. */
  53. if (final_count == initial_count)
  54. schedule_timeout_uninterruptible(HZ / 2);
  55. out:
  56. #ifdef CONFIG_SEC_PM
  57. if (error) {
  58. pr_info("PM: suspend returned(%d)\n", error);
  59. schedule_timeout_uninterruptible(HZ / 2);
  60. }
  61. #endif
  62. queue_up_suspend_work();
  63. }
  64. static DECLARE_WORK(suspend_work, try_to_suspend);
  65. void queue_up_suspend_work(void)
  66. {
  67. if (autosleep_state > PM_SUSPEND_ON)
  68. queue_work(autosleep_wq, &suspend_work);
  69. }
  70. suspend_state_t pm_autosleep_state(void)
  71. {
  72. return autosleep_state;
  73. }
  74. int pm_autosleep_lock(void)
  75. {
  76. return mutex_lock_interruptible(&autosleep_lock);
  77. }
  78. void pm_autosleep_unlock(void)
  79. {
  80. mutex_unlock(&autosleep_lock);
  81. }
  82. int pm_autosleep_set_state(suspend_state_t state)
  83. {
  84. #ifndef CONFIG_HIBERNATION
  85. if (state >= PM_SUSPEND_MAX)
  86. return -EINVAL;
  87. #endif
  88. __pm_stay_awake(autosleep_ws);
  89. mutex_lock(&autosleep_lock);
  90. autosleep_state = state;
  91. __pm_relax(autosleep_ws);
  92. #ifdef CONFIG_SEC_PM_DEBUG
  93. wakeup_sources_stats_active();
  94. #endif
  95. if (state > PM_SUSPEND_ON) {
  96. pm_wakep_autosleep_enabled(true);
  97. queue_up_suspend_work();
  98. } else {
  99. pm_wakep_autosleep_enabled(false);
  100. }
  101. mutex_unlock(&autosleep_lock);
  102. return 0;
  103. }
  104. int __init pm_autosleep_init(void)
  105. {
  106. autosleep_ws = wakeup_source_register(NULL, "autosleep");
  107. if (!autosleep_ws)
  108. return -ENOMEM;
  109. autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
  110. if (autosleep_wq)
  111. return 0;
  112. wakeup_source_unregister(autosleep_ws);
  113. return -ENOMEM;
  114. }