mm: mm_event supports vmstat
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / lib / debug-snapshot.c
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.h>
26 #include <linux/of_fdt.h>
27 #include <linux/of_address.h>
28 #include <linux/of_reserved_mem.h>
29 #include <linux/sched/clock.h>
30
31 #include "debug-snapshot-local.h"
32
33 /* To Support Samsung SoC */
34 #include <dt-bindings/soc/samsung/debug-snapshot-table.h>
35 #ifdef CONFIG_DEBUG_SNAPSHOT_PMU
36 #include <soc/samsung/cal-if.h>
37 #endif
38
39 extern void register_hook_logbuf(void (*)(const char *, size_t));
40 extern void register_hook_logger(void (*)(const char *, const char *, size_t));
41
42 struct dbg_snapshot_interface {
43 struct dbg_snapshot_log *info_event;
44 struct dbg_snapshot_item info_log[DSS_ITEM_MAX_NUM];
45 };
46
47 #ifdef CONFIG_DEBUG_SNAPSHOT_PMU
48 struct dbg_snapshot_ops {
49 int (*pd_status)(unsigned int id);
50 };
51
52 struct dbg_snapshot_ops dss_ops = {
53 .pd_status = cal_pd_status,
54 };
55 #endif
56
57 const char *debug_level_val[] = {
58 "low",
59 "mid",
60 };
61
62 struct dbg_snapshot_bl *dss_bl;
63 struct dbg_snapshot_item dss_items[] = {
64 {"header", {0, 0, 0, false, false}, NULL ,NULL, 0, },
65 {"log_kernel", {0, 0, 0, false, false}, NULL ,NULL, 0, },
66 {"log_platform", {0, 0, 0, false, false}, NULL ,NULL, 0, },
67 {"log_sfr", {0, 0, 0, false, false}, NULL ,NULL, 0, },
68 {"log_s2d", {0, 0, 0, true, false}, NULL, NULL, 0, },
69 {"log_cachedump", {0, 0, 0, true, false}, NULL, NULL, 0, },
70 {"log_etm", {0, 0, 0, true, false}, NULL ,NULL, 0, },
71 {"log_bcm", {0, 0, 0, false, false}, NULL ,NULL, 0, },
72 {"log_pstore", {0, 0, 0, true, false}, NULL ,NULL, 0, },
73 {"log_kevents", {0, 0, 0, false, false}, NULL ,NULL, 0, },
74 };
75
76 /* External interface variable for trace debugging */
77 static struct dbg_snapshot_interface dss_info __attribute__ ((used));
78 static struct dbg_snapshot_interface *ess_info __attribute__ ((used));
79
80 struct dbg_snapshot_base dss_base;
81 struct dbg_snapshot_base ess_base;
82 struct dbg_snapshot_log *dss_log = NULL;
83 struct dbg_snapshot_desc dss_desc;
84
85 /* Variable for assigning virtual address base */
86 static size_t g_dbg_snapshot_vaddr_base = DSS_FIXED_VIRT_BASE;
87
88 int dbg_snapshot_get_debug_level(void)
89 {
90 return dss_desc.debug_level;
91 }
92
93 int dbg_snapshot_add_bl_item_info(const char *name, unsigned int paddr, unsigned int size)
94 {
95 if (dss_bl->item_count >= SZ_16)
96 return -1;
97
98 memcpy(dss_bl->item[dss_bl->item_count].name, name, strlen(name) + 1);
99 dss_bl->item[dss_bl->item_count].paddr = paddr;
100 dss_bl->item[dss_bl->item_count].size = size;
101 dss_bl->item[dss_bl->item_count].enabled = 1;
102 dss_bl->item_count++;
103
104 return 0;
105 }
106
107 int dbg_snapshot_set_enable(const char *name, int en)
108 {
109 struct dbg_snapshot_item *item = NULL;
110 unsigned long i;
111
112 if (!strncmp(name, "base", strlen(name))) {
113 dss_base.enabled = en;
114 pr_info("debug-snapshot: %sabled\n", en ? "en" : "dis");
115 } else {
116 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
117 if (!strncmp(dss_items[i].name, name, strlen(name))) {
118 item = &dss_items[i];
119 item->entry.enabled = en;
120 item->time = local_clock();
121 pr_info("debug-snapshot: item - %s is %sabled\n",
122 name, en ? "en" : "dis");
123 break;
124 }
125 }
126 }
127 return 0;
128 }
129 EXPORT_SYMBOL(dbg_snapshot_set_enable);
130
131 int dbg_snapshot_try_enable(const char *name, unsigned long long duration)
132 {
133 struct dbg_snapshot_item *item = NULL;
134 unsigned long long time;
135 unsigned long i;
136 int ret = -1;
137
138 /* If DSS was disabled, just return */
139 if (unlikely(!dss_base.enabled) || !dbg_snapshot_get_enable("header"))
140 return ret;
141
142 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
143 if (!strncmp(dss_items[i].name, name, strlen(name))) {
144 item = &dss_items[i];
145
146 /* We only interest in disabled */
147 if (!item->entry.enabled) {
148 time = local_clock() - item->time;
149 if (time > duration) {
150 item->entry.enabled = true;
151 ret = 1;
152 } else
153 ret = 0;
154 }
155 break;
156 }
157 }
158 return ret;
159 }
160 EXPORT_SYMBOL(dbg_snapshot_try_enable);
161
162 int dbg_snapshot_get_enable(const char *name)
163 {
164 struct dbg_snapshot_item *item = NULL;
165 unsigned long i;
166 int ret = 0;
167
168 if (!strncmp(name, "base", strlen(name)))
169 return dss_base.enabled;
170
171 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
172 if (!strncmp(dss_items[i].name, name, strlen(name))) {
173 item = &dss_items[i];
174 ret = item->entry.enabled;
175 break;
176 }
177 }
178 return ret;
179 }
180 EXPORT_SYMBOL(dbg_snapshot_get_enable);
181
182 static inline int dbg_snapshot_check_eob(struct dbg_snapshot_item *item,
183 size_t size)
184 {
185 size_t max, cur;
186
187 max = (size_t)(item->head_ptr + item->entry.size);
188 cur = (size_t)(item->curr_ptr + size);
189
190 if (unlikely(cur > max))
191 return -1;
192 else
193 return 0;
194 }
195
196 static inline void dbg_snapshot_hook_logger(const char *name,
197 const char *buf, size_t size)
198 {
199 struct dbg_snapshot_item *item = &dss_items[dss_desc.log_platform_num];
200
201 if (likely(dss_base.enabled && item->entry.enabled)) {
202 size_t last_buf;
203
204 if (unlikely((dbg_snapshot_check_eob(item, size))))
205 item->curr_ptr = item->head_ptr;
206
207 memcpy(item->curr_ptr, buf, size);
208 item->curr_ptr += size;
209 /* save the address of last_buf to physical address */
210 last_buf = (size_t)item->curr_ptr;
211
212 __raw_writel(item->entry.paddr + (last_buf - item->entry.vaddr),
213 dbg_snapshot_get_base_vaddr() + DSS_OFFSET_LAST_PLATFORM_LOGBUF);
214 }
215 }
216
217 static inline void dbg_snapshot_hook_logbuf(const char *buf, size_t size)
218 {
219 struct dbg_snapshot_item *item = &dss_items[dss_desc.log_kernel_num];
220
221 if (likely(dss_base.enabled && item->entry.enabled)) {
222 size_t last_buf;
223
224 if (dbg_snapshot_check_eob(item, size))
225 item->curr_ptr = item->head_ptr;
226
227 memcpy(item->curr_ptr, buf, size);
228 item->curr_ptr += size;
229 /* save the address of last_buf to physical address */
230 last_buf = (size_t)item->curr_ptr;
231
232 __raw_writel(item->entry.paddr + (last_buf - item->entry.vaddr),
233 dbg_snapshot_get_base_vaddr() + DSS_OFFSET_LAST_LOGBUF);
234 }
235 }
236
237 #ifdef CONFIG_DEBUG_SNAPSHOT_PMU
238 static bool dbg_snapshot_check_pmu(struct dbg_snapshot_sfrdump *sfrdump,
239 const struct device_node *np)
240 {
241 int ret = 0, count, i;
242 unsigned int val;
243
244 if (!sfrdump->pwr_mode)
245 return true;
246
247 count = of_property_count_u32_elems(np, "cal-pd-id");
248 for (i = 0; i < count; i++) {
249 ret = of_property_read_u32_index(np, "cal-pd-id", i, &val);
250 if (ret < 0) {
251 pr_err("failed to get pd-id - %s\n", sfrdump->name);
252 return false;
253 }
254 ret = dss_ops.pd_status(val);
255 if (ret < 0) {
256 pr_err("not powered - %s (pd-id: %d)\n", sfrdump->name, i);
257 return false;
258 }
259 }
260 return true;
261 }
262
263 void dbg_snapshot_dump_sfr(void)
264 {
265 struct dbg_snapshot_sfrdump *sfrdump;
266 struct dbg_snapshot_item *item = &dss_items[dss_desc.log_sfr_num];
267 struct list_head *entry;
268 struct device_node *np;
269 unsigned int reg, offset, val, size;
270 int i, ret;
271 static char buf[SZ_64];
272
273 if (unlikely(!dss_base.enabled || !item->entry.enabled))
274 return;
275
276 if (list_empty(&dss_desc.sfrdump_list)) {
277 pr_emerg("debug-snapshot: %s: No information\n", __func__);
278 return;
279 }
280
281 list_for_each(entry, &dss_desc.sfrdump_list) {
282 sfrdump = list_entry(entry, struct dbg_snapshot_sfrdump, list);
283 np = of_node_get(sfrdump->node);
284 ret = dbg_snapshot_check_pmu(sfrdump, np);
285 if (!ret)
286 /* may off */
287 continue;
288
289 for (i = 0; i < sfrdump->num; i++) {
290 ret = of_property_read_u32_index(np, "addr", i, &reg);
291 if (ret < 0) {
292 pr_err("debug-snapshot: failed to get address information - %s\n",
293 sfrdump->name);
294 break;
295 }
296 if (reg == 0xFFFFFFFF || reg == 0)
297 break;
298 offset = reg - sfrdump->phy_reg;
299 if (reg < offset) {
300 pr_err("debug-snapshot: invalid address information - %s: 0x%08x\n",
301 sfrdump->name, reg);
302 break;
303 }
304 val = __raw_readl(sfrdump->reg + offset);
305 snprintf(buf, SZ_64, "0x%X = 0x%0X\n",reg, val);
306 size = (unsigned int)strlen(buf);
307 if (unlikely((dbg_snapshot_check_eob(item, size))))
308 item->curr_ptr = item->head_ptr;
309 memcpy(item->curr_ptr, buf, strlen(buf));
310 item->curr_ptr += strlen(buf);
311 }
312 of_node_put(np);
313 pr_info("debug-snapshot: complete to dump %s\n", sfrdump->name);
314 }
315
316 }
317
318 static int dbg_snapshot_sfr_dump_init(struct device_node *np)
319 {
320 struct device_node *dump_np;
321 struct dbg_snapshot_sfrdump *sfrdump;
322 char *dump_str;
323 int count, ret, i;
324 u32 phy_regs[2];
325
326 ret = of_property_count_strings(np, "sfr-dump-list");
327 if (ret < 0) {
328 pr_err("failed to get sfr-dump-list\n");
329 return ret;
330 }
331 count = ret;
332
333 INIT_LIST_HEAD(&dss_desc.sfrdump_list);
334 for (i = 0; i < count; i++) {
335 ret = of_property_read_string_index(np, "sfr-dump-list", i,
336 (const char **)&dump_str);
337 if (ret < 0) {
338 pr_err("failed to get sfr-dump-list\n");
339 continue;
340 }
341
342 dump_np = of_get_child_by_name(np, dump_str);
343 if (!dump_np) {
344 pr_err("failed to get %s node, count:%d\n", dump_str, count);
345 continue;
346 }
347
348 sfrdump = kzalloc(sizeof(struct dbg_snapshot_sfrdump), GFP_KERNEL);
349 if (!sfrdump) {
350 pr_err("failed to get memory region of dbg_snapshot_sfrdump\n");
351 of_node_put(dump_np);
352 continue;
353 }
354
355 ret = of_property_read_u32_array(dump_np, "reg", phy_regs, 2);
356 if (ret < 0) {
357 pr_err("failed to get register information\n");
358 of_node_put(dump_np);
359 kfree(sfrdump);
360 continue;
361 }
362
363 sfrdump->reg = ioremap(phy_regs[0], phy_regs[1]);
364 if (!sfrdump->reg) {
365 pr_err("failed to get i/o address %s node\n", dump_str);
366 of_node_put(dump_np);
367 kfree(sfrdump);
368 continue;
369 }
370 sfrdump->name = dump_str;
371
372 ret = of_property_count_u32_elems(dump_np, "addr");
373 if (ret < 0) {
374 pr_err("failed to get addr count\n");
375 of_node_put(dump_np);
376 kfree(sfrdump);
377 continue;
378 }
379 sfrdump->phy_reg = phy_regs[0];
380 sfrdump->num = ret;
381
382 ret = of_property_count_u32_elems(dump_np, "cal-pd-id");
383 if (ret < 0)
384 sfrdump->pwr_mode = false;
385 else
386 sfrdump->pwr_mode = true;
387
388 sfrdump->node = dump_np;
389 list_add(&sfrdump->list, &dss_desc.sfrdump_list);
390
391 pr_info("success to regsiter %s\n", sfrdump->name);
392 of_node_put(dump_np);
393 ret = 0;
394 }
395 return ret;
396 }
397 #endif
398
399 static int __init dbg_snapshot_remap(void)
400 {
401 unsigned long i, j;
402 unsigned int enabled_count = 0;
403 pgprot_t prot = __pgprot(PROT_NORMAL_NC);
404 int page_size, ret;
405 struct page *page;
406 struct page **pages;
407
408 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
409 if (dss_items[i].entry.enabled) {
410 enabled_count++;
411 page_size = dss_items[i].entry.size / PAGE_SIZE;
412 pages = kzalloc(sizeof(struct page *) * page_size, GFP_KERNEL);
413 page = phys_to_page(dss_items[i].entry.paddr);
414
415 for (j = 0; j < page_size; j++)
416 pages[j] = page++;
417
418 ret = map_vm_area(&dss_items[i].vm, prot, pages);
419 kfree(pages);
420 if (ret) {
421 pr_err("debug-snapshot: failed to mapping between virt and phys");
422 return -ENOMEM;
423 }
424
425 dss_items[i].entry.vaddr = (size_t)dss_items[i].vm.addr;
426 dss_items[i].head_ptr = (unsigned char *)dss_items[i].entry.vaddr;
427 dss_items[i].curr_ptr = (unsigned char *)dss_items[i].entry.vaddr;
428 }
429 }
430 dss_desc.log_cnt = ARRAY_SIZE(dss_items);
431 return enabled_count;
432 }
433
434 static int __init dbg_snapshot_init_desc(void)
435 {
436 unsigned int i, len;
437
438 /* initialize dss_desc */
439 memset((struct dbg_snapshot_desc *)&dss_desc, 0, sizeof(struct dbg_snapshot_desc));
440 dss_desc.callstack = CONFIG_DEBUG_SNAPSHOT_CALLSTACK;
441 raw_spin_lock_init(&dss_desc.ctrl_lock);
442 raw_spin_lock_init(&dss_desc.nmi_lock);
443
444 for (i = 0; i < (unsigned int)ARRAY_SIZE(dss_items); i++) {
445 len = strlen(dss_items[i].name);
446 if (!strncmp(dss_items[i].name, "header", len))
447 dss_desc.header_num = i;
448 else if (!strncmp(dss_items[i].name, "log_kevents", len))
449 dss_desc.kevents_num = i;
450 else if (!strncmp(dss_items[i].name, "log_kernel", len))
451 dss_desc.log_kernel_num = i;
452 else if (!strncmp(dss_items[i].name, "log_platform", len))
453 dss_desc.log_platform_num = i;
454 else if (!strncmp(dss_items[i].name, "log_sfr", len))
455 dss_desc.log_sfr_num = i;
456 else if (!strncmp(dss_items[i].name, "log_pstore", len))
457 dss_desc.log_pstore_num = i;
458 }
459
460 #ifdef CONFIG_S3C2410_WATCHDOG
461 dss_desc.no_wdt_dev = false;
462 #else
463 dss_desc.no_wdt_dev = true;
464 #endif
465 return 0;
466 }
467
468 #ifdef CONFIG_OF_RESERVED_MEM
469 int __init dbg_snapshot_reserved_mem_check(unsigned long node, unsigned long size)
470 {
471 const char *name;
472 int ret = 0;
473
474 name = of_get_flat_dt_prop(node, "compatible", NULL);
475 if (!name)
476 goto out;
477
478 if (!strstr(name, "debug-snapshot"))
479 goto out;
480
481 if (!strstr(name, "log"))
482 goto out;
483
484 if (size == 0) {
485 ret = -EINVAL;
486 goto out;
487 }
488
489 #if !defined(CONFIG_DEBUG_SNAPSHOT_USER_MODE)
490 if (strstr(name, "user"))
491 ret = -EINVAL;
492 #else
493 if (!strstr(name, "user"))
494 ret = -EINVAL;
495 #endif
496 out:
497 return ret;
498 }
499
500 static int __init dbg_snapshot_item_reserved_mem_setup(struct reserved_mem *remem)
501 {
502 unsigned int i;
503
504 for (i = 0; i < (unsigned int)ARRAY_SIZE(dss_items); i++) {
505 if (strnstr(remem->name, dss_items[i].name, strlen(remem->name)))
506 break;
507 }
508
509 if (i == ARRAY_SIZE(dss_items))
510 return -ENODEV;
511
512 dss_items[i].entry.paddr = remem->base;
513 dss_items[i].entry.size = remem->size;
514 dss_items[i].entry.enabled = true;
515
516 dss_items[i].vm.phys_addr = remem->base;
517 dss_items[i].vm.addr = (void *)g_dbg_snapshot_vaddr_base;
518 dss_items[i].vm.size = remem->size;
519 dss_items[i].vm.flags = VM_NO_GUARD;
520 g_dbg_snapshot_vaddr_base += remem->size;
521
522 vm_area_add_early(&dss_items[i].vm);
523
524 if (strnstr(remem->name, "header", strlen(remem->name))) {
525 dss_base.paddr = remem->base;
526 dss_base.vaddr = (size_t)dss_items[i].vm.addr;
527 ess_base = dss_base;
528 dss_base.enabled = false;
529 }
530 dss_base.size += remem->size;
531 return 0;
532 }
533
534 #define DECLARE_DBG_SNAPSHOT_RESERVED_REGION(compat, name) \
535 RESERVEDMEM_OF_DECLARE(name, compat#name, dbg_snapshot_item_reserved_mem_setup)
536
537 #if !defined(CONFIG_DEBUG_SNAPSHOT_USER_MODE)
538 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", header);
539 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_kernel);
540 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_platform);
541 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_sfr);
542 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_s2d);
543 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_cachedump);
544 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_etm);
545 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_bcm);
546 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_pstore);
547 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_kevents);
548 #else
549 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", header);
550 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_kernel_user);
551 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_platform_user);
552 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_sfr_user);
553 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_s2d_user);
554 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_cachedump_user);
555 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_etm_user);
556 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_bcm_user);
557 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_pstore_user);
558 DECLARE_DBG_SNAPSHOT_RESERVED_REGION("debug-snapshot,", log_kevents_user);
559 #endif
560 #endif
561
562 /*
563 * ---------------------------------------------------------------------
564 * - dummy data:phy_addr, virtual_addr, buffer_size, magic_key(4K) -
565 * ---------------------------------------------------------------------
566 * - Cores MMU register(4K) -
567 * ---------------------------------------------------------------------
568 * - Cores CPU register(4K) -
569 * ---------------------------------------------------------------------
570 */
571 static int __init dbg_snapshot_output(void)
572 {
573 unsigned long i, size = 0;
574
575 pr_info("debug-snapshot physical / virtual memory layout:\n");
576 for (i = 0; i < ARRAY_SIZE(dss_items); i++) {
577 if (dss_items[i].entry.enabled)
578 pr_info("%-12s: phys:0x%zx / virt:0x%zx / size:0x%zx\n",
579 dss_items[i].name,
580 dss_items[i].entry.paddr,
581 dss_items[i].entry.vaddr,
582 dss_items[i].entry.size);
583 size += dss_items[i].entry.size;
584 }
585
586 pr_info("total_item_size: %ldKB, dbg_snapshot_log struct size: %dKB\n",
587 size / SZ_1K, dbg_snapshot_log_size / SZ_1K);
588
589 return 0;
590 }
591
592 /* Header dummy data(4K)
593 * -------------------------------------------------------------------------
594 * 0 4 8 C
595 * -------------------------------------------------------------------------
596 * 0 vaddr phy_addr size magic_code
597 * 4 Scratch_val logbuf_addr 0 0
598 * -------------------------------------------------------------------------
599 */
600
601 static void __init dbg_snapshot_fixmap_header(void)
602 {
603 /* fill 0 to next to header */
604 size_t vaddr, paddr, size;
605 size_t *addr;
606
607 vaddr = dss_items[dss_desc.header_num].entry.vaddr;
608 paddr = dss_items[dss_desc.header_num].entry.paddr;
609 size = dss_items[dss_desc.header_num].entry.size;
610
611 /* set to confirm debug-snapshot */
612 addr = (size_t *)vaddr;
613 memcpy(addr, &dss_base, sizeof(struct dbg_snapshot_base));
614
615 if (!dbg_snapshot_get_enable("header"))
616 return;
617
618 /* initialize kernel event to 0 except only header */
619 memset((size_t *)(vaddr + DSS_KEEP_HEADER_SZ), 0, size - DSS_KEEP_HEADER_SZ);
620
621 dss_bl = dbg_snapshot_get_base_vaddr() + DSS_OFFSET_ITEM_INFO;
622 memset(dss_bl, 0, sizeof(struct dbg_snapshot_bl));
623 dss_bl->magic1 = 0x01234567;
624 dss_bl->magic2 = 0x89ABCDEF;
625 dss_bl->item_count = ARRAY_SIZE(dss_items);
626 memcpy(dss_bl->item[dss_desc.header_num].name,
627 dss_items[dss_desc.header_num].name,
628 strlen(dss_items[dss_desc.header_num].name) + 1);
629 dss_bl->item[dss_desc.header_num].paddr = paddr;
630 dss_bl->item[dss_desc.header_num].size = size;
631 dss_bl->item[dss_desc.header_num].enabled =
632 dss_items[dss_desc.header_num].entry.enabled;
633 }
634
635 static void __init dbg_snapshot_fixmap(void)
636 {
637 size_t last_buf;
638 size_t vaddr, paddr, size;
639 unsigned long i;
640
641 /* fixmap to header first */
642 dbg_snapshot_fixmap_header();
643
644 for (i = 1; i < ARRAY_SIZE(dss_items); i++) {
645 memcpy(dss_bl->item[i].name,
646 dss_items[i].name,
647 strlen(dss_items[i].name) + 1);
648 dss_bl->item[i].enabled = dss_items[i].entry.enabled;
649
650 if (!dss_items[i].entry.enabled)
651 continue;
652
653 /* assign dss_item information */
654 paddr = dss_items[i].entry.paddr;
655 vaddr = dss_items[i].entry.vaddr;
656 size = dss_items[i].entry.size;
657
658 if (i == dss_desc.log_kernel_num) {
659 /* load last_buf address value(phy) by virt address */
660 last_buf = (size_t)__raw_readl(dbg_snapshot_get_base_vaddr() +
661 DSS_OFFSET_LAST_LOGBUF);
662 /* check physical address offset of kernel logbuf */
663 if (last_buf >= dss_items[i].entry.paddr &&
664 (last_buf) <= (dss_items[i].entry.paddr + dss_items[i].entry.size)) {
665 /* assumed valid address, conversion to virt */
666 dss_items[i].curr_ptr = (unsigned char *)(dss_items[i].entry.vaddr +
667 (last_buf - dss_items[i].entry.paddr));
668 } else {
669 /* invalid address, set to first line */
670 dss_items[i].curr_ptr = (unsigned char *)vaddr;
671 /* initialize logbuf to 0 */
672 memset((size_t *)vaddr, 0, size);
673 }
674 } else if (i == dss_desc.log_platform_num) {
675 last_buf = (size_t)__raw_readl(dbg_snapshot_get_base_vaddr() +
676 DSS_OFFSET_LAST_PLATFORM_LOGBUF);
677 if (last_buf >= dss_items[i].entry.vaddr &&
678 (last_buf) <= (dss_items[i].entry.vaddr + dss_items[i].entry.size)) {
679 dss_items[i].curr_ptr = (unsigned char *)(last_buf);
680 } else {
681 dss_items[i].curr_ptr = (unsigned char *)vaddr;
682 memset((size_t *)vaddr, 0, size);
683 }
684 } else {
685 /* initialized log to 0 if persist == false */
686 if (!dss_items[i].entry.persist)
687 memset((size_t *)vaddr, 0, size);
688 }
689 dss_info.info_log[i - 1].name = kstrdup(dss_items[i].name, GFP_KERNEL);
690 dss_info.info_log[i - 1].head_ptr = (unsigned char *)dss_items[i].entry.vaddr;
691 dss_info.info_log[i - 1].curr_ptr = NULL;
692 dss_info.info_log[i - 1].entry.size = size;
693
694 memcpy(dss_bl->item[i].name,
695 dss_items[i].name,
696 strlen(dss_items[i].name) + 1);
697 dss_bl->item[i].paddr = paddr;
698 dss_bl->item[i].size = size;
699 }
700
701 dss_log = (struct dbg_snapshot_log *)(dss_items[dss_desc.kevents_num].entry.vaddr);
702
703 /* set fake translation to virtual address to debug trace */
704 dss_info.info_event = dss_log;
705 ess_info = &dss_info;
706
707 /* output the information of debug-snapshot */
708 dbg_snapshot_output();
709 }
710
711 static int dbg_snapshot_init_dt_parse(struct device_node *np)
712 {
713 int ret = 0;
714 struct device_node *sfr_dump_np;
715
716 if (of_property_read_u32(np, "use_multistage_wdt_irq",
717 &dss_desc.multistage_wdt_irq)) {
718 dss_desc.multistage_wdt_irq = 0;
719 pr_err("debug-snapshot: no support multistage_wdt\n");
720 }
721
722 sfr_dump_np = of_get_child_by_name(np, "dump-info");
723 if (!sfr_dump_np) {
724 pr_err("debug-snapshot: failed to get dump-info node\n");
725 ret = -ENODEV;
726 } else {
727 #ifdef CONFIG_DEBUG_SNAPSHOT_PMU
728 ret = dbg_snapshot_sfr_dump_init(sfr_dump_np);
729 if (ret < 0) {
730 pr_err("debug-snapshot: failed to register sfr dump node\n");
731 ret = -ENODEV;
732 of_node_put(sfr_dump_np);
733 }
734 #endif
735 }
736 if (ret < 0)
737 dbg_snapshot_set_enable("log_sfr", false);
738
739 of_node_put(np);
740 return ret;
741 }
742
743 static const struct of_device_id dss_of_match[] __initconst = {
744 { .compatible = "debug-snapshot-soc",
745 .data = dbg_snapshot_init_dt_parse},
746 {},
747 };
748
749 static int __init dbg_snapshot_init_dt(void)
750 {
751 struct device_node *np;
752 const struct of_device_id *matched_np;
753 dss_initcall_t init_fn;
754
755 np = of_find_matching_node_and_match(NULL, dss_of_match, &matched_np);
756
757 if (!np) {
758 pr_info("debug-snapshot: couldn't find device tree file of debug-snapshot\n");
759 dbg_snapshot_set_enable("log_sfr", false);
760 return -ENODEV;
761 }
762
763 init_fn = (dss_initcall_t)matched_np->data;
764 return init_fn(np);
765 }
766
767 static int __init dbg_snapshot_init_value(void)
768 {
769 dss_desc.debug_level = dbg_snapshot_get_debug_level_reg();
770
771 pr_info("debug-snapshot: debug_level [%s]\n",
772 debug_level_val[dss_desc.debug_level]);
773
774 if (dss_desc.debug_level != DSS_DEBUG_LEVEL_LOW)
775 dbg_snapshot_scratch_reg(DSS_SIGN_SCRATCH);
776
777 /* copy linux_banner, physical address of
778 * kernel log / platform log / kevents to DSS header */
779 strncpy(dbg_snapshot_get_base_vaddr() + DSS_OFFSET_LINUX_BANNER,
780 linux_banner, strlen(linux_banner));
781
782 return 0;
783 }
784
785 static int __init dbg_snapshot_init(void)
786 {
787 dbg_snapshot_init_desc();
788 if (dbg_snapshot_remap() > 0) {
789 /*
790 * for debugging when we don't know the virtual address of pointer,
791 * In just privous the debug buffer, It is added 16byte dummy data.
792 * start address(dummy 16bytes)
793 * --> @virtual_addr | @phy_addr | @buffer_size | @magic_key(0xDBDBDBDB)
794 * And then, the debug buffer is shown.
795 */
796 dbg_snapshot_init_log_idx();
797 dbg_snapshot_fixmap();
798 dbg_snapshot_init_dt();
799 dbg_snapshot_init_helper();
800 dbg_snapshot_init_utils();
801 dbg_snapshot_init_value();
802
803 dbg_snapshot_set_enable("base", true);
804
805 register_hook_logbuf(dbg_snapshot_hook_logbuf);
806 register_hook_logger(dbg_snapshot_hook_logger);
807 } else
808 pr_err("debug-snapshot: %s failed\n", __func__);
809
810 return 0;
811 }
812 early_initcall(dbg_snapshot_init);