summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Yan <andy.yan@rock-chips.com>2019-02-22 19:08:19 +0800
committerTao Huang <huangtao@rock-chips.com>2019-03-12 16:10:53 +0800
commit5cc41272c3d2ab770f1890abeae3f5e1c2127a11 (patch)
tree53280fcc75eecc556afe8877902c3fa0039bb32c
parentde56d92b60f66f938ee8cd0a02ff7cbe60bf16d7 (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>
-rw-r--r--drivers/power/reset/reboot-mode.c69
-rw-r--r--drivers/power/reset/reboot-mode.h3
-rw-r--r--drivers/power/reset/syscon-reboot-mode.c12
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");