[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250710-arm-psci-system_reset2-vendor-reboots-v10-10-b2d3b882be85@oss.qualcomm.com>
Date: Thu, 10 Jul 2025 14:45:52 +0530
From: Shivendra Pratap <shivendra.pratap@....qualcomm.com>
To: Bartosz Golaszewski <bartosz.golaszewski@...aro.org>,
Bjorn Andersson <andersson@...nel.org>,
Sebastian Reichel <sre@...nel.org>, Rob Herring <robh@...nel.org>,
Sudeep Holla <sudeep.holla@....com>,
Souvik Chakravarty <Souvik.Chakravarty@....com>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>, Andy Yan <andy.yan@...k-chips.com>,
Mark Rutland <mark.rutland@....com>,
Lorenzo Pieralisi <lpieralisi@...nel.org>,
Arnd Bergmann <arnd@...db.de>, Olof Johansson <olof@...om.net>,
Konrad Dybcio <konradybcio@...nel.org>,
cros-qcom-dts-watchers@...omium.org, Vinod Koul <vkoul@...nel.org>,
Catalin Marinas <catalin.marinas@....com>,
Will Deacon <will@...nel.org>,
Florian Fainelli <florian.fainelli@...adcom.com>,
Elliot Berman <elliotb317@...il.com>
Cc: Stephen Boyd <swboyd@...omium.org>, linux-pm@...r.kernel.org,
linux-kernel@...r.kernel.org, devicetree@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org, linux-arm-msm@...r.kernel.org,
Andre Draszik <andre.draszik@...aro.org>,
Alim Akhtar <alim.akhtar@...sung.com>,
linux-samsung-soc@...r.kernel.org, Wei Xu <xuwei5@...ilicon.com>,
linux-rockchip@...ts.infradead.org,
Baolin Wang <baolin.wang@...ux.alibaba.com>,
Sen Chu <sen.chu@...iatek.com>, Sean Wang <sean.wang@...iatek.com>,
Macpaul Lin <macpaul.lin@...iatek.com>,
AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com>,
Ray Jui <rjui@...adcom.com>, Scott Branden <sbranden@...adcom.com>,
bcm-kernel-feedback-list@...adcom.com,
Nicolas Ferre <nicolas.ferre@...rochip.com>,
Alexandre Belloni <alexandre.belloni@...tlin.com>,
Elliot Berman <quic_eberman@...cinc.com>,
Shivendra Pratap <shivendra.pratap@....qualcomm.com>,
Srinivas Kandagatla <srini@...nel.org>
Subject: [PATCH v10 10/10] power: reset: reboot-mode: Expose sysfs for
registered arguments
Currently, there is no standardized mechanism for userspace to
discover which reboot-modes are supported on a given platform.
This limitation forces tools and scripts to rely on hardcoded
assumptions about the supported reboot-modes.
Create a class 'reboot-mode' and a device under it to expose a
sysfs interface to show the available reboot mode arguments to
userspace.
Create the device using the node name of the driver that
registers with reboot mode driver.
This results in the creation of:
/sys/class/reboot-mode/<driver>/reboot_modes
This read-only sysfs file will exposes the list of supported
reboot modes arguments provided by the driver, enabling userspace
to query the list of arguments.
Align the clean up path to maintain backward compatibility for
existing reboot-mode based drivers.
Signed-off-by: Shivendra Pratap <shivendra.pratap@....qualcomm.com>
---
drivers/power/reset/reboot-mode.c | 95 ++++++++++++++++++++++++++++++++++-----
include/linux/reboot-mode.h | 1 +
2 files changed, 84 insertions(+), 12 deletions(-)
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index afadd823d62d0f7e7e645746b978cc8fecfb9ac4..128192d49d895beeacb180c1a92b44a5eddccc78 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -22,6 +22,8 @@ struct mode_info {
struct list_head list;
};
+static struct class *rb_class;
+
static struct mode_info *get_reboot_mode_info(struct reboot_mode_driver *reboot, const char *cmd)
{
const char *normal = "normal";
@@ -70,6 +72,79 @@ static int reboot_mode_notify(struct notifier_block *this,
return NOTIFY_DONE;
}
+static void release_reboot_mode_device(struct device *dev, void *res);
+
+static ssize_t reboot_modes_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct reboot_mode_driver **devres_reboot;
+ struct reboot_mode_driver *reboot;
+ struct mode_info *info;
+ ssize_t size = 0;
+
+ devres_reboot = devres_find(dev, release_reboot_mode_device, NULL, 0);
+ reboot = *devres_reboot;
+ list_for_each_entry(info, &reboot->head, list) {
+ size += sprintf(buf + size, "%s,", info->mode);
+ }
+
+ if (size) {
+ size += sprintf(buf + size - 1, "\n");
+ return size;
+ }
+
+ return -ENODATA;
+}
+static DEVICE_ATTR_RO(reboot_modes);
+
+static void release_reboot_mode_device(struct device *dev, void *res)
+{
+ struct reboot_mode_driver *reboot = *(struct reboot_mode_driver **)res;
+ struct mode_info *info;
+ struct mode_info *next;
+
+ unregister_reboot_notifier(&reboot->reboot_notifier);
+
+ list_for_each_entry_safe(info, next, &reboot->head, list) {
+ kfree_const(info->mode);
+ list_del(&info->list);
+ kfree(info);
+ }
+
+ device_remove_file(reboot->dev, &dev_attr_reboot_modes);
+}
+
+static int create_reboot_mode_device(struct reboot_mode_driver *reboot,
+ const char *dev_name)
+{
+ struct reboot_mode_driver **dr;
+ int ret = 0;
+
+ if (!rb_class) {
+ rb_class = class_create("reboot-mode");
+ if (IS_ERR(rb_class))
+ return PTR_ERR(rb_class);
+ }
+
+ reboot->reboot_dev = device_create(rb_class, NULL, 0, NULL, dev_name);
+ if (IS_ERR(reboot->reboot_dev))
+ return PTR_ERR(reboot->reboot_dev);
+
+ ret = device_create_file(reboot->reboot_dev, &dev_attr_reboot_modes);
+ if (ret)
+ return ret;
+
+ dr = devres_alloc(release_reboot_mode_device, sizeof(*dr), GFP_KERNEL);
+ if (!dr) {
+ device_remove_file(reboot->reboot_dev, &dev_attr_reboot_modes);
+ return -ENOMEM;
+ }
+
+ *dr = reboot;
+ devres_add(reboot->reboot_dev, dr);
+
+ return ret;
+}
+
/**
* reboot_mode_register - register a reboot mode driver
* @reboot: reboot mode driver
@@ -84,6 +159,10 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, struct device_node *
size_t len = strlen(PREFIX);
int ret;
+ ret = create_reboot_mode_device(reboot, np->name ? np->name : "reboot-mode-dev");
+ if (ret)
+ return ret;
+
INIT_LIST_HEAD(&reboot->head);
for_each_property_of_node(np, prop) {
@@ -140,24 +219,16 @@ EXPORT_SYMBOL_GPL(reboot_mode_register);
*/
int reboot_mode_unregister(struct reboot_mode_driver *reboot)
{
- struct mode_info *info;
- struct mode_info *next;
-
- unregister_reboot_notifier(&reboot->reboot_notifier);
-
- list_for_each_entry_safe(info, next, &reboot->head, list) {
- kfree_const(info->mode);
- list_del(&info->list);
- kfree(info);
- }
-
+ device_unregister(reboot->reboot_dev);
return 0;
}
EXPORT_SYMBOL_GPL(reboot_mode_unregister);
static void devm_reboot_mode_release(struct device *dev, void *res)
{
- reboot_mode_unregister(*(struct reboot_mode_driver **)res);
+ struct reboot_mode_driver *reboot = *(struct reboot_mode_driver **)res;
+
+ device_unregister(reboot->reboot_dev);
}
/**
diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h
index cfe18cdc2559be249969bba6c022940a508dd188..3aab8700a5961b90b07ed4d722c77484213ac6c4 100644
--- a/include/linux/reboot-mode.h
+++ b/include/linux/reboot-mode.h
@@ -4,6 +4,7 @@
struct reboot_mode_driver {
struct device *dev;
+ struct device *reboot_dev;
struct list_head head;
int (*write)(struct reboot_mode_driver *reboot, unsigned int magic);
int (*write_with_cookie)(struct reboot_mode_driver *reboot,
--
2.34.1
Powered by blists - more mailing lists