From nobody Sun Feb 8 15:25:21 2026 Received: from mail-pl1-f193.google.com (mail-pl1-f193.google.com [209.85.214.193]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 338D02E5437 for ; Mon, 12 Jan 2026 15:15:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.193 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768230950; cv=none; b=cM1ChalXNnh28FQpDjnG/iQfFRYBTg1Ik7KM3Vv1j1ftvRfNRTyvrcaQEHEKFCHB6FS2EtWA5MVwqQfdYiYXat/bs3lu7dncj4IAU3tOAB7fe0jOn358lpJRDrqfX/K7FDRTmGen3OCjbCH6xaA3oAe2oDrKLiBZQtUGUZTNSSU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768230950; c=relaxed/simple; bh=uu/0gx32kQnkFqHlQ6veDyTiR50b8osndfHDDKfyLFA=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=iCbK92PJ5PHhW8TeRhomU/bDQZut4ENaBHyVy9qkQOgqld2w4eodrZj9cFXpVQ7dedh9zd1HW5Vz+UnF3rzeMDSH3KGW/lGyV1+YQcxM7LAc2NIXUiqk6E5UOSiSxuIqn94FQ+v1qtQYBYyPzwshHc+m4hbnTs/c0x2GEBn1EZ4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=J2z48vMq; arc=none smtp.client-ip=209.85.214.193 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="J2z48vMq" Received: by mail-pl1-f193.google.com with SMTP id d9443c01a7336-2a07f8dd9cdso46060865ad.1 for ; Mon, 12 Jan 2026 07:15:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1768230948; x=1768835748; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=GnMqe0D1x/FU87z66s9oq5Es+BDzRArlUSrNXRg5zps=; b=J2z48vMq9jGBBb4ZQqveJjUNvIh+kUTrktuBogKJTXgZoEDU7ty1JexOVXABFVMCCD O6aDE4qpnuqavvJEmTaeoV489thijz7ZAq+J/ltcPzIUy2PyYhi7jK6VDgDm6oYlIj1M e6JCW8+m81shp0qpzLsQqzVXjF4DT8ZkqMaBY3ej2nkcgkS+YLjp9bKO7El8lK6Mz3GM cU2/QJ2U3MvEniXrBm0C+hEpodgQU1hUR/PT9pjGAwyy1Gs56cviXMj82xI0qj/44tBV bU6gKLUt9O+GPiGoCG2bWrOqCKq1ligrTjaWGXHcQ6kl1f/xBvjLodJsuxqIKiEJ95i7 0ICg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768230948; x=1768835748; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=GnMqe0D1x/FU87z66s9oq5Es+BDzRArlUSrNXRg5zps=; b=spjsv9+9vR+S2TGuyLP/3MekcCcSc8QfiofVxV38zvgydCPshtIQo/kwlSONUaozUb g5GqYKXZRRsMjFalQ4CgDpY+WhKUc96rLuWm1CEMAn1HqECxtM28fVh3zJk1l43/6fbE /ZmNf+QkgCLMPsgd+gCQa7PiCiWOPbkroBJYFQVyTkeU9MPjt0iuUCp8t/zQC+t1zN3n FWrq3hHHb2rfmRlXb4c+VreWaZr4wlNuQ28H1KN9IoF0U+ZdmNM+UhWB/ElvBoMhT8Gi cPAlIl5TS0521/Qs9tmv6IDscaAHvJzyeOo3ZZ7E3qYIM3hEG0zyd89o14GdfdVF+HQ/ Izcg== X-Forwarded-Encrypted: i=1; AJvYcCVyETMJ2ghpVAuQnnQfB5gr4QLCCzi+SKpQ1HcvINi5EAi64UelNsGXsOmrYbmHmXMup6Qt40RWEasZSc0=@vger.kernel.org X-Gm-Message-State: AOJu0YydKOC6m5EGyQQBByNxLxvIsbVtpcb8Dk1jX3hk9NOQLTAxU4PT yPKAr5MBsdhPMHx5+cDCqRfrjRAogy8h7utlsTapMg8ArZes9HFj7FDV X-Gm-Gg: AY/fxX52v8N551XOi3z7gP/YuM+U8ISKQCDjm9+hZQsrLjFdH+0GMnXb591vaYrfH4I fyjSESvSvrS4ZtjXmrF6/WmhL0UgO6/M4NEZwNn35vffXXYmbC/O36u41BqLNZQuIe5frP5L3qh heE6nD9sgKZhnv96mGS86edjIJ7aOlQnLzjWRpqF2VnAWxFGYbg0FWpBCJHAq24txfikwWI1xhz DGGp6BnKULGz/ot9a2ZJz4RlGJgLW2pLRa/5lIC8ladN4QG+EH7SCgeH4d+KUYCJYCNa04ANa4a Jmfg2ye8aEeadPn9+g6Ii0+baFtnu9cTkE60+E7DetvCK5WCJY4m5sBI7cxxa2QRxTAyN3AsbAU p/zXfwygGaxdZClez+0Bojd92st1oC2lLCGSgHZfBuuI3D7SDgYyWG5VS/7WTo3CIKeWuVyVSPe yRPdRv8dDuxkP5hG4t9V0+YH6Sg/A6xemo6/E= X-Google-Smtp-Source: AGHT+IGPxmQ1kqM9Y+/PooGdd71tDVNUoILktcyjch+8IqS37vwBrYsliExh1QZEWmEBY6AsgV25IA== X-Received: by 2002:a17:902:c949:b0:2a0:c942:8adf with SMTP id d9443c01a7336-2a3ee40d5a9mr161920895ad.8.1768230948295; Mon, 12 Jan 2026 07:15:48 -0800 (PST) Received: from localhost.localdomain ([38.47.127.59]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3c48d77sm175976905ad.41.2026.01.12.07.15.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jan 2026 07:15:47 -0800 (PST) From: Li XingYang To: "Rafael J . Wysocki" , Len Brown , Pavel Machek Cc: Greg Kroah-Hartman , Danilo Krummrich , linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Li XingYang Subject: [PATCH v0] PM: wakeup: call device resume after superior device complete resume Date: Mon, 12 Jan 2026 23:14:41 +0800 Message-ID: <20260112151441.1860607-1-yanhuoguifan@gmail.com> X-Mailer: git-send-email 2.52.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Background: Extist device A,B and C.A is parent of B,C has no dependency on either A or B.A is an asynchronously resume device, while B and C are synchronously resume devices.dpm_list: A->B->C. When A has not completed asynchronous resume, the main loop will be blocked at B,and C cannot start resume even if it is not associated with either A or B. This will result in a waste of CPU resources in the main loop if A resume need long time. Solution: Place devices that are dependent on others but have not yet completed resume into a waiting queue,and resume subsequent unrelated devices first. After the current list is empty, resume the devices that were skipped before. This approach does not violate the dependencies between devices. Benefits of modification: 1. The synchronous device will not block the main loop by waiting for dependent devices to complete. 2. Asynchronous devices will not start early and waste scheduling resources. Signed-off-by: Li XingYang --- drivers/base/power/main.c | 144 +++++++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 4bec5dd88547..13633b96c1c8 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include =20 #include "../base.h" #include "power.h" @@ -327,6 +329,64 @@ static bool dpm_wait_for_superior(struct device *dev, = bool async) return device_pm_initialized(dev); } =20 +/** + * dpm_finish - Test a PM operation have finished. + * @dev: Device to test. + */ +static bool dpm_finish(struct device *dev) +{ + if (!dev) + return true; + + return completion_done(&dev->power.completion); +} + +/** + * dpm_test_suppliers_finish - test suppliers of the device have finished + * @dev: Device to handle. + */ +static bool dpm_test_suppliers_finish(struct device *dev) +{ + struct device_link *link; + int idx; + + idx =3D device_links_read_lock(); + + dev_for_each_link_to_supplier(link, dev) + if (READ_ONCE(link->status) !=3D DL_STATE_DORMANT && + !device_link_flag_is_sync_state_only(link->flags)) + if (!dpm_finish(link->supplier)) { + device_links_read_unlock(idx); + return false; + } + + device_links_read_unlock(idx); + + return true; +} + +/** + * dpm_test_superior_finish - test superior of the device have finished + * @dev: Device to handle. + */ +static bool dpm_test_superior_finish(struct device *dev) +{ + struct device *parent; + + if (!device_pm_initialized(dev)) + return true; + + parent =3D get_device(dev->parent); + + if (!dpm_finish(parent)) { + put_device(parent); + return false; + } + put_device(parent); + + return dpm_test_suppliers_finish(dev); +} + static void dpm_wait_for_consumers(struct device *dev, bool async) { struct device_link *link; @@ -831,6 +891,8 @@ static void dpm_noirq_resume_devices(pm_message_t state) { struct device *dev; ktime_t starttime =3D ktime_get(); + int resume_num =3D 0; + LIST_HEAD(dpm_noirq_wait_list); =20 trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, true); =20 @@ -849,8 +911,32 @@ static void dpm_noirq_resume_devices(pm_message_t stat= e) dpm_async_with_cleanup(dev, async_resume_noirq); } =20 - while (!list_empty(&dpm_noirq_list)) { + while (!list_empty(&dpm_noirq_list) || !list_empty(&dpm_noirq_wait_list))= { + if (list_empty(&dpm_noirq_list)) { + list_splice_init(&dpm_noirq_wait_list, &dpm_noirq_list); + /* + * sleep 1 millisecond avoid CPU busy loops + */ + if (!resume_num) { + mutex_unlock(&dpm_list_mtx); + fsleep(USEC_PER_MSEC); + mutex_lock(&dpm_list_mtx); + } + resume_num =3D 0; + } + dev =3D to_device(dpm_noirq_list.next); + + /* + * Skip devices that are still pending completion of dependent devices + */ + if (!dev->power.syscore && !dev->power.direct_complete && + dev->power.is_noirq_suspended && !dpm_test_superior_finish(dev)) { + list_move_tail(&dev->power.entry, &dpm_noirq_wait_list); + continue; + } + ++resume_num; + list_move_tail(&dev->power.entry, &dpm_late_early_list); =20 if (!dpm_async_fn(dev, async_resume_noirq)) { @@ -981,6 +1067,8 @@ void dpm_resume_early(pm_message_t state) { struct device *dev; ktime_t starttime =3D ktime_get(); + int resume_num =3D 0; + LIST_HEAD(dpm_late_early_wait_list); =20 trace_suspend_resume(TPS("dpm_resume_early"), state.event, true); =20 @@ -999,8 +1087,32 @@ void dpm_resume_early(pm_message_t state) dpm_async_with_cleanup(dev, async_resume_early); } =20 - while (!list_empty(&dpm_late_early_list)) { + while (!list_empty(&dpm_late_early_list) || !list_empty(&dpm_late_early_w= ait_list)) { + if (list_empty(&dpm_late_early_list)) { + list_splice_init(&dpm_late_early_wait_list, &dpm_late_early_list); + /* + * sleep 1 millisecond avoid CPU busy loops + */ + if (!resume_num) { + mutex_unlock(&dpm_list_mtx); + fsleep(USEC_PER_MSEC); + mutex_lock(&dpm_list_mtx); + } + resume_num =3D 0; + } + dev =3D to_device(dpm_late_early_list.next); + + /* + * Skip devices that are still pending completion of dependent devices + */ + if (!dev->power.syscore && !dev->power.direct_complete && + dev->power.is_late_suspended && !dpm_test_superior_finish(dev)) { + list_move_tail(&dev->power.entry, &dpm_late_early_wait_list); + continue; + } + ++resume_num; + list_move_tail(&dev->power.entry, &dpm_suspended_list); =20 if (!dpm_async_fn(dev, async_resume_early)) { @@ -1160,6 +1272,8 @@ void dpm_resume(pm_message_t state) { struct device *dev; ktime_t starttime =3D ktime_get(); + int resume_num =3D 0; + LIST_HEAD(dpm_suspended_wait_list); =20 trace_suspend_resume(TPS("dpm_resume"), state.event, true); =20 @@ -1178,8 +1292,32 @@ void dpm_resume(pm_message_t state) dpm_async_with_cleanup(dev, async_resume); } =20 - while (!list_empty(&dpm_suspended_list)) { + while (!list_empty(&dpm_suspended_list) || !list_empty(&dpm_suspended_wai= t_list)) { + if (list_empty(&dpm_suspended_list)) { + list_splice_init(&dpm_suspended_wait_list, &dpm_suspended_list); + /* + * sleep 1 millisecond avoid CPU busy loops + */ + if (!resume_num) { + mutex_unlock(&dpm_list_mtx); + fsleep(USEC_PER_MSEC); + mutex_lock(&dpm_list_mtx); + } + resume_num =3D 0; + } + dev =3D to_device(dpm_suspended_list.next); + + /* + * Skip devices that are still pending completion of dependent devices + */ + if (!dev->power.syscore && !dev->power.direct_complete && + dev->power.is_suspended && !dpm_test_superior_finish(dev)) { + list_move_tail(&dev->power.entry, &dpm_suspended_wait_list); + continue; + } + ++resume_num; + list_move_tail(&dev->power.entry, &dpm_prepared_list); =20 if (!dpm_async_fn(dev, async_resume)) { --=20 2.52.0