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
d89d7ff9
Commit
d89d7ff9
authored
Dec 07, 2015
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'pm-sleep' and 'pm-runtime' into pm-core
parents
7b06a6d7
013c074f
5de85b9d
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
90 additions
and
7 deletions
+90
-7
drivers/base/base.h
drivers/base/base.h
+2
-0
drivers/base/dd.c
drivers/base/dd.c
+49
-1
drivers/base/power/main.c
drivers/base/power/main.c
+17
-0
drivers/base/power/power.h
drivers/base/power/power.h
+2
-0
drivers/base/power/runtime.c
drivers/base/power/runtime.c
+20
-6
No files found.
drivers/base/base.h
View file @
d89d7ff9
...
...
@@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
extern
char
*
make_class_name
(
const
char
*
name
,
struct
kobject
*
kobj
);
extern
int
devres_release_all
(
struct
device
*
dev
);
extern
void
device_block_probing
(
void
);
extern
void
device_unblock_probing
(
void
);
/* /sys/devices directory */
extern
struct
kset
*
devices_kset
;
...
...
drivers/base/dd.c
View file @
d89d7ff9
...
...
@@ -54,6 +54,13 @@ static LIST_HEAD(deferred_probe_active_list);
static
struct
workqueue_struct
*
deferred_wq
;
static
atomic_t
deferred_trigger_count
=
ATOMIC_INIT
(
0
);
/*
* In some cases, like suspend to RAM or hibernation, It might be reasonable
* to prohibit probing of devices as it could be unsafe.
* Once defer_all_probes is true all drivers probes will be forcibly deferred.
*/
static
bool
defer_all_probes
;
/*
* deferred_probe_work_func() - Retry probing devices in the active list.
*/
...
...
@@ -171,6 +178,30 @@ static void driver_deferred_probe_trigger(void)
queue_work
(
deferred_wq
,
&
deferred_probe_work
);
}
/**
* device_block_probing() - Block/defere device's probes
*
* It will disable probing of devices and defer their probes instead.
*/
void
device_block_probing
(
void
)
{
defer_all_probes
=
true
;
/* sync with probes to avoid races. */
wait_for_device_probe
();
}
/**
* device_unblock_probing() - Unblock/enable device's probes
*
* It will restore normal behavior and trigger re-probing of deferred
* devices.
*/
void
device_unblock_probing
(
void
)
{
defer_all_probes
=
false
;
driver_deferred_probe_trigger
();
}
/**
* deferred_probe_initcall() - Enable probing of deferred devices
*
...
...
@@ -277,9 +308,20 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
static
int
really_probe
(
struct
device
*
dev
,
struct
device_driver
*
drv
)
{
int
ret
=
0
;
int
ret
=
-
EPROBE_DEFER
;
int
local_trigger_count
=
atomic_read
(
&
deferred_trigger_count
);
if
(
defer_all_probes
)
{
/*
* Value of defer_all_probes can be set only by
* device_defer_all_probes_enable() which, in turn, will call
* wait_for_device_probe() right after that to avoid any races.
*/
dev_dbg
(
dev
,
"Driver %s force probe deferral
\n
"
,
drv
->
name
);
driver_deferred_probe_add
(
dev
);
return
ret
;
}
atomic_inc
(
&
probe_count
);
pr_debug
(
"bus: '%s': %s: probing driver %s with device %s
\n
"
,
drv
->
bus
->
name
,
__func__
,
drv
->
name
,
dev_name
(
dev
));
...
...
@@ -340,6 +382,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
dev_set_drvdata
(
dev
,
NULL
);
if
(
dev
->
pm_domain
&&
dev
->
pm_domain
->
dismiss
)
dev
->
pm_domain
->
dismiss
(
dev
);
pm_runtime_reinit
(
dev
);
switch
(
ret
)
{
case
-
EPROBE_DEFER
:
...
...
@@ -393,6 +436,10 @@ int driver_probe_done(void)
*/
void
wait_for_device_probe
(
void
)
{
/* wait for the deferred probe workqueue to finish */
if
(
driver_deferred_probe_enable
)
flush_workqueue
(
deferred_wq
);
/* wait for the known devices to complete their probing */
wait_event
(
probe_waitqueue
,
atomic_read
(
&
probe_count
)
==
0
);
async_synchronize_full
();
...
...
@@ -695,6 +742,7 @@ static void __device_release_driver(struct device *dev)
dev_set_drvdata
(
dev
,
NULL
);
if
(
dev
->
pm_domain
&&
dev
->
pm_domain
->
dismiss
)
dev
->
pm_domain
->
dismiss
(
dev
);
pm_runtime_reinit
(
dev
);
klist_remove
(
&
dev
->
p
->
knode_driver
);
if
(
dev
->
bus
)
...
...
drivers/base/power/main.c
View file @
d89d7ff9
...
...
@@ -963,6 +963,9 @@ void dpm_complete(pm_message_t state)
}
list_splice
(
&
list
,
&
dpm_list
);
mutex_unlock
(
&
dpm_list_mtx
);
/* Allow device probing and trigger re-probing of deferred devices */
device_unblock_probing
();
trace_suspend_resume
(
TPS
(
"dpm_complete"
),
state
.
event
,
false
);
}
...
...
@@ -1624,6 +1627,20 @@ int dpm_prepare(pm_message_t state)
trace_suspend_resume
(
TPS
(
"dpm_prepare"
),
state
.
event
,
true
);
might_sleep
();
/*
* Give a chance for the known devices to complete their probes, before
* disable probing of devices. This sync point is important at least
* at boot time + hibernation restore.
*/
wait_for_device_probe
();
/*
* It is unsafe if probing of devices will happen during suspend or
* hibernation and system behavior will be unpredictable in this case.
* So, let's prohibit device's probing here and defer their probes
* instead. The normal behavior will be restored in dpm_complete().
*/
device_block_probing
();
mutex_lock
(
&
dpm_list_mtx
);
while
(
!
list_empty
(
&
dpm_list
))
{
struct
device
*
dev
=
to_device
(
dpm_list
.
next
);
...
...
drivers/base/power/power.h
View file @
d89d7ff9
...
...
@@ -18,6 +18,7 @@ static inline void pm_runtime_early_init(struct device *dev)
}
extern
void
pm_runtime_init
(
struct
device
*
dev
);
extern
void
pm_runtime_reinit
(
struct
device
*
dev
);
extern
void
pm_runtime_remove
(
struct
device
*
dev
);
struct
wake_irq
{
...
...
@@ -84,6 +85,7 @@ static inline void pm_runtime_early_init(struct device *dev)
}
static
inline
void
pm_runtime_init
(
struct
device
*
dev
)
{}
static
inline
void
pm_runtime_reinit
(
struct
device
*
dev
)
{}
static
inline
void
pm_runtime_remove
(
struct
device
*
dev
)
{}
static
inline
int
dpm_sysfs_add
(
struct
device
*
dev
)
{
return
0
;
}
...
...
drivers/base/power/runtime.c
View file @
d89d7ff9
...
...
@@ -1389,6 +1389,25 @@ void pm_runtime_init(struct device *dev)
init_waitqueue_head
(
&
dev
->
power
.
wait_queue
);
}
/**
* pm_runtime_reinit - Re-initialize runtime PM fields in given device object.
* @dev: Device object to re-initialize.
*/
void
pm_runtime_reinit
(
struct
device
*
dev
)
{
if
(
!
pm_runtime_enabled
(
dev
))
{
if
(
dev
->
power
.
runtime_status
==
RPM_ACTIVE
)
pm_runtime_set_suspended
(
dev
);
if
(
dev
->
power
.
irq_safe
)
{
spin_lock_irq
(
&
dev
->
power
.
lock
);
dev
->
power
.
irq_safe
=
0
;
spin_unlock_irq
(
&
dev
->
power
.
lock
);
if
(
dev
->
parent
)
pm_runtime_put
(
dev
->
parent
);
}
}
}
/**
* pm_runtime_remove - Prepare for removing a device from device hierarchy.
* @dev: Device object being removed from device hierarchy.
...
...
@@ -1396,12 +1415,7 @@ void pm_runtime_init(struct device *dev)
void
pm_runtime_remove
(
struct
device
*
dev
)
{
__pm_runtime_disable
(
dev
,
false
);
/* Change the status back to 'suspended' to match the initial status. */
if
(
dev
->
power
.
runtime_status
==
RPM_ACTIVE
)
pm_runtime_set_suspended
(
dev
);
if
(
dev
->
power
.
irq_safe
&&
dev
->
parent
)
pm_runtime_put
(
dev
->
parent
);
pm_runtime_reinit
(
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