2 * arch/arm/mach-tegra/nvdumper.c
4 * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/errno.h>
18 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/reboot.h>
22 #include <linux/slab.h>
23 #include <linux/uaccess.h>
24 #include "../../../arch/arm/mach-tegra/board.h"
26 #include "nvdumper-footprint.h"
28 #ifdef CONFIG_TEGRA_USE_NCT
29 #include "../../../arch/arm/mach-tegra/include/mach/nct.h"
32 static void __init nvdumper_sysfs_init(void);
33 static void __exit nvdumper_sysfs_exit(void);
35 #define NVDUMPER_CLEAN 0xf000caf3U
36 #define NVDUMPER_DIRTY 0x2badfaceU
37 #define NVDUMPER_DIRTY_DUMP 0xdeadbeefU
38 #define NVDUMPER_WDT_DUMP 0x2badbeefU
40 #define RW_MODE (S_IWUSR | S_IRUGO)
42 static void __iomem *nvdumper_ptr;
43 static uint32_t nvdumper_last_reboot;
45 static uint32_t get_dirty_state(void)
47 return ioread32(nvdumper_ptr);
50 static void set_dirty_state(uint32_t state)
52 pr_info("nvdumper: set_dirty_state 0x%x\n", state);
53 iowrite32(state, nvdumper_ptr);
56 static int nvdumper_reboot_cb(struct notifier_block *nb,
57 unsigned long event, void *unused)
59 pr_info("nvdumper: %s cleanly.\n",
60 (event == SYS_RESTART) ? "rebooting" : "shutting down");
61 set_dirty_state(NVDUMPER_CLEAN);
65 static struct notifier_block nvdumper_reboot_notifier = {
66 .notifier_call = nvdumper_reboot_cb,
69 static int __init nvdumper_init(void)
73 #ifdef CONFIG_TEGRA_USE_NCT
74 union nct_item_type *item;
77 if (!nvdumper_reserved) {
78 pr_info("nvdumper: not configured\n");
81 nvdumper_ptr = ioremap_nocache(nvdumper_reserved,
82 NVDUMPER_RESERVED_SIZE);
84 pr_info("nvdumper: failed to ioremap memory at 0x%08lx\n",
88 ret = register_reboot_notifier(&nvdumper_reboot_notifier);
92 ret = nvdumper_regdump_init();
96 nvdumper_dbg_footprint_init();
98 nvdumper_last_reboot = get_dirty_state();
99 switch (nvdumper_last_reboot) {
101 pr_info("nvdumper: last reboot was clean\n");
104 case NVDUMPER_DIRTY_DUMP:
105 case NVDUMPER_WDT_DUMP:
106 pr_info("nvdumper: last reboot was dirty\n");
109 pr_info("nvdumper: last reboot was unknown\n");
113 nvdumper_sysfs_init();
115 #ifdef CONFIG_TEGRA_USE_NCT
116 item = kzalloc(sizeof(*item), GFP_KERNEL);
118 pr_err("failed to allocate memory\n");
122 ret = tegra_nct_read_item(NCT_ID_RAMDUMP, item);
124 pr_err("%s: NCT read failure\n", __func__);
126 set_dirty_state(NVDUMPER_CLEAN);
130 pr_info("%s: RAMDUMP flag(%d) from NCT\n",
131 __func__, item->ramdump.flag);
132 if (item->ramdump.flag == 1)
133 set_dirty_state(NVDUMPER_DIRTY_DUMP);
134 else if (item->ramdump.flag == 2)
135 set_dirty_state(NVDUMPER_DIRTY);
136 else if (item->ramdump.flag == 3)
137 set_dirty_state(NVDUMPER_WDT_DUMP);
139 set_dirty_state(NVDUMPER_CLEAN);
148 set_dirty_state(NVDUMPER_DIRTY);
153 unregister_reboot_notifier(&nvdumper_reboot_notifier);
155 iounmap(nvdumper_ptr);
157 #ifdef CONFIG_TEGRA_USE_NCT /* avoid build error if NCT is not enabled*/
165 static void __exit nvdumper_exit(void)
167 nvdumper_sysfs_exit();
168 nvdumper_regdump_exit();
169 nvdumper_dbg_footprint_exit();
170 unregister_reboot_notifier(&nvdumper_reboot_notifier);
171 set_dirty_state(NVDUMPER_CLEAN);
172 iounmap(nvdumper_ptr);
175 static char *nvdumper_set_str = "dirty_dump";
176 static struct kobject *nvdumper_kobj;
178 static ssize_t nvdumper_set_show(struct kobject *kobj,
179 struct kobj_attribute *attr,
182 return sprintf(buf, "%s\n", nvdumper_set_str);
185 static ssize_t nvdumper_set_store(struct kobject *kobj,
186 struct kobj_attribute *attr,
187 const char *buf, size_t n)
192 sprintf(nvdumper_set_str, "%s", buf);
193 nvdumper_set_str[n-1] = '\0';
195 if (!strcmp(nvdumper_set_str, "clean"))
196 set_dirty_state(NVDUMPER_CLEAN);
197 else if (!strcmp(nvdumper_set_str, "dirty"))
198 set_dirty_state(NVDUMPER_DIRTY);
199 else if (!strcmp(nvdumper_set_str, "dirty_dump"))
200 set_dirty_state(NVDUMPER_DIRTY_DUMP);
201 else if (!strcmp(nvdumper_set_str, "wdt_dump"))
202 set_dirty_state(NVDUMPER_WDT_DUMP);
204 strcpy(nvdumper_set_str, "unknown");
206 pr_info("nvdumper_set was updated to %s\n", nvdumper_set_str);
211 static ssize_t nvdumper_prev_show(struct kobject *kobj,
212 struct kobj_attribute *attr,
215 return sprintf(buf, "%s\n", nvdumper_set_str);
218 static const struct kobj_attribute nvdumper_attr[] = {
219 __ATTR(nvdumper_set, 0644, nvdumper_set_show, nvdumper_set_store),
220 __ATTR(nvdumper_prev, 0444, nvdumper_prev_show, NULL),
223 static void __init nvdumper_sysfs_init(void)
227 nvdumper_kobj = kobject_create_and_add("nvdumper", kernel_kobj);
229 if (!nvdumper_kobj) {
230 pr_err("unable to create nvdumper kernel object!\n");
235 for (i = 0; i < ARRAY_SIZE(nvdumper_attr); i++) {
236 ret = sysfs_create_file(nvdumper_kobj, &nvdumper_attr[i].attr);
238 pr_err("failed to create %s\n",
239 nvdumper_attr[i].attr.name);
242 switch (nvdumper_last_reboot) {
244 nvdumper_set_str = "clean\n";
247 nvdumper_set_str = "dirty\n";
249 case NVDUMPER_DIRTY_DUMP:
250 nvdumper_set_str = "dirty_dump\n";
253 nvdumper_set_str = "dirty\n";
258 static void __exit nvdumper_sysfs_exit(void)
265 for (i = 0; i < ARRAY_SIZE(nvdumper_attr); i++)
266 sysfs_remove_file(nvdumper_kobj, &nvdumper_attr[i].attr);
269 arch_initcall(nvdumper_init);
270 module_exit(nvdumper_exit);
272 MODULE_LICENSE("GPL");