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@xxxxxxxx> --- 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 --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@xxxxxxxx> +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@xxxxxxxx> 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; -- 2.24.0