Current reboot-mode driver supports a single argument(magic) for each reboot-mode. There may be uses-cases where a mode requires an additional argument and hence may not be able to use the reboot-mode driver. For example, ARM PSCI vendor-specific resets, need two arguments for its operation – reset_type and cookie, to complete the reset operation. If a driver wants to implement this firmware-based reset, it cannot use reboot-mode framework. Add support for storing an additional optional argument (cookie) for each reboot-mode and introduce a write function in reboot-mode that writes two arguments for each reboot-mode command. Implement the read and store of additional cookie value for each reboot-mode defined in the device tree. In case there is no cookie specified in the reboot-mode device tree, mark the cookie as invalid to support backward compatibility. Signed-off-by: Shivendra Pratap <shivendra.pratap@xxxxxxxxxxxxxxxx> --- drivers/power/reset/reboot-mode.c | 32 ++++++++++++++++++++++---------- include/linux/reboot-mode.h | 2 ++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index 61f647b23959789a313f3af0bd967abcad45fa43..afadd823d62d0f7e7e645746b978cc8fecfb9ac4 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -17,11 +17,12 @@ struct mode_info { const char *mode; u32 magic; + u32 cookie; + bool is_cookie_valid; struct list_head list; }; -static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, - const char *cmd) +static struct mode_info *get_reboot_mode_info(struct reboot_mode_driver *reboot, const char *cmd) { const char *normal = "normal"; struct mode_info *info; @@ -32,11 +33,11 @@ static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, list_for_each_entry(info, &reboot->head, list) if (!strcmp(info->mode, cmd)) - return info->magic; + return info; /* try to match again, replacing characters impossible in DT */ if (strscpy(cmd_, cmd, sizeof(cmd_)) == -E2BIG) - return 0; + return NULL; strreplace(cmd_, ' ', '-'); strreplace(cmd_, ',', '-'); @@ -44,21 +45,27 @@ static unsigned int get_reboot_mode_magic(struct reboot_mode_driver *reboot, list_for_each_entry(info, &reboot->head, list) if (!strcmp(info->mode, cmd_)) - return info->magic; + return info; - return 0; + return NULL; } static int reboot_mode_notify(struct notifier_block *this, unsigned long mode, void *cmd) { struct reboot_mode_driver *reboot; - unsigned int magic; + struct mode_info *info; reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); - magic = get_reboot_mode_magic(reboot, cmd); - if (magic) - reboot->write(reboot, magic); + info = get_reboot_mode_info(reboot, cmd); + if (info) { + if (info->is_cookie_valid) { + reboot->write_with_cookie(reboot, info->magic, info->cookie); + } else { + if (info->magic) + reboot->write(reboot, info->magic); + } + } return NOTIFY_DONE; } @@ -95,6 +102,11 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, struct device_node * continue; } + if (of_property_read_u32_index(np, prop->name, 1, &info->cookie)) + info->is_cookie_valid = false; + else + info->is_cookie_valid = true; + info->mode = kstrdup_const(prop->name + len, GFP_KERNEL); if (!info->mode) { ret = -ENOMEM; diff --git a/include/linux/reboot-mode.h b/include/linux/reboot-mode.h index 36f071f4b82e1fc255d8dd679a18e537655c3179..cfe18cdc2559be249969bba6c022940a508dd188 100644 --- a/include/linux/reboot-mode.h +++ b/include/linux/reboot-mode.h @@ -6,6 +6,8 @@ struct reboot_mode_driver { struct device *dev; struct list_head head; int (*write)(struct reboot_mode_driver *reboot, unsigned int magic); + int (*write_with_cookie)(struct reboot_mode_driver *reboot, + unsigned int magic, unsigned int cookie); struct notifier_block reboot_notifier; }; -- 2.34.1