diff mbox series

[RFC,3/3] ACPI: scan: add a request_offline_recursive attribute

Message ID 20200327112247.17691-4-clin@suse.com
State New
Headers show
Series None | expand

Commit Message

Chester Lin March 27, 2020, 11:22 a.m. UTC
Add a request_offline_recursive attribute for userland to change
request_offline settings of the target and its child nodes at once.

Signed-off-by: Chester Lin <clin@suse.com>
---
 Documentation/ABI/testing/sysfs-bus-acpi |  7 +++++
 drivers/acpi/device_sysfs.c              | 33 ++++++++++++++++++++++++
 drivers/acpi/internal.h                  |  2 +-
 drivers/acpi/scan.c                      | 24 +++++++++++++++++
 4 files changed, 65 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-bus-acpi b/Documentation/ABI/testing/sysfs-bus-acpi
index be00749f00e6..eb2fd9752b66 100644
--- a/Documentation/ABI/testing/sysfs-bus-acpi
+++ b/Documentation/ABI/testing/sysfs-bus-acpi
@@ -110,6 +110,13 @@  Description:
 		provides flexibility while some applications could need more
 		time to release resources.
 
+What:		/sys/bus/acpi/devices/.../request_offline_recursive
+Date:		Mar, 2020
+Contact:	Chester Lin <clin@suse.com>
+Description:
+		(RW) Same as request_offline but the writing will also apply
+		to all child ndoes under the target.
+
 What:		/sys/bus/acpi/devices/.../cancel_eject
 Date:		Mar, 2020
 Contact:	Chester Lin <clin@suse.com>
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index e40daafa3f85..d4fdb6846c78 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -537,6 +537,32 @@  static ssize_t request_offline_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(request_offline);
 
+static ssize_t request_offline_recursive_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	bool value;
+
+	if (!count)
+		return -EINVAL;
+
+	switch (buf[0]) {
+	case '0':
+		value = false;
+		break;
+	case '1':
+		value = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	acpi_request_offline_recursive(acpi_dev, value);
+
+	return count;
+}
+static DEVICE_ATTR_WO(request_offline_recursive);
+
 static ssize_t auto_eject_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -685,6 +711,11 @@  int acpi_device_setup_files(struct acpi_device *dev)
 		if (result)
 			return result;
 
+		result = device_create_file(&dev->dev,
+					&dev_attr_request_offline_recursive);
+		if (result)
+			return result;
+
 		result = device_create_file(&dev->dev,
 					    &dev_attr_auto_eject);
 		if (result)
@@ -741,6 +772,8 @@  void acpi_device_remove_files(struct acpi_device *dev)
 	if (acpi_has_method(dev->handle, "_EJ0")) {
 		device_remove_file(&dev->dev, &dev_attr_eject);
 		device_remove_file(&dev->dev, &dev_attr_request_offline);
+		device_remove_file(&dev->dev,
+				   &dev_attr_request_offline_recursive);
 		device_remove_file(&dev->dev, &dev_attr_auto_eject);
 		device_remove_file(&dev->dev, &dev_attr_cancel_eject);
 	}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 45f4ce42a044..3a2f66eac639 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -89,7 +89,7 @@  bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
 
 acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context);
 void acpi_scan_table_handler(u32 event, void *table, void *context);
-
+void acpi_request_offline_recursive(struct acpi_device *device, bool value);
 /* --------------------------------------------------------------------------
                      Device Node Initialization / Removal
    -------------------------------------------------------------------------- */
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index b4678ed14eed..db6f0551ca94 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -269,6 +269,30 @@  static int acpi_scan_try_to_offline(struct acpi_device *device)
 	return 0;
 }
 
+static acpi_status acpi_bus_request_offline(acpi_handle handle, u32 lvl,
+					    void *data, void **ret_p)
+{
+	struct acpi_device *device = NULL;
+
+	if (!acpi_bus_get_device(handle, &device))
+		device->eject.request_offline = (bool)data;
+
+	return AE_OK;
+}
+
+void acpi_request_offline_recursive(struct acpi_device *device, bool value)
+{
+	acpi_handle handle = device->handle;
+	acpi_status status;
+
+	mutex_lock(&acpi_scan_lock);
+	device->eject.request_offline = value;
+	status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+				     acpi_bus_request_offline, NULL,
+				     (void *)value, NULL);
+	mutex_unlock(&acpi_scan_lock);
+}
+
 static void acpi_scan_cancel_eject(struct acpi_device *device)
 {
 	acpi_handle handle = device->handle;