[RAMEN9610-9428] debugfs: purge obsolete SRCU based removal protection
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / lib / debug-snapshot.c
CommitLineData
dd101ca5
DC
1/*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * Debug-SnapShot: Debug Framework for Ramdump based debugging method
6 * The original code is Exynos-Snapshot for Exynos SoC
7 *
8 * Author: Hosung Kim <hosung0.kim@samsung.com>
9 * Author: Changki Kim <changki.kim@samsung.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#include <linux/kernel.h>
17#include <linux/version.h>
18#include <linux/io.h>
19#include <linux/device.h>
20#include <linux/bootmem.h>
21#include <linux/slab.h>
22#include <linux/vmalloc.h>
23#include <linux/module.h>
24#include <linux/memblock.h>
25#include <linux/of_address.h>
26#include <linux/of_reserved_mem.h>
27#include <linux/sched/clock.h>
28
29#include "debug-snapshot-local.h"
30
92c0dff1
HK
31/* To Support Samsung SoC */
32#include <dt-bindings/soc/samsung/debug-snapshot-table.h>
33#ifdef CONFIG_DEBUG_SNAPSHOT_PMU
34#include <soc/samsung/cal-if.h>
35#endif
36
dd101ca5
DC
37extern void register_hook_logbuf(void (*)(const char *, size_t));
38extern void register_hook_logger(void (*)(const char *, const char *, size_t));
39
40struct dbg_snapshot_interface {
41 struct dbg_snapshot_log *info_event;
42 struct dbg_snapshot_item info_log[DSS_ITEM_MAX_NUM];
43};
44
45#ifdef CONFIG_DEBUG_SNAPSHOT_PMU
92c0dff1
HK
46struct dbg_snapshot_ops {
47 int (*pd_status)(unsigned int id);
48};
49
dd101ca5
DC
50struct dbg_snapshot_ops dss_ops = {
51 .pd_status = cal_pd_status,
52};
53#endif
54
55struct dbg_snapshot_item dss_items[] = {
56 {"header", {0, 0, 0, false, false}, NULL ,NULL, 0, },
57 {"log_kernel", {0, 0, 0, false, false}, NULL ,NULL, 0, },
58 {"log_platform", {0, 0, 0, false, false}, NULL ,NULL, 0, },
59 {"log_sfr", {0, 0, 0, false, false}, NULL ,NULL, 0, },
60 {"log_s2d", {0, 0, 0, true, false}, NULL, NULL, 0, },
61 {"log_cachedump", {0, 0, 0, true, false}, NULL, NULL, 0, },
62 {"log_etm", {0, 0, 0, true, false}, NULL ,NULL, 0, },
63 {"log_bcm", {0, 0, 0, false, false}, NULL ,NULL, 0, },
64 {"log_pstore", {0, 0, 0, true, false}, NULL ,NULL, 0, },
65 {"log_kevents", {0, 0, 0, false, false}, NULL ,NULL, 0, },
66};
67
68/* External interface variable for trace debugging */
69static struct dbg_snapshot_interface dss_info __attribute__ ((used));
70static struct dbg_snapshot_interface *ess_info __attribute__ ((used));
71
72struct dbg_snapshot_base dss_base;
73struct dbg_snapshot_base ess_base;
74struct dbg_snapshot_log *dss_log = NULL;
75struct dbg_snapshot_desc dss_desc;
76
77/* Variable for assigning virtual address base */
78static size_t g_dbg_snapshot_vaddr_base = DSS_FIXED_VIRT_BASE;
79
80int dbg_snapshot_set_enable(const char *name, int en)
81{
82 struct dbg_snapshot_item *item = NULL;
83 unsigned long i;
84
85 if (!strncmp(name, "base", strlen(name))) {
86 dss_base.enabled = en;
87 pr_info("debug-snapshot: %sabled\n", en ? "en" : "dis");
88 } else {
89 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
90 if (!strncmp(dss_items[i].name, name, strlen(name))) {
91 item = &dss_items[i];
92 item->entry.enabled = en;
93 item->time = local_clock();
94 pr_info("debug-snapshot: item - %s is %sabled\n",
95 name, en ? "en" : "dis");
96 break;
97 }
98 }
99 }
100 return 0;
101}
102EXPORT_SYMBOL(dbg_snapshot_set_enable);
103
104int dbg_snapshot_try_enable(const char *name, unsigned long long duration)
105{
106 struct dbg_snapshot_item *item = NULL;
107 unsigned long long time;
108 unsigned long i;
109 int ret = -1;
110
111 /* If DSS was disabled, just return */
112 if (unlikely(!dss_base.enabled) || !dbg_snapshot_get_enable("header"))
113 return ret;
114
115 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
116 if (!strncmp(dss_items[i].name, name, strlen(name))) {
117 item = &dss_items[i];
118
119 /* We only interest in disabled */
120 if (!item->entry.enabled) {
121 time = local_clock() - item->time;
122 if (time > duration) {
123 item->entry.enabled = true;
124 ret = 1;
125 } else
126 ret = 0;
127 }
128 break;
129 }
130 }
131 return ret;
132}
133EXPORT_SYMBOL(dbg_snapshot_try_enable);
134
135int dbg_snapshot_get_enable(const char *name)
136{
137 struct dbg_snapshot_item *item = NULL;
138 unsigned long i;
139 int ret = 0;
140
141 if (!strncmp(name, "base", strlen(name)))
142 return dss_base.enabled;
143
144 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
145 if (!strncmp(dss_items[i].name, name, strlen(name))) {
146 item = &dss_items[i];
147 ret = item->entry.enabled;
148 break;
149 }
150 }
151 return ret;
152}
153EXPORT_SYMBOL(dbg_snapshot_get_enable);
154
155static inline int dbg_snapshot_check_eob(struct dbg_snapshot_item *item,
156 size_t size)
157{
158 size_t max, cur;
159
160 max = (size_t)(item->head_ptr + item->entry.size);
161 cur = (size_t)(item->curr_ptr + size);
162
163 if (unlikely(cur > max))
164 return -1;
165 else
166 return 0;
167}
168
169static inline void dbg_snapshot_hook_logger(const char *name,
170 const char *buf, size_t size)
171{
172 struct dbg_snapshot_item *item = &dss_items[dss_desc.log_platform_num];
173
174 if (likely(dss_base.enabled && item->entry.enabled)) {
175 if (unlikely((dbg_snapshot_check_eob(item, size))))
176 item->curr_ptr = item->head_ptr;
177 memcpy(item->curr_ptr, buf, size);
178 item->curr_ptr += size;
179 }
180}
181
182static inline void dbg_snapshot_hook_logbuf(const char *buf, size_t size)
183{
184 struct dbg_snapshot_item *item = &dss_items[dss_desc.log_kernel_num];
185
186 if (likely(dss_base.enabled && item->entry.enabled)) {
187 size_t last_buf;
188
189 if (dbg_snapshot_check_eob(item, size))
190 item->curr_ptr = item->head_ptr;
191
192 memcpy(item->curr_ptr, buf, size);
193 item->curr_ptr += size;
194 /* save the address of last_buf to physical address */
195 last_buf = (size_t)item->curr_ptr;
196
197 __raw_writel(item->entry.paddr + (last_buf - item->entry.vaddr),
198 dbg_snapshot_get_base_vaddr() + DSS_OFFSET_LAST_LOGBUF);
199 }
200}
201
202#ifdef CONFIG_DEBUG_SNAPSHOT_PMU
203static bool dbg_snapshot_check_pmu(struct dbg_snapshot_sfrdump *sfrdump,
204 const struct device_node *np)
205{
206 int ret = 0, count, i;
207 unsigned int val;
208
209 if (!sfrdump->pwr_mode)
210 return true;
211
212 count = of_property_count_u32_elems(np, "cal-pd-id");
213 for (i = 0; i < count; i++) {
214 ret = of_property_read_u32_index(np, "cal-pd-id", i, &val);
215 if (ret < 0) {
216 pr_err("failed to get pd-id - %s\n", sfrdump->name);
217 return false;
218 }
219 ret = dss_ops.pd_status(val);
220 if (ret < 0) {
221 pr_err("not powered - %s (pd-id: %d)\n", sfrdump->name, i);
222 return false;
223 }
224 }
225 return true;
226}
227
228void dbg_snapshot_dump_sfr(void)
229{
230 struct dbg_snapshot_sfrdump *sfrdump;
231 struct dbg_snapshot_item *item = &dss_items[dss_desc.log_sfr_num];
232 struct list_head *entry;
233 struct device_node *np;
234 unsigned int reg, offset, val, size;
235 int i, ret;
236 static char buf[SZ_64];
237
238 if (unlikely(!dss_base.enabled || !item->entry.enabled))
239 return;
240
241 if (list_empty(&dss_desc.sfrdump_list)) {
242 pr_emerg("debug-snapshot: %s: No information\n", __func__);
243 return;
244 }
245
246 list_for_each(entry, &dss_desc.sfrdump_list) {
247 sfrdump = list_entry(entry, struct dbg_snapshot_sfrdump, list);
248 np = of_node_get(sfrdump->node);
249 ret = dbg_snapshot_check_pmu(sfrdump, np);
250 if (!ret)
251 /* may off */
252 continue;
253
254 for (i = 0; i < sfrdump->num; i++) {
255 ret = of_property_read_u32_index(np, "addr", i, &reg);
256 if (ret < 0) {
257 pr_err("debug-snapshot: failed to get address information - %s\n",
258 sfrdump->name);
259 break;
260 }
261 if (reg == 0xFFFFFFFF || reg == 0)
262 break;
263 offset = reg - sfrdump->phy_reg;
264 if (reg < offset) {
265 pr_err("debug-snapshot: invalid address information - %s: 0x%08x\n",
266 sfrdump->name, reg);
267 break;
268 }
269 val = __raw_readl(sfrdump->reg + offset);
270 snprintf(buf, SZ_64, "0x%X = 0x%0X\n",reg, val);
271 size = (unsigned int)strlen(buf);
272 if (unlikely((dbg_snapshot_check_eob(item, size))))
273 item->curr_ptr = item->head_ptr;
274 memcpy(item->curr_ptr, buf, strlen(buf));
275 item->curr_ptr += strlen(buf);
276 }
277 of_node_put(np);
278 pr_info("debug-snapshot: complete to dump %s\n", sfrdump->name);
279 }
280
281}
282
283static int dbg_snapshot_sfr_dump_init(struct device_node *np)
284{
285 struct device_node *dump_np;
286 struct dbg_snapshot_sfrdump *sfrdump;
287 char *dump_str;
288 int count, ret, i;
289 u32 phy_regs[2];
290
291 ret = of_property_count_strings(np, "sfr-dump-list");
292 if (ret < 0) {
293 pr_err("failed to get sfr-dump-list\n");
294 return ret;
295 }
296 count = ret;
297
298 INIT_LIST_HEAD(&dss_desc.sfrdump_list);
299 for (i = 0; i < count; i++) {
300 ret = of_property_read_string_index(np, "sfr-dump-list", i,
301 (const char **)&dump_str);
302 if (ret < 0) {
303 pr_err("failed to get sfr-dump-list\n");
304 continue;
305 }
306
307 dump_np = of_get_child_by_name(np, dump_str);
308 if (!dump_np) {
309 pr_err("failed to get %s node, count:%d\n", dump_str, count);
310 continue;
311 }
312
313 sfrdump = kzalloc(sizeof(struct dbg_snapshot_sfrdump), GFP_KERNEL);
314 if (!sfrdump) {
315 pr_err("failed to get memory region of dbg_snapshot_sfrdump\n");
316 of_node_put(dump_np);
317 continue;
318 }
319
320 ret = of_property_read_u32_array(dump_np, "reg", phy_regs, 2);
321 if (ret < 0) {
322 pr_err("failed to get register information\n");
323 of_node_put(dump_np);
324 kfree(sfrdump);
325 continue;
326 }
327
328 sfrdump->reg = ioremap(phy_regs[0], phy_regs[1]);
329 if (!sfrdump->reg) {
330 pr_err("failed to get i/o address %s node\n", dump_str);
331 of_node_put(dump_np);
332 kfree(sfrdump);
333 continue;
334 }
335 sfrdump->name = dump_str;
336
337 ret = of_property_count_u32_elems(dump_np, "addr");
338 if (ret < 0) {
339 pr_err("failed to get addr count\n");
340 of_node_put(dump_np);
341 kfree(sfrdump);
342 continue;
343 }
344 sfrdump->phy_reg = phy_regs[0];
345 sfrdump->num = ret;
346
347 ret = of_property_count_u32_elems(dump_np, "cal-pd-id");
348 if (ret < 0)
349 sfrdump->pwr_mode = false;
350 else
351 sfrdump->pwr_mode = true;
352
353 sfrdump->node = dump_np;
354 list_add(&sfrdump->list, &dss_desc.sfrdump_list);
355
356 pr_info("success to regsiter %s\n", sfrdump->name);
357 of_node_put(dump_np);
358 ret = 0;
359 }
360 return ret;
361}
362#endif
363
364static int __init dbg_snapshot_remap(void)
365{
366 unsigned long i, j;
367 unsigned int enabled_count = 0;
368 pgprot_t prot = __pgprot(PROT_NORMAL_NC);
369 int page_size, ret;
370 struct page *page;
371 struct page **pages;
372
373 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
374 if (dss_items[i].entry.enabled) {
375 enabled_count++;
376 page_size = dss_items[i].entry.size / PAGE_SIZE;
377 pages = kzalloc(sizeof(struct page *) * page_size, GFP_KERNEL);
378 page = phys_to_page(dss_items[i].entry.paddr);
379
380 for (j = 0; j < page_size; j++)
381 pages[j] = page++;
382
383 ret = map_vm_area(&dss_items[i].vm, prot, pages);
384 kfree(pages);
385 if (ret) {
386 pr_err("debug-snapshot: failed to mapping between virt and phys");
387 return -ENOMEM;
388 }
389
390 dss_items[i].entry.vaddr = (size_t)dss_items[i].vm.addr;
391 dss_items[i].head_ptr = (unsigned char *)dss_items[i].entry.vaddr;
392 dss_items[i].curr_ptr = (unsigned char *)dss_items[i].entry.vaddr;
393 }
394 }
758cb36c 395 dss_desc.log_cnt = ARRAY_SIZE(dss_items);
dd101ca5
DC
396 return enabled_count;
397}
398
399static int __init dbg_snapshot_init_desc(void)
400{
401 unsigned int i, len;
402
403 /* initialize dss_desc */
404 memset((struct dbg_snapshot_desc *)&dss_desc, 0, sizeof(struct dbg_snapshot_desc));
405 dss_desc.callstack = CONFIG_DEBUG_SNAPSHOT_CALLSTACK;
406 raw_spin_lock_init(&dss_desc.ctrl_lock);
407 raw_spin_lock_init(&dss_desc.nmi_lock);
408
409 for (i = 0; i < (unsigned int)ARRAY_SIZE(dss_items); i++) {
410 len = strlen(dss_items[i].name);
411 if (!strncmp(dss_items[i].name, "header", len))
412 dss_desc.header_num = i;
413 else if (!strncmp(dss_items[i].name, "log_kevents", len))
414 dss_desc.kevents_num = i;
415 else if (!strncmp(dss_items[i].name, "log_kernel", len))
416 dss_desc.log_kernel_num = i;
417 else if (!strncmp(dss_items[i].name, "log_platform", len))
418 dss_desc.log_platform_num = i;
419 else if (!strncmp(dss_items[i].name, "log_sfr", len))
420 dss_desc.log_sfr_num = i;
421 else if (!strncmp(dss_items[i].name, "log_pstore", len))
422 dss_desc.log_pstore_num = i;
423 }
424
425#ifdef CONFIG_S3C2410_WATCHDOG
426 dss_desc.no_wdt_dev = false;
427#else
428 dss_desc.no_wdt_dev = true;
429#endif
430 return 0;
431}
432
433#ifdef CONFIG_OF_RESERVED_MEM
434static int __init dbg_snapshot_item_reserved_mem_setup(struct reserved_mem *remem)
435{
436 unsigned int i;
437
438 for (i = 0; i < (unsigned int)ARRAY_SIZE(dss_items); i++) {
439 if (strnstr(remem->name, dss_items[i].name, strlen(remem->name)))
440 break;
441 }
442
443 if (i == ARRAY_SIZE(dss_items))
444 return -ENODEV;
445
446 dss_items[i].entry.paddr = remem->base;
447 dss_items[i].entry.size = remem->size;
448 dss_items[i].entry.enabled = true;
449
450 dss_items[i].vm.phys_addr = remem->base;
451 dss_items[i].vm.addr = (void *)g_dbg_snapshot_vaddr_base;
452 dss_items[i].vm.size = remem->size;
453 dss_items[i].vm.flags = VM_NO_GUARD;
454 g_dbg_snapshot_vaddr_base += remem->size;
455
456 vm_area_add_early(&dss_items[i].vm);
457
458 if (strnstr(remem->name, "header", strlen(remem->name))) {
459 dss_base.paddr = remem->base;
460 dss_base.vaddr = (size_t)dss_items[i].vm.addr;
461 ess_base = dss_base;
462 dss_base.enabled = false;
463 }
464 dss_base.size += remem->size;
465 return 0;
466}
467
468#define DECLARE_DBG_SNAPSHOT_RESERVED_REGION(compat, name) \
469RESERVEDMEM_OF_DECLARE(name, compat#name, dbg_snapshot_item_reserved_mem_setup)
470
471DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", header);
472DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_kernel);
473DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_platform);
474DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_sfr);
475DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_s2d);
476DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_cachedump);
477DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_etm);
478DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_bcm);
479DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_pstore);
480DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_kevents);
481#endif
482
483/*
484 * ---------------------------------------------------------------------
485 * - dummy data:phy_addr, virtual_addr, buffer_size, magic_key(4K) -
486 * ---------------------------------------------------------------------
487 * - Cores MMU register(4K) -
488 * ---------------------------------------------------------------------
489 * - Cores CPU register(4K) -
490 * ---------------------------------------------------------------------
491 */
492static int __init dbg_snapshot_output(void)
493{
494 unsigned long i, size = 0;
495
496 pr_info("debug-snapshot physical / virtual memory layout:\n");
497 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
498 if (dss_items[i].entry.enabled)
499 pr_info("%-12s: phys:0x%zx / virt:0x%zx / size:0x%zx\n",
500 dss_items[i].name,
501 dss_items[i].entry.paddr,
502 dss_items[i].entry.vaddr,
503 dss_items[i].entry.size);
504 size += dss_items[i].entry.size;
505 }
506
507 pr_info("total_item_size: %ldKB, dbg_snapshot_log struct size: %dKB\n",
508 size / SZ_1K, dbg_snapshot_log_size / SZ_1K);
509
510 return 0;
511}
512
513/* Header dummy data(4K)
514 * -------------------------------------------------------------------------
515 * 0 4 8 C
516 * -------------------------------------------------------------------------
517 * 0 vaddr phy_addr size magic_code
518 * 4 Scratch_val logbuf_addr 0 0
519 * -------------------------------------------------------------------------
520*/
521
522static void __init dbg_snapshot_fixmap_header(void)
523{
524 /* fill 0 to next to header */
525 size_t vaddr, paddr, size;
526 size_t *addr;
527
528 vaddr = dss_items[dss_desc.header_num].entry.vaddr;
529 paddr = dss_items[dss_desc.header_num].entry.paddr;
530 size = dss_items[dss_desc.header_num].entry.size;
531
532 /* set to confirm debug-snapshot */
533 addr = (size_t *)vaddr;
534 memcpy(addr, &dss_base, sizeof(struct dbg_snapshot_base));
535
536 if (!dbg_snapshot_get_enable("header"))
537 return;
538
539 /* initialize kernel event to 0 except only header */
540 memset((size_t *)(vaddr + DSS_KEEP_HEADER_SZ), 0, size - DSS_KEEP_HEADER_SZ);
541}
542
543static void __init dbg_snapshot_fixmap(void)
544{
545 size_t last_buf;
546 size_t vaddr, paddr, size;
547 unsigned long i;
548
549 /* fixmap to header first */
550 dbg_snapshot_fixmap_header();
551
552 for (i = 1; i < ARRAY_SIZE(dss_items); i++) {
553 if (!dss_items[i].entry.enabled)
554 continue;
555
556 /* assign dss_item information */
557 paddr = dss_items[i].entry.paddr;
558 vaddr = dss_items[i].entry.vaddr;
559 size = dss_items[i].entry.size;
560
561 if (i == dss_desc.log_kernel_num) {
562 /* load last_buf address value(phy) by virt address */
563 last_buf = (size_t)__raw_readl(dbg_snapshot_get_base_vaddr() +
564 DSS_OFFSET_LAST_LOGBUF);
565 /* check physical address offset of kernel logbuf */
566 if (last_buf >= dss_items[i].entry.paddr &&
567 (last_buf) <= (dss_items[i].entry.paddr + dss_items[i].entry.size)) {
568 /* assumed valid address, conversion to virt */
569 dss_items[i].curr_ptr = (unsigned char *)(dss_items[i].entry.vaddr +
570 (last_buf - dss_items[i].entry.paddr));
571 } else {
572 /* invalid address, set to first line */
573 dss_items[i].curr_ptr = (unsigned char *)vaddr;
574 /* initialize logbuf to 0 */
575 memset((size_t *)vaddr, 0, size);
576 }
577 } else {
578 /* initialized log to 0 if persist == false */
579 if (!dss_items[i].entry.persist)
580 memset((size_t *)vaddr, 0, size);
581 }
582 dss_info.info_log[i - 1].name = kstrdup(dss_items[i].name, GFP_KERNEL);
583 dss_info.info_log[i - 1].head_ptr = (unsigned char *)dss_items[i].entry.vaddr;
584 dss_info.info_log[i - 1].curr_ptr = NULL;
585 dss_info.info_log[i - 1].entry.size = size;
586 }
587
588 dss_log = (struct dbg_snapshot_log *)(dss_items[dss_desc.kevents_num].entry.vaddr);
589
590 /* set fake translation to virtual address to debug trace */
591 dss_info.info_event = dss_log;
592 ess_info = &dss_info;
593
594 /* output the information of debug-snapshot */
595 dbg_snapshot_output();
596}
597
598static int dbg_snapshot_init_dt_parse(struct device_node *np)
599{
600 int ret = 0;
601 struct device_node *sfr_dump_np = of_get_child_by_name(np, "dump-info");
602
603 if (!sfr_dump_np) {
604 pr_err("debug-snapshot: failed to get dump-info node\n");
605 ret = -ENODEV;
606 } else {
607#ifdef CONFIG_DEBUG_SNAPSHOT_PMU
608 ret = dbg_snapshot_sfr_dump_init(sfr_dump_np);
609 if (ret < 0) {
610 pr_err("debug-snapshot: failed to register sfr dump node\n");
611 ret = -ENODEV;
612 of_node_put(sfr_dump_np);
613 }
614#endif
615 }
616 if (ret < 0)
617 dbg_snapshot_set_enable("log_sfr", false);
618
619 if (of_property_read_u32(np, "use_multistage_wdt_irq",
620 &dss_desc.multistage_wdt_irq)) {
621 dss_desc.multistage_wdt_irq = 0;
622 pr_err("debug-snapshot: no support multistage_wdt\n");
623 ret = -EINVAL;
624 }
625
626 of_node_put(np);
627 return ret;
628}
629
630static const struct of_device_id dss_of_match[] __initconst = {
631 { .compatible = "debug-snapshot-soc",
632 .data = dbg_snapshot_init_dt_parse},
633 {},
634};
635
636static int __init dbg_snapshot_init_dt(void)
637{
638 struct device_node *np;
639 const struct of_device_id *matched_np;
640 dss_initcall_t init_fn;
641
642 np = of_find_matching_node_and_match(NULL, dss_of_match, &matched_np);
643
644 if (!np) {
645 pr_info("debug-snapshot: couldn't find device tree file of debug-snapshot\n");
646 dbg_snapshot_set_enable("log_sfr", false);
647 return -ENODEV;
648 }
649
650 init_fn = (dss_initcall_t)matched_np->data;
651 return init_fn(np);
652}
653
654static int __init dbg_snapshot_init(void)
655{
656 dbg_snapshot_init_desc();
657 if (dbg_snapshot_remap() > 0) {
658 /*
659 * for debugging when we don't know the virtual address of pointer,
660 * In just privous the debug buffer, It is added 16byte dummy data.
661 * start address(dummy 16bytes)
662 * --> @virtual_addr | @phy_addr | @buffer_size | @magic_key(0xDBDBDBDB)
663 * And then, the debug buffer is shown.
664 */
665 dbg_snapshot_log_idx_init();
666 dbg_snapshot_fixmap();
667 dbg_snapshot_init_dt();
668 dbg_snapshot_helper_init();
669 dbg_snapshot_utils_init();
670
671 dbg_snapshot_scratch_reg(DSS_SIGN_SCRATCH);
672 dbg_snapshot_set_enable("base", true);
673
674 register_hook_logbuf(dbg_snapshot_hook_logbuf);
675 register_hook_logger(dbg_snapshot_hook_logger);
676 } else
677 pr_err("debug-snapshot: %s failed\n", __func__);
678
679 return 0;
680}
681early_initcall(dbg_snapshot_init);