Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
aa9abe2c
Commit
aa9abe2c
authored
May 07, 2014
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'pm-cpuidle' into pm-sleep
parents
2c730785
a6220fc1
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
62 additions
and
39 deletions
+62
-39
drivers/cpuidle/cpuidle.c
drivers/cpuidle/cpuidle.c
+42
-13
drivers/cpuidle/governors/menu.c
drivers/cpuidle/governors/menu.c
+9
-8
include/linux/cpuidle.h
include/linux/cpuidle.h
+2
-5
kernel/power/suspend.c
kernel/power/suspend.c
+2
-0
kernel/sched/idle.c
kernel/sched/idle.c
+7
-13
No files found.
drivers/cpuidle/cpuidle.c
View file @
aa9abe2c
...
...
@@ -32,6 +32,7 @@ LIST_HEAD(cpuidle_detected_devices);
static
int
enabled_devices
;
static
int
off
__read_mostly
;
static
int
initialized
__read_mostly
;
static
bool
use_deepest_state
__read_mostly
;
int
cpuidle_disabled
(
void
)
{
...
...
@@ -65,23 +66,42 @@ int cpuidle_play_dead(void)
}
/**
* cpuidle_enabled - check if the cpuidle framework is ready
* @dev: cpuidle device for this cpu
* @drv: cpuidle driver for this cpu
* cpuidle_use_deepest_state - Enable/disable the "deepest idle" mode.
* @enable: Whether enable or disable the feature.
*
* If the "deepest idle" mode is enabled, cpuidle will ignore the governor and
* always use the state with the greatest exit latency (out of the states that
* are not disabled).
*
* Return 0 on success, otherwise:
* -NODEV : the cpuidle framework is not available
* -EBUSY : the cpuidle framework is not initialized
* This function can only be called after cpuidle_pause() to avoid races.
*/
int
cpuidle_enabled
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
)
void
cpuidle_use_deepest_state
(
bool
enable
)
{
if
(
off
||
!
initialized
)
return
-
ENODEV
;
use_deepest_state
=
enable
;
}
if
(
!
drv
||
!
dev
||
!
dev
->
enabled
)
return
-
EBUSY
;
/**
* cpuidle_find_deepest_state - Find the state of the greatest exit latency.
* @drv: cpuidle driver for a given CPU.
* @dev: cpuidle device for a given CPU.
*/
static
int
cpuidle_find_deepest_state
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
)
{
unsigned
int
latency_req
=
0
;
int
i
,
ret
=
CPUIDLE_DRIVER_STATE_START
-
1
;
return
0
;
for
(
i
=
CPUIDLE_DRIVER_STATE_START
;
i
<
drv
->
state_count
;
i
++
)
{
struct
cpuidle_state
*
s
=
&
drv
->
states
[
i
];
struct
cpuidle_state_usage
*
su
=
&
dev
->
states_usage
[
i
];
if
(
s
->
disabled
||
su
->
disable
||
s
->
exit_latency
<=
latency_req
)
continue
;
latency_req
=
s
->
exit_latency
;
ret
=
i
;
}
return
ret
;
}
/**
...
...
@@ -138,6 +158,15 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
*/
int
cpuidle_select
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
)
{
if
(
off
||
!
initialized
)
return
-
ENODEV
;
if
(
!
drv
||
!
dev
||
!
dev
->
enabled
)
return
-
EBUSY
;
if
(
unlikely
(
use_deepest_state
))
return
cpuidle_find_deepest_state
(
drv
,
dev
);
return
cpuidle_curr_governor
->
select
(
drv
,
dev
);
}
...
...
@@ -169,7 +198,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
*/
void
cpuidle_reflect
(
struct
cpuidle_device
*
dev
,
int
index
)
{
if
(
cpuidle_curr_governor
->
reflect
)
if
(
cpuidle_curr_governor
->
reflect
&&
!
unlikely
(
use_deepest_state
)
)
cpuidle_curr_governor
->
reflect
(
dev
,
index
);
}
...
...
drivers/cpuidle/governors/menu.c
View file @
aa9abe2c
...
...
@@ -296,7 +296,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
data
->
needs_update
=
0
;
}
data
->
last_state_idx
=
0
;
data
->
last_state_idx
=
CPUIDLE_DRIVER_STATE_START
-
1
;
/* Special case when user has set very strict latency requirement */
if
(
unlikely
(
latency_req
==
0
))
...
...
@@ -310,13 +310,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
data
->
bucket
=
which_bucket
(
data
->
next_timer_us
);
/*
* if the correction factor is 0 (eg first time init or cpu hotplug
* etc), we actually want to start out with a unity factor.
*/
if
(
data
->
correction_factor
[
data
->
bucket
]
==
0
)
data
->
correction_factor
[
data
->
bucket
]
=
RESOLUTION
*
DECAY
;
/*
* Force the result of multiplication to be 64 bits even if both
* operands are 32 bits.
...
...
@@ -466,9 +459,17 @@ static int menu_enable_device(struct cpuidle_driver *drv,
struct
cpuidle_device
*
dev
)
{
struct
menu_device
*
data
=
&
per_cpu
(
menu_devices
,
dev
->
cpu
);
int
i
;
memset
(
data
,
0
,
sizeof
(
struct
menu_device
));
/*
* if the correction factor is 0 (eg first time init or cpu hotplug
* etc), we actually want to start out with a unity factor.
*/
for
(
i
=
0
;
i
<
BUCKETS
;
i
++
)
data
->
correction_factor
[
i
]
=
RESOLUTION
*
DECAY
;
return
0
;
}
...
...
include/linux/cpuidle.h
View file @
aa9abe2c
...
...
@@ -120,8 +120,6 @@ struct cpuidle_driver {
#ifdef CONFIG_CPU_IDLE
extern
void
disable_cpuidle
(
void
);
extern
int
cpuidle_enabled
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
);
extern
int
cpuidle_select
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
);
extern
int
cpuidle_enter
(
struct
cpuidle_driver
*
drv
,
...
...
@@ -145,13 +143,11 @@ extern void cpuidle_resume(void);
extern
int
cpuidle_enable_device
(
struct
cpuidle_device
*
dev
);
extern
void
cpuidle_disable_device
(
struct
cpuidle_device
*
dev
);
extern
int
cpuidle_play_dead
(
void
);
extern
void
cpuidle_use_deepest_state
(
bool
enable
);
extern
struct
cpuidle_driver
*
cpuidle_get_cpu_driver
(
struct
cpuidle_device
*
dev
);
#else
static
inline
void
disable_cpuidle
(
void
)
{
}
static
inline
int
cpuidle_enabled
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
)
{
return
-
ENODEV
;
}
static
inline
int
cpuidle_select
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
)
{
return
-
ENODEV
;
}
...
...
@@ -180,6 +176,7 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
{
return
-
ENODEV
;
}
static
inline
void
cpuidle_disable_device
(
struct
cpuidle_device
*
dev
)
{
}
static
inline
int
cpuidle_play_dead
(
void
)
{
return
-
ENODEV
;
}
static
inline
void
cpuidle_use_deepest_state
(
bool
enable
)
{}
static
inline
struct
cpuidle_driver
*
cpuidle_get_cpu_driver
(
struct
cpuidle_device
*
dev
)
{
return
NULL
;
}
#endif
...
...
kernel/power/suspend.c
View file @
aa9abe2c
...
...
@@ -54,9 +54,11 @@ static void freeze_begin(void)
static
void
freeze_enter
(
void
)
{
cpuidle_use_deepest_state
(
true
);
cpuidle_resume
();
wait_event
(
suspend_freeze_wait_head
,
suspend_freeze_wake
);
cpuidle_pause
();
cpuidle_use_deepest_state
(
false
);
}
void
freeze_wake
(
void
)
...
...
kernel/sched/idle.c
View file @
aa9abe2c
...
...
@@ -101,19 +101,13 @@ static int cpuidle_idle_call(void)
rcu_idle_enter
();
/*
* Check if the cpuidle framework is ready, otherwise fallback
* to the default arch specific idle method
*/
ret
=
cpuidle_enabled
(
drv
,
dev
);
if
(
!
ret
)
{
/*
* Ask the governor to choose an idle state it thinks
* it is convenient to go to. There is *always* a
* convenient idle state
* Ask the cpuidle framework to choose a convenient idle state.
* Fall back to the default arch specific idle method on errors.
*/
next_state
=
cpuidle_select
(
drv
,
dev
);
ret
=
next_state
;
if
(
ret
>=
0
)
{
/*
* The idle task must be scheduled, it is pointless to
* go to idle, just update no idle residency and get
...
...
@@ -140,7 +134,7 @@ static int cpuidle_idle_call(void)
CLOCK_EVT_NOTIFY_BROADCAST_ENTER
,
&
dev
->
cpu
);
if
(
!
ret
)
{
if
(
ret
>=
0
)
{
trace_cpu_idle_rcuidle
(
next_state
,
dev
->
cpu
);
/*
...
...
@@ -175,7 +169,7 @@ static int cpuidle_idle_call(void)
* We can't use the cpuidle framework, let's use the default
* idle routine
*/
if
(
ret
)
if
(
ret
<
0
)
arch_cpu_idle
();
__current_set_polling
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment