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
Kirill Smelkov
linux
Commits
0015afaa
Commit
0015afaa
authored
Dec 25, 2011
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'pm-runtime' into pm-for-linus
* pm-runtime: PM / Runtime: Use device PM QoS constraints (v2)
parents
b7ba68c4
00dc9ad1
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
154 additions
and
28 deletions
+154
-28
drivers/base/power/qos.c
drivers/base/power/qos.c
+16
-8
drivers/base/power/runtime.c
drivers/base/power/runtime.c
+128
-20
include/linux/pm.h
include/linux/pm.h
+2
-0
include/linux/pm_qos.h
include/linux/pm_qos.h
+3
-0
include/linux/pm_runtime.h
include/linux/pm_runtime.h
+5
-0
No files found.
drivers/base/power/qos.c
View file @
0015afaa
...
...
@@ -47,21 +47,29 @@ static DEFINE_MUTEX(dev_pm_qos_mtx);
static
BLOCKING_NOTIFIER_HEAD
(
dev_pm_notifiers
);
/**
* dev_pm_qos_read_value - Get PM QoS constraint for a given device.
* __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
* @dev: Device to get the PM QoS constraint value for.
*
* This routine must be called with dev->power.lock held.
*/
s32
__dev_pm_qos_read_value
(
struct
device
*
dev
)
{
struct
pm_qos_constraints
*
c
=
dev
->
power
.
constraints
;
return
c
?
pm_qos_read_value
(
c
)
:
0
;
}
/**
* dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
* @dev: Device to get the PM QoS constraint value for.
*/
s32
dev_pm_qos_read_value
(
struct
device
*
dev
)
{
struct
pm_qos_constraints
*
c
;
unsigned
long
flags
;
s32
ret
=
0
;
s32
ret
;
spin_lock_irqsave
(
&
dev
->
power
.
lock
,
flags
);
c
=
dev
->
power
.
constraints
;
if
(
c
)
ret
=
pm_qos_read_value
(
c
);
ret
=
__dev_pm_qos_read_value
(
dev
);
spin_unlock_irqrestore
(
&
dev
->
power
.
lock
,
flags
);
return
ret
;
...
...
drivers/base/power/runtime.c
View file @
0015afaa
...
...
@@ -282,6 +282,47 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
return
retval
!=
-
EACCES
?
retval
:
-
EIO
;
}
struct
rpm_qos_data
{
ktime_t
time_now
;
s64
constraint_ns
;
};
/**
* rpm_update_qos_constraint - Update a given PM QoS constraint data.
* @dev: Device whose timing data to use.
* @data: PM QoS constraint data to update.
*
* Use the suspend timing data of @dev to update PM QoS constraint data pointed
* to by @data.
*/
static
int
rpm_update_qos_constraint
(
struct
device
*
dev
,
void
*
data
)
{
struct
rpm_qos_data
*
qos
=
data
;
unsigned
long
flags
;
s64
delta_ns
;
int
ret
=
0
;
spin_lock_irqsave
(
&
dev
->
power
.
lock
,
flags
);
if
(
dev
->
power
.
max_time_suspended_ns
<
0
)
goto
out
;
delta_ns
=
dev
->
power
.
max_time_suspended_ns
-
ktime_to_ns
(
ktime_sub
(
qos
->
time_now
,
dev
->
power
.
suspend_time
));
if
(
delta_ns
<=
0
)
{
ret
=
-
EBUSY
;
goto
out
;
}
if
(
qos
->
constraint_ns
>
delta_ns
||
qos
->
constraint_ns
==
0
)
qos
->
constraint_ns
=
delta_ns
;
out:
spin_unlock_irqrestore
(
&
dev
->
power
.
lock
,
flags
);
return
ret
;
}
/**
* rpm_suspend - Carry out runtime suspend of given device.
* @dev: Device to suspend.
...
...
@@ -308,6 +349,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
{
int
(
*
callback
)(
struct
device
*
);
struct
device
*
parent
=
NULL
;
struct
rpm_qos_data
qos
;
int
retval
;
trace_rpm_suspend
(
dev
,
rpmflags
);
...
...
@@ -403,8 +445,38 @@ static int rpm_suspend(struct device *dev, int rpmflags)
goto
out
;
}
qos
.
constraint_ns
=
__dev_pm_qos_read_value
(
dev
);
if
(
qos
.
constraint_ns
<
0
)
{
/* Negative constraint means "never suspend". */
retval
=
-
EPERM
;
goto
out
;
}
qos
.
constraint_ns
*=
NSEC_PER_USEC
;
qos
.
time_now
=
ktime_get
();
__update_runtime_status
(
dev
,
RPM_SUSPENDING
);
if
(
!
dev
->
power
.
ignore_children
)
{
if
(
dev
->
power
.
irq_safe
)
spin_unlock
(
&
dev
->
power
.
lock
);
else
spin_unlock_irq
(
&
dev
->
power
.
lock
);
retval
=
device_for_each_child
(
dev
,
&
qos
,
rpm_update_qos_constraint
);
if
(
dev
->
power
.
irq_safe
)
spin_lock
(
&
dev
->
power
.
lock
);
else
spin_lock_irq
(
&
dev
->
power
.
lock
);
if
(
retval
)
goto
fail
;
}
dev
->
power
.
suspend_time
=
qos
.
time_now
;
dev
->
power
.
max_time_suspended_ns
=
qos
.
constraint_ns
?
:
-
1
;
if
(
dev
->
pm_domain
)
callback
=
dev
->
pm_domain
->
ops
.
runtime_suspend
;
else
if
(
dev
->
type
&&
dev
->
type
->
pm
)
...
...
@@ -420,27 +492,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
callback
=
dev
->
driver
->
pm
->
runtime_suspend
;
retval
=
rpm_callback
(
callback
,
dev
);
if
(
retval
)
{
__update_runtime_status
(
dev
,
RPM_ACTIVE
);
dev
->
power
.
deferred_resume
=
false
;
if
(
retval
==
-
EAGAIN
||
retval
==
-
EBUSY
)
{
dev
->
power
.
runtime_error
=
0
;
if
(
retval
)
goto
fail
;
/*
* If the callback routine failed an autosuspend, and
* if the last_busy time has been updated so that there
* is a new autosuspend expiration time, automatically
* reschedule another autosuspend.
*/
if
((
rpmflags
&
RPM_AUTO
)
&&
pm_runtime_autosuspend_expiration
(
dev
)
!=
0
)
goto
repeat
;
}
else
{
pm_runtime_cancel_pending
(
dev
);
}
wake_up_all
(
&
dev
->
power
.
wait_queue
);
goto
out
;
}
no_callback:
__update_runtime_status
(
dev
,
RPM_SUSPENDED
);
pm_runtime_deactivate_timer
(
dev
);
...
...
@@ -472,6 +526,29 @@ static int rpm_suspend(struct device *dev, int rpmflags)
trace_rpm_return_int
(
dev
,
_THIS_IP_
,
retval
);
return
retval
;
fail:
__update_runtime_status
(
dev
,
RPM_ACTIVE
);
dev
->
power
.
suspend_time
=
ktime_set
(
0
,
0
);
dev
->
power
.
max_time_suspended_ns
=
-
1
;
dev
->
power
.
deferred_resume
=
false
;
if
(
retval
==
-
EAGAIN
||
retval
==
-
EBUSY
)
{
dev
->
power
.
runtime_error
=
0
;
/*
* If the callback routine failed an autosuspend, and
* if the last_busy time has been updated so that there
* is a new autosuspend expiration time, automatically
* reschedule another autosuspend.
*/
if
((
rpmflags
&
RPM_AUTO
)
&&
pm_runtime_autosuspend_expiration
(
dev
)
!=
0
)
goto
repeat
;
}
else
{
pm_runtime_cancel_pending
(
dev
);
}
wake_up_all
(
&
dev
->
power
.
wait_queue
);
goto
out
;
}
/**
...
...
@@ -626,6 +703,9 @@ static int rpm_resume(struct device *dev, int rpmflags)
if
(
dev
->
power
.
no_callbacks
)
goto
no_callback
;
/* Assume success. */
dev
->
power
.
suspend_time
=
ktime_set
(
0
,
0
);
dev
->
power
.
max_time_suspended_ns
=
-
1
;
__update_runtime_status
(
dev
,
RPM_RESUMING
);
if
(
dev
->
pm_domain
)
...
...
@@ -1288,6 +1368,9 @@ void pm_runtime_init(struct device *dev)
setup_timer
(
&
dev
->
power
.
suspend_timer
,
pm_suspend_timer_fn
,
(
unsigned
long
)
dev
);
dev
->
power
.
suspend_time
=
ktime_set
(
0
,
0
);
dev
->
power
.
max_time_suspended_ns
=
-
1
;
init_waitqueue_head
(
&
dev
->
power
.
wait_queue
);
}
...
...
@@ -1305,3 +1388,28 @@ void pm_runtime_remove(struct device *dev)
if
(
dev
->
power
.
irq_safe
&&
dev
->
parent
)
pm_runtime_put_sync
(
dev
->
parent
);
}
/**
* pm_runtime_update_max_time_suspended - Update device's suspend time data.
* @dev: Device to handle.
* @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
*
* Update the device's power.max_time_suspended_ns field by subtracting
* @delta_ns from it. The resulting value of power.max_time_suspended_ns is
* never negative.
*/
void
pm_runtime_update_max_time_suspended
(
struct
device
*
dev
,
s64
delta_ns
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
dev
->
power
.
lock
,
flags
);
if
(
delta_ns
>
0
&&
dev
->
power
.
max_time_suspended_ns
>
0
)
{
if
(
dev
->
power
.
max_time_suspended_ns
>
delta_ns
)
dev
->
power
.
max_time_suspended_ns
-=
delta_ns
;
else
dev
->
power
.
max_time_suspended_ns
=
0
;
}
spin_unlock_irqrestore
(
&
dev
->
power
.
lock
,
flags
);
}
include/linux/pm.h
View file @
0015afaa
...
...
@@ -508,6 +508,8 @@ struct dev_pm_info {
unsigned
long
active_jiffies
;
unsigned
long
suspended_jiffies
;
unsigned
long
accounting_timestamp
;
ktime_t
suspend_time
;
s64
max_time_suspended_ns
;
#endif
struct
pm_subsys_data
*
subsys_data
;
/* Owned by the subsystem. */
struct
pm_qos_constraints
*
constraints
;
...
...
include/linux/pm_qos.h
View file @
0015afaa
...
...
@@ -78,6 +78,7 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
int
pm_qos_request_active
(
struct
pm_qos_request
*
req
);
s32
pm_qos_read_value
(
struct
pm_qos_constraints
*
c
);
s32
__dev_pm_qos_read_value
(
struct
device
*
dev
);
s32
dev_pm_qos_read_value
(
struct
device
*
dev
);
int
dev_pm_qos_add_request
(
struct
device
*
dev
,
struct
dev_pm_qos_request
*
req
,
s32
value
);
...
...
@@ -119,6 +120,8 @@ static inline int pm_qos_request_active(struct pm_qos_request *req)
static
inline
s32
pm_qos_read_value
(
struct
pm_qos_constraints
*
c
)
{
return
0
;
}
static
inline
s32
__dev_pm_qos_read_value
(
struct
device
*
dev
)
{
return
0
;
}
static
inline
s32
dev_pm_qos_read_value
(
struct
device
*
dev
)
{
return
0
;
}
static
inline
int
dev_pm_qos_add_request
(
struct
device
*
dev
,
...
...
include/linux/pm_runtime.h
View file @
0015afaa
...
...
@@ -45,6 +45,8 @@ extern void pm_runtime_irq_safe(struct device *dev);
extern
void
__pm_runtime_use_autosuspend
(
struct
device
*
dev
,
bool
use
);
extern
void
pm_runtime_set_autosuspend_delay
(
struct
device
*
dev
,
int
delay
);
extern
unsigned
long
pm_runtime_autosuspend_expiration
(
struct
device
*
dev
);
extern
void
pm_runtime_update_max_time_suspended
(
struct
device
*
dev
,
s64
delta_ns
);
static
inline
bool
pm_children_suspended
(
struct
device
*
dev
)
{
...
...
@@ -148,6 +150,9 @@ static inline void pm_runtime_set_autosuspend_delay(struct device *dev,
static
inline
unsigned
long
pm_runtime_autosuspend_expiration
(
struct
device
*
dev
)
{
return
0
;
}
static
inline
void
pm_runtime_update_max_time_suspended
(
struct
device
*
dev
,
s64
delta_ns
)
{}
#endif
/* !CONFIG_PM_RUNTIME */
static
inline
int
pm_runtime_idle
(
struct
device
*
dev
)
...
...
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