diff options
author | Andy Yan <andy.yan@rock-chips.com> | 2019-02-22 19:08:19 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2019-03-12 16:10:53 +0800 |
commit | 5cc41272c3d2ab770f1890abeae3f5e1c2127a11 (patch) | |
tree | 53280fcc75eecc556afe8877902c3fa0039bb32c /drivers | |
parent | de56d92b60f66f938ee8cd0a02ff7cbe60bf16d7 (diff) |
power: reset: reboot-mode: support parse boot mode
Parse boot mode on system bootup, and export it to
userspace by sysfs: sys/kernel/boot_mode
Change-Id: I0158fc28f4dae51c798806006e49cead4ce2e923
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/reset/reboot-mode.c | 69 | ||||
-rw-r--r-- | drivers/power/reset/reboot-mode.h | 3 | ||||
-rw-r--r-- | drivers/power/reset/syscon-reboot-mode.c | 12 |
3 files changed, 75 insertions, 9 deletions
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index 1afccd2300b1..2597d8cf798e 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -10,9 +10,11 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/kobject.h> #include <linux/module.h> #include <linux/of.h> #include <linux/reboot.h> +#include <linux/sysfs.h> #include "reboot-mode.h" #define PREFIX "mode-" @@ -26,9 +28,21 @@ struct mode_info { struct reboot_mode_driver { struct list_head head; int (*write)(int magic); + int (*read)(void); struct notifier_block reboot_notifier; + struct notifier_block panic_notifier; }; +static char *boot_mode = "coldboot"; + +static ssize_t boot_mode_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", boot_mode); +} + +static struct kobj_attribute kobj_boot_mode = __ATTR_RO(boot_mode); + static int get_reboot_mode_magic(struct reboot_mode_driver *reboot, const char *cmd) { @@ -49,23 +63,60 @@ static int get_reboot_mode_magic(struct reboot_mode_driver *reboot, return magic; } -static int reboot_mode_notify(struct notifier_block *this, - unsigned long mode, void *cmd) +static void reboot_mode_write(struct reboot_mode_driver *reboot, + const void *cmd) { - struct reboot_mode_driver *reboot; int magic; - reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); magic = get_reboot_mode_magic(reboot, cmd); if (!magic) magic = get_reboot_mode_magic(reboot, NULL); if (magic) reboot->write(magic); +} + +static int reboot_mode_notify(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct reboot_mode_driver *reboot; + + reboot = container_of(this, struct reboot_mode_driver, reboot_notifier); + reboot_mode_write(reboot, cmd); return NOTIFY_DONE; } -int reboot_mode_register(struct device *dev, int (*write)(int)) +static int reboot_mode_panic_notify(struct notifier_block *this, + unsigned long ev, void *ptr) +{ + struct reboot_mode_driver *reboot; + const char *cmd = "panic"; + + reboot = container_of(this, struct reboot_mode_driver, panic_notifier); + reboot_mode_write(reboot, cmd); + + return NOTIFY_DONE; +} + +static int boot_mode_parse(struct reboot_mode_driver *reboot) +{ + struct mode_info *info; + unsigned int magic = reboot->read(); + + list_for_each_entry(info, &reboot->head, list) { + if (info->magic == magic) { + boot_mode = info->mode; + break; + } + } + + pr_info("Boot mode: %s\n", boot_mode); + + return 0; +} + +int reboot_mode_register(struct device *dev, int (*write)(int), + int (*read)(void)) { struct reboot_mode_driver *reboot; struct mode_info *info; @@ -78,6 +129,7 @@ int reboot_mode_register(struct device *dev, int (*write)(int)) return -ENOMEM; reboot->write = write; + reboot->read = read; INIT_LIST_HEAD(&reboot->head); for_each_property_of_node(dev->of_node, prop) { if (len > strlen(prop->name) || strncmp(prop->name, PREFIX, len)) @@ -94,10 +146,13 @@ int reboot_mode_register(struct device *dev, int (*write)(int)) } list_add_tail(&info->list, &reboot->head); } + boot_mode_parse(reboot); reboot->reboot_notifier.notifier_call = reboot_mode_notify; + reboot->panic_notifier.notifier_call = reboot_mode_panic_notify; ret = register_reboot_notifier(&reboot->reboot_notifier); - if (ret) - dev_err(dev, "can't register reboot notifier\n"); + ret += atomic_notifier_chain_register(&panic_notifier_list, + &reboot->panic_notifier); + ret += sysfs_create_file(kernel_kobj, &kobj_boot_mode.attr); return ret; } diff --git a/drivers/power/reset/reboot-mode.h b/drivers/power/reset/reboot-mode.h index 342df786d043..3de8ad6cc4aa 100644 --- a/drivers/power/reset/reboot-mode.h +++ b/drivers/power/reset/reboot-mode.h @@ -2,6 +2,7 @@ #ifndef __REBOOT_MODE_H__ #define __REBOOT_MODE_H__ -int reboot_mode_register(struct device *dev, int (*write)(int)); +int reboot_mode_register(struct device *dev, int (*write)(int), + int (*read)(void)); #endif diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c index d1521d810ea2..27ef0b3151bd 100644 --- a/drivers/power/reset/syscon-reboot-mode.c +++ b/drivers/power/reset/syscon-reboot-mode.c @@ -29,6 +29,15 @@ static int syscon_reboot_mode_write(int magic) return 0; } +static int syscon_reboot_mode_read(void) +{ + u32 val = 0; + + regmap_read(map, offset, &val); + + return val; +} + static int syscon_reboot_mode_probe(struct platform_device *pdev) { int ret; @@ -39,7 +48,8 @@ static int syscon_reboot_mode_probe(struct platform_device *pdev) if (of_property_read_u32(pdev->dev.of_node, "offset", &offset)) return -EINVAL; of_property_read_u32(pdev->dev.of_node, "mask", &mask); - ret = reboot_mode_register(&pdev->dev, syscon_reboot_mode_write); + ret = reboot_mode_register(&pdev->dev, syscon_reboot_mode_write, + syscon_reboot_mode_read); if (ret) dev_err(&pdev->dev, "can't register reboot mode\n"); |