Takashi Iwai c29a99
From e554c13dbe3caaa25558a845816baec77d03da7c Mon Sep 17 00:00:00 2001
Takashi Iwai c29a99
From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Takashi Iwai c29a99
Date: Thu, 4 Nov 2021 18:26:26 +0100
Takashi Iwai c29a99
Subject: [PATCH] PM: sleep: Avoid calling put_device() under dpm_list_mtx
Takashi Iwai c29a99
Git-commit: 2aa36604e8243698ff22bd5fef0dd0c6bb07ba92
Takashi Iwai c29a99
Patch-mainline: v5.16-rc1
Takashi Iwai c29a99
References: stable-5.14.19
Takashi Iwai c29a99
Takashi Iwai c29a99
commit 2aa36604e8243698ff22bd5fef0dd0c6bb07ba92 upstream.
Takashi Iwai c29a99
Takashi Iwai c29a99
It is generally unsafe to call put_device() with dpm_list_mtx held,
Takashi Iwai c29a99
because the given device's release routine may carry out an action
Takashi Iwai c29a99
depending on that lock which then may deadlock, so modify the
Takashi Iwai c29a99
system-wide suspend and resume of devices to always drop dpm_list_mtx
Takashi Iwai c29a99
before calling put_device() (and adjust white space somewhat while
Takashi Iwai c29a99
at it).
Takashi Iwai c29a99
Takashi Iwai c29a99
For instance, this prevents the following splat from showing up in
Takashi Iwai c29a99
the kernel log after a system resume in certain configurations:
Takashi Iwai c29a99
Takashi Iwai c29a99
[ 3290.969514] ======================================================
Takashi Iwai c29a99
[ 3290.969517] WARNING: possible circular locking dependency detected
Takashi Iwai c29a99
[ 3290.969519] 5.15.0+ #2420 Tainted: G S
Takashi Iwai c29a99
[ 3290.969523] ------------------------------------------------------
Takashi Iwai c29a99
[ 3290.969525] systemd-sleep/4553 is trying to acquire lock:
Takashi Iwai c29a99
[ 3290.969529] ffff888117ab1138 ((wq_completion)hci0#2){+.+.}-{0:0}, at: flush_workqueue+0x87/0x4a0
Takashi Iwai c29a99
[ 3290.969554]
Takashi Iwai c29a99
               but task is already holding lock:
Takashi Iwai c29a99
[ 3290.969556] ffffffff8280fca8 (dpm_list_mtx){+.+.}-{3:3}, at: dpm_resume+0x12e/0x3e0
Takashi Iwai c29a99
[ 3290.969571]
Takashi Iwai c29a99
               which lock already depends on the new lock.
Takashi Iwai c29a99
Takashi Iwai c29a99
[ 3290.969573]
Takashi Iwai c29a99
               the existing dependency chain (in reverse order) is:
Takashi Iwai c29a99
[ 3290.969575]
Takashi Iwai c29a99
               -> #3 (dpm_list_mtx){+.+.}-{3:3}:
Takashi Iwai c29a99
[ 3290.969583]        __mutex_lock+0x9d/0xa30
Takashi Iwai c29a99
[ 3290.969591]        device_pm_add+0x2e/0xe0
Takashi Iwai c29a99
[ 3290.969597]        device_add+0x4d5/0x8f0
Takashi Iwai c29a99
[ 3290.969605]        hci_conn_add_sysfs+0x43/0xb0 [bluetooth]
Takashi Iwai c29a99
[ 3290.969689]        hci_conn_complete_evt.isra.71+0x124/0x750 [bluetooth]
Takashi Iwai c29a99
[ 3290.969747]        hci_event_packet+0xd6c/0x28a0 [bluetooth]
Takashi Iwai c29a99
[ 3290.969798]        hci_rx_work+0x213/0x640 [bluetooth]
Takashi Iwai c29a99
[ 3290.969842]        process_one_work+0x2aa/0x650
Takashi Iwai c29a99
[ 3290.969851]        worker_thread+0x39/0x400
Takashi Iwai c29a99
[ 3290.969859]        kthread+0x142/0x170
Takashi Iwai c29a99
[ 3290.969865]        ret_from_fork+0x22/0x30
Takashi Iwai c29a99
[ 3290.969872]
Takashi Iwai c29a99
               -> #2 (&hdev->lock){+.+.}-{3:3}:
Takashi Iwai c29a99
[ 3290.969881]        __mutex_lock+0x9d/0xa30
Takashi Iwai c29a99
[ 3290.969887]        hci_event_packet+0xba/0x28a0 [bluetooth]
Takashi Iwai c29a99
[ 3290.969935]        hci_rx_work+0x213/0x640 [bluetooth]
Takashi Iwai c29a99
[ 3290.969978]        process_one_work+0x2aa/0x650
Takashi Iwai c29a99
[ 3290.969985]        worker_thread+0x39/0x400
Takashi Iwai c29a99
[ 3290.969993]        kthread+0x142/0x170
Takashi Iwai c29a99
[ 3290.969999]        ret_from_fork+0x22/0x30
Takashi Iwai c29a99
[ 3290.970004]
Takashi Iwai c29a99
               -> #1 ((work_completion)(&hdev->rx_work)){+.+.}-{0:0}:
Takashi Iwai c29a99
[ 3290.970013]        process_one_work+0x27d/0x650
Takashi Iwai c29a99
[ 3290.970020]        worker_thread+0x39/0x400
Takashi Iwai c29a99
[ 3290.970028]        kthread+0x142/0x170
Takashi Iwai c29a99
[ 3290.970033]        ret_from_fork+0x22/0x30
Takashi Iwai c29a99
[ 3290.970038]
Takashi Iwai c29a99
               -> #0 ((wq_completion)hci0#2){+.+.}-{0:0}:
Takashi Iwai c29a99
[ 3290.970047]        __lock_acquire+0x15cb/0x1b50
Takashi Iwai c29a99
[ 3290.970054]        lock_acquire+0x26c/0x300
Takashi Iwai c29a99
[ 3290.970059]        flush_workqueue+0xae/0x4a0
Takashi Iwai c29a99
[ 3290.970066]        drain_workqueue+0xa1/0x130
Takashi Iwai c29a99
[ 3290.970073]        destroy_workqueue+0x34/0x1f0
Takashi Iwai c29a99
[ 3290.970081]        hci_release_dev+0x49/0x180 [bluetooth]
Takashi Iwai c29a99
[ 3290.970130]        bt_host_release+0x1d/0x30 [bluetooth]
Takashi Iwai c29a99
[ 3290.970195]        device_release+0x33/0x90
Takashi Iwai c29a99
[ 3290.970201]        kobject_release+0x63/0x160
Takashi Iwai c29a99
[ 3290.970211]        dpm_resume+0x164/0x3e0
Takashi Iwai c29a99
[ 3290.970215]        dpm_resume_end+0xd/0x20
Takashi Iwai c29a99
[ 3290.970220]        suspend_devices_and_enter+0x1a4/0xba0
Takashi Iwai c29a99
[ 3290.970229]        pm_suspend+0x26b/0x310
Takashi Iwai c29a99
[ 3290.970236]        state_store+0x42/0x90
Takashi Iwai c29a99
[ 3290.970243]        kernfs_fop_write_iter+0x135/0x1b0
Takashi Iwai c29a99
[ 3290.970251]        new_sync_write+0x125/0x1c0
Takashi Iwai c29a99
[ 3290.970257]        vfs_write+0x360/0x3c0
Takashi Iwai c29a99
[ 3290.970263]        ksys_write+0xa7/0xe0
Takashi Iwai c29a99
[ 3290.970269]        do_syscall_64+0x3a/0x80
Takashi Iwai c29a99
[ 3290.970276]        entry_SYSCALL_64_after_hwframe+0x44/0xae
Takashi Iwai c29a99
[ 3290.970284]
Takashi Iwai c29a99
               other info that might help us debug this:
Takashi Iwai c29a99
Takashi Iwai c29a99
[ 3290.970285] Chain exists of:
Takashi Iwai c29a99
                 (wq_completion)hci0#2 --> &hdev->lock --> dpm_list_mtx
Takashi Iwai c29a99
Takashi Iwai c29a99
[ 3290.970297]  Possible unsafe locking scenario:
Takashi Iwai c29a99
Takashi Iwai c29a99
[ 3290.970299]        CPU0                    CPU1
Takashi Iwai c29a99
[ 3290.970300]        ----                    ----
Takashi Iwai c29a99
[ 3290.970302]   lock(dpm_list_mtx);
Takashi Iwai c29a99
[ 3290.970306]                                lock(&hdev->lock);
Takashi Iwai c29a99
[ 3290.970310]                                lock(dpm_list_mtx);
Takashi Iwai c29a99
[ 3290.970314]   lock((wq_completion)hci0#2);
Takashi Iwai c29a99
[ 3290.970319]
Takashi Iwai c29a99
                *** DEADLOCK ***
Takashi Iwai c29a99
Takashi Iwai c29a99
[ 3290.970321] 7 locks held by systemd-sleep/4553:
Takashi Iwai c29a99
[ 3290.970325]  #0: ffff888103bcd448 (sb_writers#4){.+.+}-{0:0}, at: ksys_write+0xa7/0xe0
Takashi Iwai c29a99
[ 3290.970341]  #1: ffff888115a14488 (&of->mutex){+.+.}-{3:3}, at: kernfs_fop_write_iter+0x103/0x1b0
Takashi Iwai c29a99
[ 3290.970355]  #2: ffff888100f719e0 (kn->active#233){.+.+}-{0:0}, at: kernfs_fop_write_iter+0x10c/0x1b0
Takashi Iwai c29a99
[ 3290.970369]  #3: ffffffff82661048 (autosleep_lock){+.+.}-{3:3}, at: state_store+0x12/0x90
Takashi Iwai c29a99
[ 3290.970384]  #4: ffffffff82658ac8 (system_transition_mutex){+.+.}-{3:3}, at: pm_suspend+0x9f/0x310
Takashi Iwai c29a99
[ 3290.970399]  #5: ffffffff827f2a48 (acpi_scan_lock){+.+.}-{3:3}, at: acpi_suspend_begin+0x4c/0x80
Takashi Iwai c29a99
[ 3290.970416]  #6: ffffffff8280fca8 (dpm_list_mtx){+.+.}-{3:3}, at: dpm_resume+0x12e/0x3e0
Takashi Iwai c29a99
[ 3290.970428]
Takashi Iwai c29a99
               stack backtrace:
Takashi Iwai c29a99
[ 3290.970431] CPU: 3 PID: 4553 Comm: systemd-sleep Tainted: G S                5.15.0+ #2420
Takashi Iwai c29a99
[ 3290.970438] Hardware name: Dell Inc. XPS 13 9380/0RYJWW, BIOS 1.5.0 06/03/2019
Takashi Iwai c29a99
[ 3290.970441] Call Trace:
Takashi Iwai c29a99
[ 3290.970446]  dump_stack_lvl+0x44/0x57
Takashi Iwai c29a99
[ 3290.970454]  check_noncircular+0x105/0x120
Takashi Iwai c29a99
[ 3290.970468]  ? __lock_acquire+0x15cb/0x1b50
Takashi Iwai c29a99
[ 3290.970474]  __lock_acquire+0x15cb/0x1b50
Takashi Iwai c29a99
[ 3290.970487]  lock_acquire+0x26c/0x300
Takashi Iwai c29a99
[ 3290.970493]  ? flush_workqueue+0x87/0x4a0
Takashi Iwai c29a99
[ 3290.970503]  ? __raw_spin_lock_init+0x3b/0x60
Takashi Iwai c29a99
[ 3290.970510]  ? lockdep_init_map_type+0x58/0x240
Takashi Iwai c29a99
[ 3290.970519]  flush_workqueue+0xae/0x4a0
Takashi Iwai c29a99
[ 3290.970526]  ? flush_workqueue+0x87/0x4a0
Takashi Iwai c29a99
[ 3290.970544]  ? drain_workqueue+0xa1/0x130
Takashi Iwai c29a99
[ 3290.970552]  drain_workqueue+0xa1/0x130
Takashi Iwai c29a99
[ 3290.970561]  destroy_workqueue+0x34/0x1f0
Takashi Iwai c29a99
[ 3290.970572]  hci_release_dev+0x49/0x180 [bluetooth]
Takashi Iwai c29a99
[ 3290.970624]  bt_host_release+0x1d/0x30 [bluetooth]
Takashi Iwai c29a99
[ 3290.970687]  device_release+0x33/0x90
Takashi Iwai c29a99
[ 3290.970695]  kobject_release+0x63/0x160
Takashi Iwai c29a99
[ 3290.970705]  dpm_resume+0x164/0x3e0
Takashi Iwai c29a99
[ 3290.970710]  ? dpm_resume_early+0x251/0x3b0
Takashi Iwai c29a99
[ 3290.970718]  dpm_resume_end+0xd/0x20
Takashi Iwai c29a99
[ 3290.970723]  suspend_devices_and_enter+0x1a4/0xba0
Takashi Iwai c29a99
[ 3290.970737]  pm_suspend+0x26b/0x310
Takashi Iwai c29a99
[ 3290.970746]  state_store+0x42/0x90
Takashi Iwai c29a99
[ 3290.970755]  kernfs_fop_write_iter+0x135/0x1b0
Takashi Iwai c29a99
[ 3290.970764]  new_sync_write+0x125/0x1c0
Takashi Iwai c29a99
[ 3290.970777]  vfs_write+0x360/0x3c0
Takashi Iwai c29a99
[ 3290.970785]  ksys_write+0xa7/0xe0
Takashi Iwai c29a99
[ 3290.970794]  do_syscall_64+0x3a/0x80
Takashi Iwai c29a99
[ 3290.970803]  entry_SYSCALL_64_after_hwframe+0x44/0xae
Takashi Iwai c29a99
[ 3290.970811] RIP: 0033:0x7f41b1328164
Takashi Iwai c29a99
[ 3290.970819] Code: 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 80 00 00 00 00 8b 05 4a d2 2c 00 48 63 ff 85 c0 75 13 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 f3 c3 66 90 55 53 48 89 d5 48 89 f3 48 83
Takashi Iwai c29a99
[ 3290.970824] RSP: 002b:00007ffe6ae21b28 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
Takashi Iwai c29a99
[ 3290.970831] RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f41b1328164
Takashi Iwai c29a99
[ 3290.970836] RDX: 0000000000000004 RSI: 000055965e651070 RDI: 0000000000000004
Takashi Iwai c29a99
[ 3290.970839] RBP: 000055965e651070 R08: 000055965e64f390 R09: 00007f41b1e3d1c0
Takashi Iwai c29a99
[ 3290.970843] R10: 000000000000000a R11: 0000000000000246 R12: 0000000000000004
Takashi Iwai c29a99
[ 3290.970846] R13: 0000000000000001 R14: 000055965e64f2b0 R15: 0000000000000004
Takashi Iwai c29a99
Takashi Iwai c29a99
Cc: All applicable <stable@vger.kernel.org>
Takashi Iwai c29a99
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Takashi Iwai c29a99
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Takashi Iwai c29a99
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai c29a99
Takashi Iwai c29a99
---
Takashi Iwai c29a99
 drivers/base/power/main.c | 84 ++++++++++++++++++++++++++-------------
Takashi Iwai c29a99
 1 file changed, 57 insertions(+), 27 deletions(-)
Takashi Iwai c29a99
Takashi Iwai c29a99
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
Takashi Iwai c29a99
index fca6eab871fc..a7fdd86fad05 100644
Takashi Iwai c29a99
--- a/drivers/base/power/main.c
Takashi Iwai c29a99
+++ b/drivers/base/power/main.c
Takashi Iwai c29a99
@@ -711,6 +711,7 @@ static void dpm_noirq_resume_devices(pm_message_t state)
Takashi Iwai c29a99
 		dev = to_device(dpm_noirq_list.next);
Takashi Iwai c29a99
 		get_device(dev);
Takashi Iwai c29a99
 		list_move_tail(&dev->power.entry, &dpm_late_early_list);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		if (!is_async(dev)) {
Takashi Iwai c29a99
@@ -725,8 +726,9 @@ static void dpm_noirq_resume_devices(pm_message_t state)
Takashi Iwai c29a99
 			}
Takashi Iwai c29a99
 		}
Takashi Iwai c29a99
 
Takashi Iwai c29a99
-		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 	async_synchronize_full();
Takashi Iwai c29a99
@@ -852,6 +854,7 @@ void dpm_resume_early(pm_message_t state)
Takashi Iwai c29a99
 		dev = to_device(dpm_late_early_list.next);
Takashi Iwai c29a99
 		get_device(dev);
Takashi Iwai c29a99
 		list_move_tail(&dev->power.entry, &dpm_suspended_list);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		if (!is_async(dev)) {
Takashi Iwai c29a99
@@ -865,8 +868,10 @@ void dpm_resume_early(pm_message_t state)
Takashi Iwai c29a99
 				pm_dev_err(dev, state, " early", error);
Takashi Iwai c29a99
 			}
Takashi Iwai c29a99
 		}
Takashi Iwai c29a99
-		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 	async_synchronize_full();
Takashi Iwai c29a99
@@ -1029,7 +1034,12 @@ void dpm_resume(pm_message_t state)
Takashi Iwai c29a99
 		}
Takashi Iwai c29a99
 		if (!list_empty(&dev->power.entry))
Takashi Iwai c29a99
 			list_move_tail(&dev->power.entry, &dpm_prepared_list);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 	async_synchronize_full();
Takashi Iwai c29a99
@@ -1107,14 +1117,16 @@ void dpm_complete(pm_message_t state)
Takashi Iwai c29a99
 		get_device(dev);
Takashi Iwai c29a99
 		dev->power.is_prepared = false;
Takashi Iwai c29a99
 		list_move(&dev->power.entry, &list);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		trace_device_pm_callback_start(dev, "", state.event);
Takashi Iwai c29a99
 		device_complete(dev, state);
Takashi Iwai c29a99
 		trace_device_pm_callback_end(dev, 0);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
-		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	list_splice(&list, &dpm_list);
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
@@ -1299,17 +1311,21 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
Takashi Iwai c29a99
 		error = device_suspend_noirq(dev);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		if (error) {
Takashi Iwai c29a99
 			pm_dev_err(dev, state, " noirq", error);
Takashi Iwai c29a99
 			dpm_save_failed_dev(dev_name(dev));
Takashi Iwai c29a99
-			put_device(dev);
Takashi Iwai c29a99
-			break;
Takashi Iwai c29a99
-		}
Takashi Iwai c29a99
-		if (!list_empty(&dev->power.entry))
Takashi Iwai c29a99
+		} else if (!list_empty(&dev->power.entry)) {
Takashi Iwai c29a99
 			list_move(&dev->power.entry, &dpm_noirq_list);
Takashi Iwai c29a99
+		}
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
-		if (async_error)
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		if (error || async_error)
Takashi Iwai c29a99
 			break;
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
@@ -1476,23 +1492,28 @@ int dpm_suspend_late(pm_message_t state)
Takashi Iwai c29a99
 		struct device *dev = to_device(dpm_suspended_list.prev);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		get_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		error = device_suspend_late(dev);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		if (!list_empty(&dev->power.entry))
Takashi Iwai c29a99
 			list_move(&dev->power.entry, &dpm_late_early_list);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		if (error) {
Takashi Iwai c29a99
 			pm_dev_err(dev, state, " late", error);
Takashi Iwai c29a99
 			dpm_save_failed_dev(dev_name(dev));
Takashi Iwai c29a99
-			put_device(dev);
Takashi Iwai c29a99
-			break;
Takashi Iwai c29a99
 		}
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
-		if (async_error)
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		if (error || async_error)
Takashi Iwai c29a99
 			break;
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
@@ -1752,21 +1773,27 @@ int dpm_suspend(pm_message_t state)
Takashi Iwai c29a99
 		struct device *dev = to_device(dpm_prepared_list.prev);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		get_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		error = device_suspend(dev);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		if (error) {
Takashi Iwai c29a99
 			pm_dev_err(dev, state, "", error);
Takashi Iwai c29a99
 			dpm_save_failed_dev(dev_name(dev));
Takashi Iwai c29a99
-			put_device(dev);
Takashi Iwai c29a99
-			break;
Takashi Iwai c29a99
-		}
Takashi Iwai c29a99
-		if (!list_empty(&dev->power.entry))
Takashi Iwai c29a99
+		} else if (!list_empty(&dev->power.entry)) {
Takashi Iwai c29a99
 			list_move(&dev->power.entry, &dpm_suspended_list);
Takashi Iwai c29a99
+		}
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
-		if (async_error)
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		if (error || async_error)
Takashi Iwai c29a99
 			break;
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
@@ -1883,6 +1910,7 @@ int dpm_prepare(pm_message_t state)
Takashi Iwai c29a99
 		struct device *dev = to_device(dpm_list.next);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		get_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		trace_device_pm_callback_start(dev, "", state.event);
Takashi Iwai c29a99
@@ -1890,21 +1918,23 @@ int dpm_prepare(pm_message_t state)
Takashi Iwai c29a99
 		trace_device_pm_callback_end(dev, error);
Takashi Iwai c29a99
 
Takashi Iwai c29a99
 		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
-		if (error) {
Takashi Iwai c29a99
-			if (error == -EAGAIN) {
Takashi Iwai c29a99
-				put_device(dev);
Takashi Iwai c29a99
-				error = 0;
Takashi Iwai c29a99
-				continue;
Takashi Iwai c29a99
-			}
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		if (!error) {
Takashi Iwai c29a99
+			dev->power.is_prepared = true;
Takashi Iwai c29a99
+			if (!list_empty(&dev->power.entry))
Takashi Iwai c29a99
+				list_move_tail(&dev->power.entry, &dpm_prepared_list);
Takashi Iwai c29a99
+		} else if (error == -EAGAIN) {
Takashi Iwai c29a99
+			error = 0;
Takashi Iwai c29a99
+		} else {
Takashi Iwai c29a99
 			dev_info(dev, "not prepared for power transition: code %d\n",
Takashi Iwai c29a99
 				 error);
Takashi Iwai c29a99
-			put_device(dev);
Takashi Iwai c29a99
-			break;
Takashi Iwai c29a99
 		}
Takashi Iwai c29a99
-		dev->power.is_prepared = true;
Takashi Iwai c29a99
-		if (!list_empty(&dev->power.entry))
Takashi Iwai c29a99
-			list_move_tail(&dev->power.entry, &dpm_prepared_list);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
 		put_device(dev);
Takashi Iwai c29a99
+
Takashi Iwai c29a99
+		mutex_lock(&dpm_list_mtx);
Takashi Iwai c29a99
 	}
Takashi Iwai c29a99
 	mutex_unlock(&dpm_list_mtx);
Takashi Iwai c29a99
 	trace_suspend_resume(TPS("dpm_prepare"), state.event, false);
Takashi Iwai c29a99
-- 
Takashi Iwai c29a99
2.26.2
Takashi Iwai c29a99