autosleep.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. if (!pm_get_wakeup_count(&initial_count, true))
  26. goto out;
  27. mutex_lock(&autosleep_lock);
  28. if (!pm_save_wakeup_count(initial_count) ||
  29. system_state != SYSTEM_RUNNING) {
  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. pm_suspend(autosleep_state);
  41. mutex_unlock(&autosleep_lock);
  42. if (!pm_get_wakeup_count(&final_count, false))
  43. goto out;
  44. /*
  45. * If the wakeup occured for an unknown reason, wait to prevent the
  46. * system from trying to suspend and waking up in a tight loop.
  47. */
  48. if (final_count == initial_count)
  49. schedule_timeout_uninterruptible(HZ / 2);
  50. out:
  51. queue_up_suspend_work();
  52. }
  53. static DECLARE_WORK(suspend_work, try_to_suspend);
  54. void queue_up_suspend_work(void)
  55. {
  56. if (autosleep_state > PM_SUSPEND_ON)
  57. queue_work(autosleep_wq, &suspend_work);
  58. }
  59. suspend_state_t pm_autosleep_state(void)
  60. {
  61. return autosleep_state;
  62. }
  63. int pm_autosleep_lock(void)
  64. {
  65. return mutex_lock_interruptible(&autosleep_lock);
  66. }
  67. void pm_autosleep_unlock(void)
  68. {
  69. mutex_unlock(&autosleep_lock);
  70. }
  71. int pm_autosleep_set_state(suspend_state_t state)
  72. {
  73. #ifndef CONFIG_HIBERNATION
  74. if (state >= PM_SUSPEND_MAX)
  75. return -EINVAL;
  76. #endif
  77. __pm_stay_awake(autosleep_ws);
  78. mutex_lock(&autosleep_lock);
  79. autosleep_state = state;
  80. __pm_relax(autosleep_ws);
  81. if (state > PM_SUSPEND_ON) {
  82. pm_wakep_autosleep_enabled(true);
  83. queue_up_suspend_work();
  84. } else {
  85. pm_wakep_autosleep_enabled(false);
  86. }
  87. mutex_unlock(&autosleep_lock);
  88. return 0;
  89. }
  90. int __init pm_autosleep_init(void)
  91. {
  92. autosleep_ws = wakeup_source_register("autosleep");
  93. if (!autosleep_ws)
  94. return -ENOMEM;
  95. autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
  96. if (autosleep_wq)
  97. return 0;
  98. wakeup_source_unregister(autosleep_ws);
  99. return -ENOMEM;
  100. }