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
e4719b52
Commit
e4719b52
authored
Dec 22, 2021
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge back PM core changes for v5.17.
parents
544e737d
2cdbd92c
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
131 additions
and
75 deletions
+131
-75
Documentation/power/runtime_pm.rst
Documentation/power/runtime_pm.rst
+10
-4
drivers/base/core.c
drivers/base/core.c
+1
-2
drivers/base/power/runtime.c
drivers/base/power/runtime.c
+55
-31
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/jz4740_mmc.c
+4
-4
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxcmmc.c
+2
-4
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/realtek/r8169_main.c
+3
-1
include/linux/pm.h
include/linux/pm.h
+53
-29
include/linux/pm_runtime.h
include/linux/pm_runtime.h
+3
-0
No files found.
Documentation/power/runtime_pm.rst
View file @
e4719b52
...
...
@@ -265,6 +265,10 @@ defined in include/linux/pm.h:
RPM_SUSPENDED, which means that each device is initially regarded by the
PM core as 'suspended', regardless of its real hardware status
`enum rpm_status last_status;`
- the last runtime PM status of the device captured before disabling runtime
PM for it (invalid initially and when disable_depth is 0)
`unsigned int runtime_auto;`
- if set, indicates that the user space has allowed the device driver to
power manage the device at run time via the /sys/devices/.../power/control
...
...
@@ -333,10 +337,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
`int pm_runtime_resume(struct device *dev);`
- execute the subsystem-level resume callback for the device; returns 0 on
success, 1 if the device's runtime PM status was already 'active' or
error code on failure, where -EAGAIN means it may be safe to attempt to
resume the device again in future, but 'power.runtime_error' should be
checked additionally, and -EACCES means that 'power.disable_depth' is
success, 1 if the device's runtime PM status is already 'active' (also if
'power.disable_depth' is nonzero, but the status was 'active' when it was
changing from 0 to 1) or error code on failure, where -EAGAIN means it may
be safe to attempt to resume the device again in future, but
'power.runtime_error' should be checked additionally, and -EACCES means
that the callback could not be run, because 'power.disable_depth' was
different from 0
`int pm_runtime_resume_and_get(struct device *dev);`
...
...
drivers/base/core.c
View file @
e4719b52
...
...
@@ -485,8 +485,7 @@ static void device_link_release_fn(struct work_struct *work)
/* Ensure that all references to the link object have been dropped. */
device_link_synchronize_removal
();
while
(
refcount_dec_not_one
(
&
link
->
rpm_active
))
pm_runtime_put
(
link
->
supplier
);
pm_runtime_release_supplier
(
link
,
true
);
put_device
(
link
->
consumer
);
put_device
(
link
->
supplier
);
...
...
drivers/base/power/runtime.c
View file @
e4719b52
...
...
@@ -305,19 +305,40 @@ static int rpm_get_suppliers(struct device *dev)
return
0
;
}
/**
* pm_runtime_release_supplier - Drop references to device link's supplier.
* @link: Target device link.
* @check_idle: Whether or not to check if the supplier device is idle.
*
* Drop all runtime PM references associated with @link to its supplier device
* and if @check_idle is set, check if that device is idle (and so it can be
* suspended).
*/
void
pm_runtime_release_supplier
(
struct
device_link
*
link
,
bool
check_idle
)
{
struct
device
*
supplier
=
link
->
supplier
;
/*
* The additional power.usage_count check is a safety net in case
* the rpm_active refcount becomes saturated, in which case
* refcount_dec_not_one() would return true forever, but it is not
* strictly necessary.
*/
while
(
refcount_dec_not_one
(
&
link
->
rpm_active
)
&&
atomic_read
(
&
supplier
->
power
.
usage_count
)
>
0
)
pm_runtime_put_noidle
(
supplier
);
if
(
check_idle
)
pm_request_idle
(
supplier
);
}
static
void
__rpm_put_suppliers
(
struct
device
*
dev
,
bool
try_to_suspend
)
{
struct
device_link
*
link
;
list_for_each_entry_rcu
(
link
,
&
dev
->
links
.
suppliers
,
c_node
,
device_links_read_lock_held
())
{
while
(
refcount_dec_not_one
(
&
link
->
rpm_active
))
pm_runtime_put_noidle
(
link
->
supplier
);
if
(
try_to_suspend
)
pm_request_idle
(
link
->
supplier
);
}
device_links_read_lock_held
())
pm_runtime_release_supplier
(
link
,
try_to_suspend
);
}
static
void
rpm_put_suppliers
(
struct
device
*
dev
)
...
...
@@ -742,13 +763,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
trace_rpm_resume_rcuidle
(
dev
,
rpmflags
);
repeat:
if
(
dev
->
power
.
runtime_error
)
if
(
dev
->
power
.
runtime_error
)
{
retval
=
-
EINVAL
;
else
if
(
dev
->
power
.
disable_depth
==
1
&&
dev
->
power
.
is_suspended
&&
dev
->
power
.
runtime_status
==
RPM_ACTIVE
)
retval
=
1
;
else
if
(
dev
->
power
.
disable_depth
>
0
)
retval
=
-
EACCES
;
}
else
if
(
dev
->
power
.
disable_depth
>
0
)
{
if
(
dev
->
power
.
runtime_status
==
RPM_ACTIVE
&&
dev
->
power
.
last_status
==
RPM_ACTIVE
)
retval
=
1
;
else
retval
=
-
EACCES
;
}
if
(
retval
)
goto
out
;
...
...
@@ -1410,8 +1433,10 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
/* Update time accounting before disabling PM-runtime. */
update_pm_runtime_accounting
(
dev
);
if
(
!
dev
->
power
.
disable_depth
++
)
if
(
!
dev
->
power
.
disable_depth
++
)
{
__pm_runtime_barrier
(
dev
);
dev
->
power
.
last_status
=
dev
->
power
.
runtime_status
;
}
out:
spin_unlock_irq
(
&
dev
->
power
.
lock
);
...
...
@@ -1428,23 +1453,23 @@ void pm_runtime_enable(struct device *dev)
spin_lock_irqsave
(
&
dev
->
power
.
lock
,
flags
);
if
(
dev
->
power
.
disable_depth
>
0
)
{
dev
->
power
.
disable_depth
--
;
/* About to enable runtime pm, set accounting_timestamp to now */
if
(
!
dev
->
power
.
disable_depth
)
dev
->
power
.
accounting_timestamp
=
ktime_get_mono_fast_ns
();
}
else
{
if
(
!
dev
->
power
.
disable_depth
)
{
dev_warn
(
dev
,
"Unbalanced %s!
\n
"
,
__func__
);
goto
out
;
}
WARN
(
!
dev
->
power
.
disable_depth
&&
dev
->
power
.
runtime_status
==
RPM_SUSPENDED
&&
!
dev
->
power
.
ignore_children
&&
atomic_read
(
&
dev
->
power
.
child_count
)
>
0
,
"Enabling runtime PM for inactive device (%s) with active children
\n
"
,
dev_name
(
dev
));
if
(
--
dev
->
power
.
disable_depth
>
0
)
goto
out
;
dev
->
power
.
last_status
=
RPM_INVALID
;
dev
->
power
.
accounting_timestamp
=
ktime_get_mono_fast_ns
();
if
(
dev
->
power
.
runtime_status
==
RPM_SUSPENDED
&&
!
dev
->
power
.
ignore_children
&&
atomic_read
(
&
dev
->
power
.
child_count
)
>
0
)
dev_warn
(
dev
,
"Enabling runtime PM for inactive device with active children
\n
"
);
out:
spin_unlock_irqrestore
(
&
dev
->
power
.
lock
,
flags
);
}
EXPORT_SYMBOL_GPL
(
pm_runtime_enable
);
...
...
@@ -1640,6 +1665,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);
void
pm_runtime_init
(
struct
device
*
dev
)
{
dev
->
power
.
runtime_status
=
RPM_SUSPENDED
;
dev
->
power
.
last_status
=
RPM_INVALID
;
dev
->
power
.
idle_notification
=
false
;
dev
->
power
.
disable_depth
=
1
;
...
...
@@ -1772,9 +1798,7 @@ void pm_runtime_drop_link(struct device_link *link)
return
;
pm_runtime_drop_link_count
(
link
->
consumer
);
while
(
refcount_dec_not_one
(
&
link
->
rpm_active
))
pm_runtime_put
(
link
->
supplier
);
pm_runtime_release_supplier
(
link
,
true
);
}
static
bool
pm_runtime_need_not_resume
(
struct
device
*
dev
)
...
...
drivers/mmc/host/jz4740_mmc.c
View file @
e4719b52
...
...
@@ -1103,17 +1103,17 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
return
0
;
}
static
int
__maybe_unused
jz4740_mmc_suspend
(
struct
device
*
dev
)
static
int
jz4740_mmc_suspend
(
struct
device
*
dev
)
{
return
pinctrl_pm_select_sleep_state
(
dev
);
}
static
int
__maybe_unused
jz4740_mmc_resume
(
struct
device
*
dev
)
static
int
jz4740_mmc_resume
(
struct
device
*
dev
)
{
return
pinctrl_select_default_state
(
dev
);
}
static
SIMPLE_DEV_PM_OPS
(
jz4740_mmc_pm_ops
,
jz4740_mmc_suspend
,
DEFINE_
SIMPLE_DEV_PM_OPS
(
jz4740_mmc_pm_ops
,
jz4740_mmc_suspend
,
jz4740_mmc_resume
);
static
struct
platform_driver
jz4740_mmc_driver
=
{
...
...
@@ -1123,7 +1123,7 @@ static struct platform_driver jz4740_mmc_driver = {
.
name
=
"jz4740-mmc"
,
.
probe_type
=
PROBE_PREFER_ASYNCHRONOUS
,
.
of_match_table
=
of_match_ptr
(
jz4740_mmc_of_match
),
.
pm
=
pm_ptr
(
&
jz4740_mmc_pm_ops
),
.
pm
=
pm_
sleep_
ptr
(
&
jz4740_mmc_pm_ops
),
},
};
...
...
drivers/mmc/host/mxcmmc.c
View file @
e4719b52
...
...
@@ -1183,7 +1183,6 @@ static int mxcmci_remove(struct platform_device *pdev)
return
0
;
}
#ifdef CONFIG_PM_SLEEP
static
int
mxcmci_suspend
(
struct
device
*
dev
)
{
struct
mmc_host
*
mmc
=
dev_get_drvdata
(
dev
);
...
...
@@ -1210,9 +1209,8 @@ static int mxcmci_resume(struct device *dev)
return
ret
;
}
#endif
static
SIMPLE_DEV_PM_OPS
(
mxcmci_pm_ops
,
mxcmci_suspend
,
mxcmci_resume
);
DEFINE_
SIMPLE_DEV_PM_OPS
(
mxcmci_pm_ops
,
mxcmci_suspend
,
mxcmci_resume
);
static
struct
platform_driver
mxcmci_driver
=
{
.
probe
=
mxcmci_probe
,
...
...
@@ -1220,7 +1218,7 @@ static struct platform_driver mxcmci_driver = {
.
driver
=
{
.
name
=
DRIVER_NAME
,
.
probe_type
=
PROBE_PREFER_ASYNCHRONOUS
,
.
pm
=
&
mxcmci_pm_ops
,
.
pm
=
pm_sleep_ptr
(
&
mxcmci_pm_ops
)
,
.
of_match_table
=
mxcmci_of_match
,
}
};
...
...
drivers/net/ethernet/realtek/r8169_main.c
View file @
e4719b52
...
...
@@ -5441,7 +5441,9 @@ static struct pci_driver rtl8169_pci_driver = {
.
probe
=
rtl_init_one
,
.
remove
=
rtl_remove_one
,
.
shutdown
=
rtl_shutdown
,
.
driver
.
pm
=
pm_ptr
(
&
rtl8169_pm_ops
),
#ifdef CONFIG_PM
.
driver
.
pm
=
&
rtl8169_pm_ops
,
#endif
};
module_pci_driver
(
rtl8169_pci_driver
);
include/linux/pm.h
View file @
e4719b52
...
...
@@ -300,47 +300,59 @@ struct dev_pm_ops {
int
(
*
runtime_idle
)(
struct
device
*
dev
);
};
#define SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
.suspend = pm_sleep_ptr(suspend_fn), \
.resume = pm_sleep_ptr(resume_fn), \
.freeze = pm_sleep_ptr(suspend_fn), \
.thaw = pm_sleep_ptr(resume_fn), \
.poweroff = pm_sleep_ptr(suspend_fn), \
.restore = pm_sleep_ptr(resume_fn),
#define LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
.suspend_late = pm_sleep_ptr(suspend_fn), \
.resume_early = pm_sleep_ptr(resume_fn), \
.freeze_late = pm_sleep_ptr(suspend_fn), \
.thaw_early = pm_sleep_ptr(resume_fn), \
.poweroff_late = pm_sleep_ptr(suspend_fn), \
.restore_early = pm_sleep_ptr(resume_fn),
#define NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
.suspend_noirq = pm_sleep_ptr(suspend_fn), \
.resume_noirq = pm_sleep_ptr(resume_fn), \
.freeze_noirq = pm_sleep_ptr(suspend_fn), \
.thaw_noirq = pm_sleep_ptr(resume_fn), \
.poweroff_noirq = pm_sleep_ptr(suspend_fn), \
.restore_noirq = pm_sleep_ptr(resume_fn),
#define RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
.runtime_suspend = suspend_fn, \
.runtime_resume = resume_fn, \
.runtime_idle = idle_fn,
#ifdef CONFIG_PM_SLEEP
#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
.suspend = suspend_fn, \
.resume = resume_fn, \
.freeze = suspend_fn, \
.thaw = resume_fn, \
.poweroff = suspend_fn, \
.restore = resume_fn,
SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#else
#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#endif
#ifdef CONFIG_PM_SLEEP
#define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
.suspend_late = suspend_fn, \
.resume_early = resume_fn, \
.freeze_late = suspend_fn, \
.thaw_early = resume_fn, \
.poweroff_late = suspend_fn, \
.restore_early = resume_fn,
LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#else
#define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#endif
#ifdef CONFIG_PM_SLEEP
#define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
.suspend_noirq = suspend_fn, \
.resume_noirq = resume_fn, \
.freeze_noirq = suspend_fn, \
.thaw_noirq = resume_fn, \
.poweroff_noirq = suspend_fn, \
.restore_noirq = resume_fn,
NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#else
#define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#endif
#ifdef CONFIG_PM
#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
.runtime_suspend = suspend_fn, \
.runtime_resume = resume_fn, \
.runtime_idle = idle_fn,
RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
#else
#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
#endif
...
...
@@ -349,9 +361,9 @@ struct dev_pm_ops {
* Use this if you want to use the same suspend and resume callbacks for suspend
* to RAM and hibernation.
*/
#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
const struct dev_pm_ops __maybe_unused
name = { \
S
ET_S
YSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
#define
DEFINE_
SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
static const struct dev_pm_ops
name = { \
SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}
/*
...
...
@@ -367,17 +379,27 @@ const struct dev_pm_ops __maybe_unused name = { \
* .resume_early(), to the same routines as .runtime_suspend() and
* .runtime_resume(), respectively (and analogously for hibernation).
*/
#define DEFINE_UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \
static const struct dev_pm_ops name = { \
SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
}
/* Deprecated. Use DEFINE_SIMPLE_DEV_PM_OPS() instead. */
#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
const struct dev_pm_ops __maybe_unused name = { \
SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}
/* Deprecated. Use DEFINE_UNIVERSAL_DEV_PM_OPS() instead. */
#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \
const struct dev_pm_ops __maybe_unused name = { \
SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
}
#ifdef CONFIG_PM
#define pm_ptr(_ptr) (_ptr)
#else
#define pm_ptr(_ptr) NULL
#endif
#define pm_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM), (_ptr))
#define pm_sleep_ptr(_ptr) PTR_IF(IS_ENABLED(CONFIG_PM_SLEEP), (_ptr))
/*
* PM_EVENT_ messages
...
...
@@ -499,6 +521,7 @@ const struct dev_pm_ops __maybe_unused name = { \
*/
enum
rpm_status
{
RPM_INVALID
=
-
1
,
RPM_ACTIVE
=
0
,
RPM_RESUMING
,
RPM_SUSPENDED
,
...
...
@@ -612,6 +635,7 @@ struct dev_pm_info {
unsigned
int
links_count
;
enum
rpm_request
request
;
enum
rpm_status
runtime_status
;
enum
rpm_status
last_status
;
int
runtime_error
;
int
autosuspend_delay
;
u64
last_busy
;
...
...
include/linux/pm_runtime.h
View file @
e4719b52
...
...
@@ -58,6 +58,7 @@ extern void pm_runtime_get_suppliers(struct device *dev);
extern
void
pm_runtime_put_suppliers
(
struct
device
*
dev
);
extern
void
pm_runtime_new_link
(
struct
device
*
dev
);
extern
void
pm_runtime_drop_link
(
struct
device_link
*
link
);
extern
void
pm_runtime_release_supplier
(
struct
device_link
*
link
,
bool
check_idle
);
extern
int
devm_pm_runtime_enable
(
struct
device
*
dev
);
...
...
@@ -283,6 +284,8 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
static
inline
void
pm_runtime_put_suppliers
(
struct
device
*
dev
)
{}
static
inline
void
pm_runtime_new_link
(
struct
device
*
dev
)
{}
static
inline
void
pm_runtime_drop_link
(
struct
device_link
*
link
)
{}
static
inline
void
pm_runtime_release_supplier
(
struct
device_link
*
link
,
bool
check_idle
)
{}
#endif
/* !CONFIG_PM */
...
...
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