[RAMEN9610-9428] debugfs: purge obsolete SRCU based removal protection
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / lib / debug-snapshot-pstore.c
CommitLineData
dd101ca5
DC
1/*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * Exynos-SnapShot debugging framework for Exynos SoC
6 *
7 * Author: Hosung Kim <Hosung0.kim@samsung.com>
8 *
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.
12 */
13
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>
24
25#include "debug-snapshot-local.h"
26#include <asm/irq.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>
35
36/* This defines are for PSTORE */
37#define DSS_LOGGER_LEVEL_HEADER (1)
38#define DSS_LOGGER_LEVEL_PREFIX (2)
39#define DSS_LOGGER_LEVEL_TEXT (3)
40#define DSS_LOGGER_LEVEL_MAX (4)
41#define DSS_LOGGER_SKIP_COUNT (4)
42#define DSS_LOGGER_STRING_PAD (1)
43#define DSS_LOGGER_HEADER_SIZE (68)
44
45#define DSS_LOG_ID_MAIN (0)
46#define DSS_LOG_ID_RADIO (1)
47#define DSS_LOG_ID_EVENTS (2)
48#define DSS_LOG_ID_SYSTEM (3)
49#define DSS_LOG_ID_CRASH (4)
50#define DSS_LOG_ID_KERNEL (5)
51
52typedef struct __attribute__((__packed__)) {
53 uint8_t magic;
54 uint16_t len;
55 uint16_t uid;
56 uint16_t pid;
57} dss_pmsg_log_header_t;
58
59typedef struct __attribute__((__packed__)) {
60 unsigned char id;
61 uint16_t tid;
62 int32_t tv_sec;
63 int32_t tv_nsec;
64} dss_android_log_header_t;
65
66typedef struct dss_logger {
67 uint16_t len;
68 uint16_t id;
69 uint16_t pid;
70 uint16_t tid;
71 uint16_t uid;
72 uint16_t level;
73 int32_t tv_sec;
74 int32_t tv_nsec;
75 char msg;
76 char *buffer;
77 void (*func_hook_logger)(const char*, const char*, size_t);
78} __attribute__((__packed__)) dss_logger;
79
80static dss_logger logger;
81
82void register_hook_logger(void (*func)(const char *name, const char *buf, size_t size))
83{
84 logger.func_hook_logger = func;
85 logger.buffer = vmalloc(PAGE_SIZE * 3);
86
87 if (logger.buffer)
88 pr_info("debug-snapshot: logger buffer alloc address: 0x%p\n", logger.buffer);
89}
90EXPORT_SYMBOL(register_hook_logger);
91
92static int dbg_snapshot_combine_pmsg(char *buffer, size_t count, unsigned int level)
93{
94 char *logbuf = logger.buffer;
95
96 if (!logbuf)
97 return -ENOMEM;
98
99 switch (level) {
100 case DSS_LOGGER_LEVEL_HEADER:
101 {
102 struct tm tmBuf;
103 u64 tv_kernel;
104 unsigned int logbuf_len;
105 unsigned long rem_nsec;
106
107 if (logger.id == DSS_LOG_ID_EVENTS)
108 break;
109
110 tv_kernel = local_clock();
111 rem_nsec = do_div(tv_kernel, 1000000000);
112 time_to_tm(logger.tv_sec, 0, &tmBuf);
113
114 logbuf_len = snprintf(logbuf, DSS_LOGGER_HEADER_SIZE,
115 "\n[%5lu.%06lu][%d:%16s] %02d-%02d %02d:%02d:%02d.%03d %5d %5d ",
116 (unsigned long)tv_kernel, rem_nsec / 1000,
117 raw_smp_processor_id(), current->comm,
118 tmBuf.tm_mon + 1, tmBuf.tm_mday,
119 tmBuf.tm_hour, tmBuf.tm_min, tmBuf.tm_sec,
120 logger.tv_nsec / 1000000, logger.pid, logger.tid);
121
122 logger.func_hook_logger("log_platform", logbuf, logbuf_len - 1);
123 }
124 break;
125 case DSS_LOGGER_LEVEL_PREFIX:
126 {
127 static const char *kPrioChars = "!.VDIWEFS";
128 unsigned char prio = logger.msg;
129
130 if (logger.id == DSS_LOG_ID_EVENTS)
131 break;
132
133 logbuf[0] = prio < strlen(kPrioChars) ? kPrioChars[prio] : '?';
134 logbuf[1] = ' ';
135
136 logger.func_hook_logger("log_platform", logbuf, DSS_LOGGER_LEVEL_PREFIX);
137 }
138 break;
139 case DSS_LOGGER_LEVEL_TEXT:
140 {
141 char *eatnl = buffer + count - DSS_LOGGER_STRING_PAD;
142
143 if (logger.id == DSS_LOG_ID_EVENTS)
144 break;
145 if (count == DSS_LOGGER_SKIP_COUNT && *eatnl != '\0')
146 break;
147
148 logger.func_hook_logger("log_platform", buffer, count - 1);
149 }
150 break;
151 default:
152 break;
153 }
154 return 0;
155}
156
157int dbg_snapshot_hook_pmsg(char *buffer, size_t count)
158{
159 dss_android_log_header_t header;
160 dss_pmsg_log_header_t pmsg_header;
161
162 if (!logger.buffer)
163 return -ENOMEM;
164
165 switch (count) {
166 case sizeof(pmsg_header):
167 memcpy((void *)&pmsg_header, buffer, count);
168 if (pmsg_header.magic != 'l') {
169 dbg_snapshot_combine_pmsg(buffer, count, DSS_LOGGER_LEVEL_TEXT);
170 } else {
171 /* save logger data */
172 logger.pid = pmsg_header.pid;
173 logger.uid = pmsg_header.uid;
174 logger.len = pmsg_header.len;
175 }
176 break;
177 case sizeof(header):
178 /* save logger data */
179 memcpy((void *)&header, buffer, count);
180 logger.id = header.id;
181 logger.tid = header.tid;
182 logger.tv_sec = header.tv_sec;
183 logger.tv_nsec = header.tv_nsec;
184 if (logger.id > 7) {
185 /* write string */
186 dbg_snapshot_combine_pmsg(buffer, count, DSS_LOGGER_LEVEL_TEXT);
187 } else {
188 /* write header */
189 dbg_snapshot_combine_pmsg(buffer, count, DSS_LOGGER_LEVEL_HEADER);
190 }
191 break;
192 case sizeof(unsigned char):
193 logger.msg = buffer[0];
194 /* write char for prefix */
195 dbg_snapshot_combine_pmsg(buffer, count, DSS_LOGGER_LEVEL_PREFIX);
196 break;
197 default:
198 /* write string */
199 dbg_snapshot_combine_pmsg(buffer, count, DSS_LOGGER_LEVEL_TEXT);
200 break;
201 }
202
203 return 0;
204}
205EXPORT_SYMBOL(dbg_snapshot_hook_pmsg);
206
207/*
208 * To support pstore/pmsg/pstore_ram, following is implementation for debug-snapshot
209 * dss_ramoops platform_device is used by pstore fs.
210 */
211
212static struct ramoops_platform_data dss_ramoops_data = {
213 .record_size = SZ_512K,
214 .console_size = SZ_512K,
215 .ftrace_size = SZ_512K,
216 .pmsg_size = SZ_512K,
217 .dump_oops = 1,
218};
219
220static struct platform_device dss_ramoops = {
221 .name = "ramoops",
222 .dev = {
223 .platform_data = &dss_ramoops_data,
224 },
225};
226
227static int __init dss_pstore_init(void)
228{
229 if (dbg_snapshot_get_enable("log_pstore")) {
230 dss_ramoops_data.mem_size = dbg_snapshot_get_item_size("log_pstore");
231 dss_ramoops_data.mem_address = dbg_snapshot_get_item_paddr("log_pstore");
232 }
233 return platform_device_register(&dss_ramoops);
234}
235
236static void __exit dss_pstore_exit(void)
237{
238 platform_device_unregister(&dss_ramoops);
239}
240module_init(dss_pstore_init);
241module_exit(dss_pstore_exit);
242
243MODULE_DESCRIPTION("Exynos Snapshot pstore module");
244MODULE_LICENSE("GPL");