Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
kernel
power
autosleep.c
Go to the documentation of this file.
1
/*
2
* kernel/power/autosleep.c
3
*
4
* Opportunistic sleep support.
5
*
6
* Copyright (C) 2012 Rafael J. Wysocki <
[email protected]
>
7
*/
8
9
#include <linux/device.h>
10
#include <
linux/mutex.h
>
11
#include <
linux/pm_wakeup.h
>
12
13
#include "
power.h
"
14
15
static
suspend_state_t
autosleep_state;
16
static
struct
workqueue_struct
*autosleep_wq;
17
/*
18
* Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
19
* is active, otherwise a deadlock with try_to_suspend() is possible.
20
* Alternatively mutex_lock_interruptible() can be used. This will then fail
21
* if an auto_sleep cycle tries to freeze processes.
22
*/
23
static
DEFINE_MUTEX
(autosleep_lock);
24
static
struct
wakeup_source
*autosleep_ws;
25
26
static
void
try_to_suspend(
struct
work_struct
*
work
)
27
{
28
unsigned
int
initial_count
, final_count;
29
30
if
(!
pm_get_wakeup_count
(&initial_count,
true
))
31
goto
out
;
32
33
mutex_lock
(&autosleep_lock);
34
35
if
(!
pm_save_wakeup_count
(initial_count)) {
36
mutex_unlock
(&autosleep_lock);
37
goto
out
;
38
}
39
40
if
(autosleep_state ==
PM_SUSPEND_ON
) {
41
mutex_unlock
(&autosleep_lock);
42
return
;
43
}
44
if
(autosleep_state >=
PM_SUSPEND_MAX
)
45
hibernate
();
46
else
47
pm_suspend
(autosleep_state);
48
49
mutex_unlock
(&autosleep_lock);
50
51
if
(!
pm_get_wakeup_count
(&final_count,
false
))
52
goto
out
;
53
54
/*
55
* If the wakeup occured for an unknown reason, wait to prevent the
56
* system from trying to suspend and waking up in a tight loop.
57
*/
58
if
(final_count == initial_count)
59
schedule_timeout_uninterruptible
(
HZ
/ 2);
60
61
out
:
62
queue_up_suspend_work
();
63
}
64
65
static
DECLARE_WORK
(suspend_work, try_to_suspend);
66
67
void
queue_up_suspend_work
(
void
)
68
{
69
if
(!
work_pending
(&suspend_work) && autosleep_state >
PM_SUSPEND_ON
)
70
queue_work
(autosleep_wq, &suspend_work);
71
}
72
73
suspend_state_t
pm_autosleep_state
(
void
)
74
{
75
return
autosleep_state;
76
}
77
78
int
pm_autosleep_lock
(
void
)
79
{
80
return
mutex_lock_interruptible
(&autosleep_lock);
81
}
82
83
void
pm_autosleep_unlock
(
void
)
84
{
85
mutex_unlock
(&autosleep_lock);
86
}
87
88
int
pm_autosleep_set_state
(
suspend_state_t
state
)
89
{
90
91
#ifndef CONFIG_HIBERNATION
92
if
(state >=
PM_SUSPEND_MAX
)
93
return
-
EINVAL
;
94
#endif
95
96
__pm_stay_awake
(autosleep_ws);
97
98
mutex_lock
(&autosleep_lock);
99
100
autosleep_state =
state
;
101
102
__pm_relax
(autosleep_ws);
103
104
if
(state >
PM_SUSPEND_ON
) {
105
pm_wakep_autosleep_enabled(
true
);
106
queue_up_suspend_work
();
107
}
else
{
108
pm_wakep_autosleep_enabled(
false
);
109
}
110
111
mutex_unlock
(&autosleep_lock);
112
return
0;
113
}
114
115
int
__init
pm_autosleep_init
(
void
)
116
{
117
autosleep_ws =
wakeup_source_register
(
"autosleep"
);
118
if
(!autosleep_ws)
119
return
-
ENOMEM
;
120
121
autosleep_wq =
alloc_ordered_workqueue
(
"autosleep"
, 0);
122
if
(autosleep_wq)
123
return
0;
124
125
wakeup_source_unregister
(autosleep_ws);
126
return
-
ENOMEM
;
127
}
Generated on Thu Jan 10 2013 14:54:42 for Linux Kernel by
1.8.2