lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240223143833.1509961-1-guanyulin@google.com>
Date: Fri, 23 Feb 2024 14:38:29 +0000
From: Guan-Yu Lin <guanyulin@...gle.com>
To: rafael@...nel.org, pavel@....cz, len.brown@...el.com, 
	gregkh@...uxfoundation.org, andriy.shevchenko@...ux.intel.com, 
	petr.tesarik.ext@...wei.com, rdunlap@...radead.org, james@...iv.tech, 
	broonie@...nel.org, james.clark@....com, masahiroy@...nel.org
Cc: linux-kernel@...r.kernel.org, linux-pm@...r.kernel.org, 
	Guan-Yu Lin <guanyulin@...gle.com>
Subject: [PATCH v3] PM / core: conditionally skip system pm in device/driver model

In systems with a main processor and a co-processor, asynchronous
controller management can lead to conflicts.  One example is the main
processor attempting to suspend a device while the co-processor is
actively using it. To address this, we introduce a new sysfs entry
called "conditional_skip". This entry allows the system to selectively
skip certain device power management state transitions. To use this
feature, set the value in "conditional_skip" to indicate the type of
state transition you want to avoid.  Please review /Documentation/ABI/
testing/sysfs-devices-power for more detailed information.

Signed-off-by: Guan-Yu Lin <guanyulin@...gle.com>
---
V2 -> V3: Integrate the feature with the pm core framework.
V1 -> V2: Cosmetics changes on coding style.
[v2] usb: host: enable suspend-to-RAM control in userspace
[v1] [RFC] usb: host: Allow userspace to control usb suspend flows
---
 Documentation/ABI/testing/sysfs-devices-power | 11 ++++++++
 drivers/base/power/main.c                     | 16 ++++++++++++
 drivers/base/power/sysfs.c                    | 26 +++++++++++++++++++
 include/linux/device.h                        |  7 +++++
 include/linux/pm.h                            |  1 +
 5 files changed, 61 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index 54195530e97a..3ac4e40f07a0 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -305,3 +305,14 @@ Description:
 		Reports the runtime PM children usage count of a device, or
 		0 if the children will be ignored.
 
+What:		/sys/devices/.../power/conditional_skip
+Date:		Feburary 2024
+Contact:	Guan-Yu Lin <guanyulin@...gle.com>
+Description:
+		The /sys/devices/.../conditional_skip attribute provides a way
+		to selectively skip system-wide power transitions like
+		suspend-to-RAM or hibernation. To skip a specific transition,
+		write its corresponding value to this attribute. For skipping
+		multiple transitions, combine their values using a bitwise OR
+		and write the result to this attribute.
+
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index fadcd0379dc2..d507626c7892 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1881,6 +1881,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
  */
 int dpm_prepare(pm_message_t state)
 {
+	struct list_head list;
 	int error = 0;
 
 	trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
@@ -1900,12 +1901,26 @@ int dpm_prepare(pm_message_t state)
 	 */
 	device_block_probing();
 
+	INIT_LIST_HEAD(&list);
 	mutex_lock(&dpm_list_mtx);
 	while (!list_empty(&dpm_list) && !error) {
 		struct device *dev = to_device(dpm_list.next);
 
 		get_device(dev);
 
+		if (dev->power.conditional_skip_pm & state.event) {
+			dev_info(dev, "skip system PM transition (event = 0x%04x)\n",
+				 state.event);
+
+			if (!list_empty(&dev->power.entry))
+				list_move_tail(&dev->power.entry, &list);
+
+			mutex_unlock(&dpm_list_mtx);
+			put_device(dev);
+			mutex_lock(&dpm_list_mtx);
+			continue;
+		}
+
 		mutex_unlock(&dpm_list_mtx);
 
 		trace_device_pm_callback_start(dev, "", state.event);
@@ -1931,6 +1946,7 @@ int dpm_prepare(pm_message_t state)
 
 		mutex_lock(&dpm_list_mtx);
 	}
+	list_splice(&list, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
 	trace_suspend_resume(TPS("dpm_prepare"), state.event, false);
 	return error;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a1474fb67db9..1feacb01b1e9 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -610,6 +610,31 @@ static DEVICE_ATTR_RW(async);
 #endif /* CONFIG_PM_SLEEP */
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 
+static ssize_t conditional_skip_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	return sysfs_emit(buf, "0x%04x\n", dev->power.conditional_skip_pm);
+}
+
+static ssize_t conditional_skip_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t n)
+{
+	int ret;
+
+	if (kstrtoint(buf, 0, &ret))
+		return -EINVAL;
+
+	ret &= (PM_EVENT_FREEZE|PM_EVENT_SUSPEND|PM_EVENT_HIBERNATE);
+
+	dev->power.conditional_skip_pm = ret;
+
+	return n;
+}
+
+static DEVICE_ATTR_RW(conditional_skip);
+
 static struct attribute *power_attrs[] = {
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 #ifdef CONFIG_PM_SLEEP
@@ -620,6 +645,7 @@ static struct attribute *power_attrs[] = {
 	&dev_attr_runtime_active_kids.attr,
 	&dev_attr_runtime_enabled.attr,
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
+	&dev_attr_conditional_skip.attr,
 	NULL,
 };
 static const struct attribute_group pm_attr_group = {
diff --git a/include/linux/device.h b/include/linux/device.h
index 97c4b046c09d..f2c73dd00211 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -968,6 +968,13 @@ static inline void device_set_pm_not_required(struct device *dev)
 	dev->power.no_pm = true;
 }
 
+static inline void device_set_pm_conditional_skip(struct device *dev,
+						  int condition)
+{
+	condition &= (PM_EVENT_FREEZE|PM_EVENT_SUSPEND|PM_EVENT_HIBERNATE);
+	dev->power.conditional_skip_pm = condition;
+}
+
 static inline void dev_pm_syscore_device(struct device *dev, bool val)
 {
 #ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/pm.h b/include/linux/pm.h
index a2f3e53a8196..890c7a601c2a 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -713,6 +713,7 @@ struct dev_pm_info {
 	enum rpm_status		last_status;
 	int			runtime_error;
 	int			autosuspend_delay;
+	int			conditional_skip_pm;
 	u64			last_busy;
 	u64			active_time;
 	u64			suspended_time;
-- 
2.44.0.rc0.258.g7320e95886-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ