2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
5 * Exynos-SnapShot debugging framework for Exynos SoC
7 * Author: Hosung Kim <Hosung0.kim@samsung.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/module.h>
17 #include <linux/ktime.h>
18 #include <linux/kallsyms.h>
19 #include <linux/platform_device.h>
20 #include <linux/clk-provider.h>
21 #include <linux/pstore_ram.h>
22 #include <linux/sched/clock.h>
23 #include <linux/ftrace.h>
25 #include "debug-snapshot-local.h"
27 #include <asm/traps.h>
28 #include <asm/hardirq.h>
29 #include <asm/stacktrace.h>
30 #include <linux/debug-snapshot.h>
31 #include <linux/kernel_stat.h>
32 #include <linux/irqnr.h>
33 #include <linux/irq.h>
34 #include <linux/irqdesc.h>
37 * sysfs implementation for debug-snapshot
38 * you can access the sysfs of debug-snapshot to /sys/devices/system/debug_snapshot
41 static struct bus_type dss_subsys
= {
42 .name
= "debug-snapshot",
43 .dev_name
= "debug-snapshot",
46 extern int dss_irqlog_exlist
[DSS_EX_MAX_NUM
];
47 extern int dss_irqexit_exlist
[DSS_EX_MAX_NUM
];
48 extern unsigned int dss_irqexit_threshold
;
50 static ssize_t
dss_enable_show(struct device
*dev
,
51 struct device_attribute
*attr
, char *buf
)
53 struct dbg_snapshot_item
*item
;
58 for (i
= 0; i
< dss_desc
.log_cnt
; i
++) {
60 n
+= scnprintf(buf
+ n
, 24, "%-12s : %sable\n",
61 item
->name
, item
->entry
.enabled
? "en" : "dis");
65 n
+= scnprintf(buf
+ n
, 24, "%-12s : %sable\n",
66 "base", dss_base
.enabled
? "en" : "dis");
71 static ssize_t
dss_enable_store(struct device
*dev
,
72 struct device_attribute
*attr
,
73 const char *buf
, size_t count
)
78 name
= (char *)kstrndup(buf
, count
, GFP_KERNEL
);
82 name
[count
- 1] = '\0';
84 en
= dbg_snapshot_get_enable(name
);
87 pr_info("echo name > enabled\n");
90 dbg_snapshot_set_enable(name
, false);
92 dbg_snapshot_set_enable(name
, true);
99 static ssize_t
dss_callstack_show(struct device
*dev
,
100 struct device_attribute
*attr
, char *buf
)
104 n
= scnprintf(buf
, 24, "callstack depth : %d\n", dss_desc
.callstack
);
109 static ssize_t
dss_callstack_store(struct device
*dev
, struct device_attribute
*attr
,
110 const char *buf
, size_t count
)
112 unsigned long callstack
;
114 callstack
= simple_strtoul(buf
, NULL
, 0);
115 pr_info("callstack depth(min 1, max 4) : %lu\n", callstack
);
117 if (callstack
< 5 && callstack
> 0) {
118 dss_desc
.callstack
= (unsigned int)callstack
;
119 pr_info("success inserting %lu to callstack value\n", callstack
);
124 static ssize_t
dss_irqlog_exlist_show(struct device
*dev
,
125 struct device_attribute
*attr
, char *buf
)
130 n
= scnprintf(buf
, 24, "excluded irq number\n");
132 for (i
= 0; i
< ARRAY_SIZE(dss_irqlog_exlist
); i
++) {
133 if (dss_irqlog_exlist
[i
] == 0)
135 n
+= scnprintf(buf
+ n
, 24, "irq num: %-4d\n", dss_irqlog_exlist
[i
]);
140 static ssize_t
dss_irqlog_exlist_store(struct device
*dev
,
141 struct device_attribute
*attr
,
142 const char *buf
, size_t count
)
147 irq
= simple_strtoul(buf
, NULL
, 0);
148 pr_info("irq number : %lu\n", irq
);
150 for (i
= 0; i
< ARRAY_SIZE(dss_irqlog_exlist
); i
++) {
151 if (dss_irqlog_exlist
[i
] == 0)
155 if (i
== ARRAY_SIZE(dss_irqlog_exlist
)) {
156 pr_err("list is full\n");
161 dss_irqlog_exlist
[i
] = irq
;
162 pr_info("success inserting %lu to list\n", irq
);
167 #ifdef CONFIG_DEBUG_SNAPSHOT_IRQ_EXIT
168 static ssize_t
dss_irqexit_exlist_show(struct device
*dev
,
169 struct device_attribute
*attr
, char *buf
)
174 n
= scnprintf(buf
, 36, "Excluded irq number\n");
175 for (i
= 0; i
< ARRAY_SIZE(dss_irqexit_exlist
); i
++) {
176 if (dss_irqexit_exlist
[i
] == 0)
178 n
+= scnprintf(buf
+ n
, 24, "IRQ num: %-4d\n", dss_irqexit_exlist
[i
]);
183 static ssize_t
dss_irqexit_exlist_store(struct device
*dev
,
184 struct device_attribute
*attr
,
185 const char *buf
, size_t count
)
190 irq
= simple_strtoul(buf
, NULL
, 0);
191 pr_info("irq number : %lu\n", irq
);
193 for (i
= 0; i
< ARRAY_SIZE(dss_irqexit_exlist
); i
++) {
194 if (dss_irqexit_exlist
[i
] == 0)
198 if (i
== ARRAY_SIZE(dss_irqexit_exlist
)) {
199 pr_err("list is full\n");
204 dss_irqexit_exlist
[i
] = irq
;
205 pr_info("success inserting %lu to list\n", irq
);
210 static ssize_t
dss_irqexit_threshold_show(struct device
*dev
,
211 struct device_attribute
*attr
, char *buf
)
215 n
= scnprintf(buf
, 46, "threshold : %12u us\n", dss_irqexit_threshold
);
219 static ssize_t
dss_irqexit_threshold_store(struct device
*dev
,
220 struct device_attribute
*attr
,
221 const char *buf
, size_t count
)
225 val
= simple_strtoul(buf
, NULL
, 0);
226 pr_info("threshold value : %lu\n", val
);
229 dss_irqexit_threshold
= (unsigned int)val
;
230 pr_info("success %lu to threshold\n", val
);
236 #ifdef CONFIG_DEBUG_SNAPSHOT_REG
237 static ssize_t
dss_reg_exlist_show(struct device
*dev
,
238 struct device_attribute
*attr
, char *buf
)
243 n
= scnprintf(buf
, 36, "excluded register address\n");
244 for (i
= 0; i
< ARRAY_SIZE(dss_reg_exlist
); i
++) {
245 if (dss_reg_exlist
[i
].addr
== 0)
247 n
+= scnprintf(buf
+ n
, 40, "register addr: %08zx size: %08zx\n",
248 dss_reg_exlist
[i
].addr
, dss_reg_exlist
[i
].size
);
253 static ssize_t
dss_reg_exlist_store(struct device
*dev
,
254 struct device_attribute
*attr
,
255 const char *buf
, size_t count
)
260 addr
= simple_strtoul(buf
, NULL
, 0);
261 pr_info("register addr: %zx\n", addr
);
263 for (i
= 0; i
< ARRAY_SIZE(dss_reg_exlist
); i
++) {
264 if (dss_reg_exlist
[i
].addr
== 0)
268 dss_reg_exlist
[i
].size
= SZ_4K
;
269 dss_reg_exlist
[i
].addr
= addr
;
270 pr_info("success %zx to threshold\n", (addr
));
277 static struct device_attribute dss_enable_attr
=
278 __ATTR(enabled
, 0644, dss_enable_show
, dss_enable_store
);
280 static struct device_attribute dss_callstack_attr
=
281 __ATTR(callstack
, 0644, dss_callstack_show
, dss_callstack_store
);
283 static struct device_attribute dss_irqlog_attr
=
284 __ATTR(exlist_irqdisabled
, 0644, dss_irqlog_exlist_show
,
285 dss_irqlog_exlist_store
);
286 #ifdef CONFIG_DEBUG_SNAPSHOT_IRQ_EXIT
287 static struct device_attribute dss_irqexit_attr
=
288 __ATTR(exlist_irqexit
, 0644, dss_irqexit_exlist_show
,
289 dss_irqexit_exlist_store
);
291 static struct device_attribute dss_irqexit_threshold_attr
=
292 __ATTR(threshold_irqexit
, 0644, dss_irqexit_threshold_show
,
293 dss_irqexit_threshold_store
);
295 #ifdef CONFIG_DEBUG_SNAPSHOT_REG
297 static struct device_attribute dss_reg_attr
=
298 __ATTR(exlist_reg
, 0644, dss_reg_exlist_show
, dss_reg_exlist_store
);
301 static struct attribute
*dss_sysfs_attrs
[] = {
302 &dss_enable_attr
.attr
,
303 &dss_callstack_attr
.attr
,
304 &dss_irqlog_attr
.attr
,
305 #ifdef CONFIG_DEBUG_SNAPSHOT_IRQ_EXIT
306 &dss_irqexit_attr
.attr
,
307 &dss_irqexit_threshold_attr
.attr
,
309 #ifdef CONFIG_DEBUG_SNAPSHOT_REG
315 static struct attribute_group dss_sysfs_group
= {
316 .attrs
= dss_sysfs_attrs
,
319 static const struct attribute_group
*dss_sysfs_groups
[] = {
324 static int __init
dbg_snapshot_sysfs_init(void)
328 ret
= subsys_system_register(&dss_subsys
, dss_sysfs_groups
);
330 pr_err("fail to register debug-snapshop subsys\n");
334 late_initcall(dbg_snapshot_sysfs_init
);