提交 d08a5ace 编写于 作者: R Rafael J. Wysocki

PM: Allow devices to be removed during late suspend and early resume

Holding dpm_list_mtx across late suspend and early resume of devices
is problematic for the PCMCIA subsystem and doesn't allow device
objects to be removed by late suspend and early resume driver
callbacks.  This appears to be overly restrictive, as drivers are
generally allowed to remove device objects in other phases of suspend
and resume.  Therefore rework dpm_{suspend|resume}_noirq() so that
they don't have to hold dpm_list_mtx all the time.
Signed-off-by: NRafael J. Wysocki <rjw@sisk.pl>
上级 f6614b7b
...@@ -475,20 +475,33 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) ...@@ -475,20 +475,33 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
*/ */
void dpm_resume_noirq(pm_message_t state) void dpm_resume_noirq(pm_message_t state)
{ {
struct device *dev; struct list_head list;
ktime_t starttime = ktime_get(); ktime_t starttime = ktime_get();
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx); mutex_lock(&dpm_list_mtx);
transition_started = false; transition_started = false;
list_for_each_entry(dev, &dpm_list, power.entry) while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
get_device(dev);
if (dev->power.status > DPM_OFF) { if (dev->power.status > DPM_OFF) {
int error; int error;
dev->power.status = DPM_OFF; dev->power.status = DPM_OFF;
mutex_unlock(&dpm_list_mtx);
error = device_resume_noirq(dev, state); error = device_resume_noirq(dev, state);
mutex_lock(&dpm_list_mtx);
if (error) if (error)
pm_dev_err(dev, state, " early", error); pm_dev_err(dev, state, " early", error);
} }
if (!list_empty(&dev->power.entry))
list_move_tail(&dev->power.entry, &list);
put_device(dev);
}
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx); mutex_unlock(&dpm_list_mtx);
dpm_show_time(starttime, state, "early"); dpm_show_time(starttime, state, "early");
resume_device_irqs(); resume_device_irqs();
...@@ -789,20 +802,33 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) ...@@ -789,20 +802,33 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
*/ */
int dpm_suspend_noirq(pm_message_t state) int dpm_suspend_noirq(pm_message_t state)
{ {
struct device *dev; struct list_head list;
ktime_t starttime = ktime_get(); ktime_t starttime = ktime_get();
int error = 0; int error = 0;
INIT_LIST_HEAD(&list);
suspend_device_irqs(); suspend_device_irqs();
mutex_lock(&dpm_list_mtx); mutex_lock(&dpm_list_mtx);
list_for_each_entry_reverse(dev, &dpm_list, power.entry) { while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
error = device_suspend_noirq(dev, state); error = device_suspend_noirq(dev, state);
mutex_lock(&dpm_list_mtx);
if (error) { if (error) {
pm_dev_err(dev, state, " late", error); pm_dev_err(dev, state, " late", error);
put_device(dev);
break; break;
} }
dev->power.status = DPM_OFF_IRQ; dev->power.status = DPM_OFF_IRQ;
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &list);
put_device(dev);
} }
list_splice_tail(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx); mutex_unlock(&dpm_list_mtx);
if (error) if (error)
dpm_resume_noirq(resume_event(state)); dpm_resume_noirq(resume_event(state));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册