blob: bf598b756dc2523730eaf9fd52d7730777c0c0df [file] [log] [blame]
Eric Holmberg20b40662011-11-21 15:18:34 -07001/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13/*
14 * Shared memory logging implementation.
15 */
16
17#include <linux/slab.h>
18#include <linux/uaccess.h>
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/miscdevice.h>
22#include <linux/kernel.h>
23#include <linux/errno.h>
24#include <linux/jiffies.h>
25#include <linux/remote_spinlock.h>
26#include <linux/debugfs.h>
27#include <linux/io.h>
28#include <linux/string.h>
29#include <linux/sched.h>
30#include <linux/wait.h>
31#include <linux/delay.h>
32
33#include <mach/msm_iomap.h>
34#include <mach/smem_log.h>
35
36#include "smd_private.h"
37#include "smd_rpc_sym.h"
38#include "modem_notifier.h"
39
40#define DEBUG
41#undef DEBUG
42
43#ifdef DEBUG
44#define D_DUMP_BUFFER(prestr, cnt, buf) \
45do { \
46 int i; \
47 printk(KERN_ERR "%s", prestr); \
48 for (i = 0; i < cnt; i++) \
49 printk(KERN_ERR "%.2x", buf[i]); \
50 printk(KERN_ERR "\n"); \
51} while (0)
52#else
53#define D_DUMP_BUFFER(prestr, cnt, buf)
54#endif
55
56#ifdef DEBUG
57#define D(x...) printk(x)
58#else
59#define D(x...) do {} while (0)
60#endif
61
62#if defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60) \
63 || defined(CONFIG_ARCH_FSM9XXX)
64#define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x08)
65#else
66#define TIMESTAMP_ADDR (MSM_TMR_BASE + 0x04)
67#endif
68
69struct smem_log_item {
70 uint32_t identifier;
71 uint32_t timetick;
72 uint32_t data1;
73 uint32_t data2;
74 uint32_t data3;
75};
76
77#define SMEM_LOG_NUM_ENTRIES 2000
78#define SMEM_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
79 SMEM_LOG_NUM_ENTRIES)
80
81#define SMEM_LOG_NUM_STATIC_ENTRIES 150
82#define SMEM_STATIC_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
83 SMEM_LOG_NUM_STATIC_ENTRIES)
84
85#define SMEM_LOG_NUM_POWER_ENTRIES 2000
86#define SMEM_POWER_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
87 SMEM_LOG_NUM_POWER_ENTRIES)
88
89#define SMEM_SPINLOCK_SMEM_LOG "S:2"
90#define SMEM_SPINLOCK_STATIC_LOG "S:5"
91/* POWER shares with SMEM_SPINLOCK_SMEM_LOG */
92
93static remote_spinlock_t remote_spinlock;
94static remote_spinlock_t remote_spinlock_static;
95static uint32_t smem_log_enable;
96static int smem_log_initialized;
97
98module_param_named(log_enable, smem_log_enable, int,
99 S_IRUGO | S_IWUSR | S_IWGRP);
100
101
102struct smem_log_inst {
103 int which_log;
104 struct smem_log_item __iomem *events;
105 uint32_t __iomem *idx;
106 uint32_t num;
107 uint32_t read_idx;
108 uint32_t last_read_avail;
109 wait_queue_head_t read_wait;
110 remote_spinlock_t *remote_spinlock;
111};
112
113enum smem_logs {
114 GEN = 0,
115 STA,
116 POW,
117 NUM
118};
119
120static struct smem_log_inst inst[NUM];
121
122#if defined(CONFIG_DEBUG_FS)
123
124#define HSIZE 13
125
126struct sym {
127 uint32_t val;
128 char *str;
129 struct hlist_node node;
130};
131
132struct sym id_syms[] = {
133 { SMEM_LOG_PROC_ID_MODEM, "MODM" },
134 { SMEM_LOG_PROC_ID_Q6, "QDSP" },
135 { SMEM_LOG_PROC_ID_APPS, "APPS" },
Eric Holmberg20b40662011-11-21 15:18:34 -0700136 { SMEM_LOG_PROC_ID_WCNSS, "WCNSS" },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137};
138
139struct sym base_syms[] = {
140 { SMEM_LOG_ONCRPC_EVENT_BASE, "ONCRPC" },
141 { SMEM_LOG_SMEM_EVENT_BASE, "SMEM" },
142 { SMEM_LOG_TMC_EVENT_BASE, "TMC" },
143 { SMEM_LOG_TIMETICK_EVENT_BASE, "TIMETICK" },
144 { SMEM_LOG_DEM_EVENT_BASE, "DEM" },
145 { SMEM_LOG_ERROR_EVENT_BASE, "ERROR" },
146 { SMEM_LOG_DCVS_EVENT_BASE, "DCVS" },
147 { SMEM_LOG_SLEEP_EVENT_BASE, "SLEEP" },
148 { SMEM_LOG_RPC_ROUTER_EVENT_BASE, "ROUTER" },
149};
150
151struct sym event_syms[] = {
152#if defined(CONFIG_MSM_N_WAY_SMSM)
153 { DEM_SMSM_ISR, "SMSM_ISR" },
154 { DEM_STATE_CHANGE, "STATE_CHANGE" },
155 { DEM_STATE_MACHINE_ENTER, "STATE_MACHINE_ENTER" },
156 { DEM_ENTER_SLEEP, "ENTER_SLEEP" },
157 { DEM_END_SLEEP, "END_SLEEP" },
158 { DEM_SETUP_SLEEP, "SETUP_SLEEP" },
159 { DEM_SETUP_POWER_COLLAPSE, "SETUP_POWER_COLLAPSE" },
160 { DEM_SETUP_SUSPEND, "SETUP_SUSPEND" },
161 { DEM_EARLY_EXIT, "EARLY_EXIT" },
162 { DEM_WAKEUP_REASON, "WAKEUP_REASON" },
163 { DEM_DETECT_WAKEUP, "DETECT_WAKEUP" },
164 { DEM_DETECT_RESET, "DETECT_RESET" },
165 { DEM_DETECT_SLEEPEXIT, "DETECT_SLEEPEXIT" },
166 { DEM_DETECT_RUN, "DETECT_RUN" },
167 { DEM_APPS_SWFI, "APPS_SWFI" },
168 { DEM_SEND_WAKEUP, "SEND_WAKEUP" },
169 { DEM_ASSERT_OKTS, "ASSERT_OKTS" },
170 { DEM_NEGATE_OKTS, "NEGATE_OKTS" },
171 { DEM_PROC_COMM_CMD, "PROC_COMM_CMD" },
172 { DEM_REMOVE_PROC_PWR, "REMOVE_PROC_PWR" },
173 { DEM_RESTORE_PROC_PWR, "RESTORE_PROC_PWR" },
174 { DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" },
175 { DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" },
176 { DEM_MAO_INTS, "MAO_INTS" },
177 { DEM_APPS_WAKEUP_INT, "APPS_WAKEUP_INT" },
178 { DEM_PROC_WAKEUP, "PROC_WAKEUP" },
179 { DEM_PROC_POWERUP, "PROC_POWERUP" },
180 { DEM_TIMER_EXPIRED, "TIMER_EXPIRED" },
181 { DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" },
182 { DEM_REMOTE_PWR_CB, "REMOTE_PWR_CB" },
183 { DEM_TIME_SYNC_START, "TIME_SYNC_START" },
184 { DEM_TIME_SYNC_SEND_VALUE, "TIME_SYNC_SEND_VALUE" },
185 { DEM_TIME_SYNC_DONE, "TIME_SYNC_DONE" },
186 { DEM_TIME_SYNC_REQUEST, "TIME_SYNC_REQUEST" },
187 { DEM_TIME_SYNC_POLL, "TIME_SYNC_POLL" },
188 { DEM_TIME_SYNC_INIT, "TIME_SYNC_INIT" },
189 { DEM_INIT, "INIT" },
190#else
191
192 { DEM_NO_SLEEP, "NO_SLEEP" },
193 { DEM_INSUF_TIME, "INSUF_TIME" },
194 { DEMAPPS_ENTER_SLEEP, "APPS_ENTER_SLEEP" },
195 { DEMAPPS_DETECT_WAKEUP, "APPS_DETECT_WAKEUP" },
196 { DEMAPPS_END_APPS_TCXO, "APPS_END_APPS_TCXO" },
197 { DEMAPPS_ENTER_SLEEPEXIT, "APPS_ENTER_SLEEPEXIT" },
198 { DEMAPPS_END_APPS_SLEEP, "APPS_END_APPS_SLEEP" },
199 { DEMAPPS_SETUP_APPS_PWRCLPS, "APPS_SETUP_APPS_PWRCLPS" },
200 { DEMAPPS_PWRCLPS_EARLY_EXIT, "APPS_PWRCLPS_EARLY_EXIT" },
201 { DEMMOD_SEND_WAKEUP, "MOD_SEND_WAKEUP" },
202 { DEMMOD_NO_APPS_VOTE, "MOD_NO_APPS_VOTE" },
203 { DEMMOD_NO_TCXO_SLEEP, "MOD_NO_TCXO_SLEEP" },
204 { DEMMOD_BT_CLOCK, "MOD_BT_CLOCK" },
205 { DEMMOD_UART_CLOCK, "MOD_UART_CLOCK" },
206 { DEMMOD_OKTS, "MOD_OKTS" },
207 { DEM_SLEEP_INFO, "SLEEP_INFO" },
208 { DEMMOD_TCXO_END, "MOD_TCXO_END" },
209 { DEMMOD_END_SLEEP_SIG, "MOD_END_SLEEP_SIG" },
210 { DEMMOD_SETUP_APPSSLEEP, "MOD_SETUP_APPSSLEEP" },
211 { DEMMOD_ENTER_TCXO, "MOD_ENTER_TCXO" },
212 { DEMMOD_WAKE_APPS, "MOD_WAKE_APPS" },
213 { DEMMOD_POWER_COLLAPSE_APPS, "MOD_POWER_COLLAPSE_APPS" },
214 { DEMMOD_RESTORE_APPS_PWR, "MOD_RESTORE_APPS_PWR" },
215 { DEMAPPS_ASSERT_OKTS, "APPS_ASSERT_OKTS" },
216 { DEMAPPS_RESTART_START_TIMER, "APPS_RESTART_START_TIMER" },
217 { DEMAPPS_ENTER_RUN, "APPS_ENTER_RUN" },
218 { DEMMOD_MAO_INTS, "MOD_MAO_INTS" },
219 { DEMMOD_POWERUP_APPS_CALLED, "MOD_POWERUP_APPS_CALLED" },
220 { DEMMOD_PC_TIMER_EXPIRED, "MOD_PC_TIMER_EXPIRED" },
221 { DEM_DETECT_SLEEPEXIT, "_DETECT_SLEEPEXIT" },
222 { DEM_DETECT_RUN, "DETECT_RUN" },
223 { DEM_SET_APPS_TIMER, "SET_APPS_TIMER" },
224 { DEM_NEGATE_OKTS, "NEGATE_OKTS" },
225 { DEMMOD_APPS_WAKEUP_INT, "MOD_APPS_WAKEUP_INT" },
226 { DEMMOD_APPS_SWFI, "MOD_APPS_SWFI" },
227 { DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" },
228 { DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" },
229 { DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" },
230 { DEMAPPS_SETUP_APPS_SUSPEND, "APPS_SETUP_APPS_SUSPEND" },
231 { DEM_RPC_EARLY_EXIT, "RPC_EARLY_EXIT" },
232 { DEMAPPS_WAKEUP_REASON, "APPS_WAKEUP_REASON" },
233 { DEM_INIT, "INIT" },
234#endif
235 { DEMMOD_UMTS_BASE, "MOD_UMTS_BASE" },
236 { DEMMOD_GL1_GO_TO_SLEEP, "GL1_GO_TO_SLEEP" },
237 { DEMMOD_GL1_SLEEP_START, "GL1_SLEEP_START" },
238 { DEMMOD_GL1_AFTER_GSM_CLK_ON, "GL1_AFTER_GSM_CLK_ON" },
239 { DEMMOD_GL1_BEFORE_RF_ON, "GL1_BEFORE_RF_ON" },
240 { DEMMOD_GL1_AFTER_RF_ON, "GL1_AFTER_RF_ON" },
241 { DEMMOD_GL1_FRAME_TICK, "GL1_FRAME_TICK" },
242 { DEMMOD_GL1_WCDMA_START, "GL1_WCDMA_START" },
243 { DEMMOD_GL1_WCDMA_ENDING, "GL1_WCDMA_ENDING" },
244 { DEMMOD_UMTS_NOT_OKTS, "UMTS_NOT_OKTS" },
245 { DEMMOD_UMTS_START_TCXO_SHUTDOWN, "UMTS_START_TCXO_SHUTDOWN" },
246 { DEMMOD_UMTS_END_TCXO_SHUTDOWN, "UMTS_END_TCXO_SHUTDOWN" },
247 { DEMMOD_UMTS_START_ARM_HALT, "UMTS_START_ARM_HALT" },
248 { DEMMOD_UMTS_END_ARM_HALT, "UMTS_END_ARM_HALT" },
249 { DEMMOD_UMTS_NEXT_WAKEUP_SCLK, "UMTS_NEXT_WAKEUP_SCLK" },
250 { TIME_REMOTE_LOG_EVENT_START, "START" },
251 { TIME_REMOTE_LOG_EVENT_GOTO_WAIT,
252 "GOTO_WAIT" },
253 { TIME_REMOTE_LOG_EVENT_GOTO_INIT,
254 "GOTO_INIT" },
255 { ERR_ERROR_FATAL, "ERR_ERROR_FATAL" },
256 { ERR_ERROR_FATAL_TASK, "ERR_ERROR_FATAL_TASK" },
257 { DCVSAPPS_LOG_IDLE, "DCVSAPPS_LOG_IDLE" },
258 { DCVSAPPS_LOG_ERR, "DCVSAPPS_LOG_ERR" },
259 { DCVSAPPS_LOG_CHG, "DCVSAPPS_LOG_CHG" },
260 { DCVSAPPS_LOG_REG, "DCVSAPPS_LOG_REG" },
261 { DCVSAPPS_LOG_DEREG, "DCVSAPPS_LOG_DEREG" },
262 { SMEM_LOG_EVENT_CB, "CB" },
263 { SMEM_LOG_EVENT_START, "START" },
264 { SMEM_LOG_EVENT_INIT, "INIT" },
265 { SMEM_LOG_EVENT_RUNNING, "RUNNING" },
266 { SMEM_LOG_EVENT_STOP, "STOP" },
267 { SMEM_LOG_EVENT_RESTART, "RESTART" },
268 { SMEM_LOG_EVENT_SS, "SS" },
269 { SMEM_LOG_EVENT_READ, "READ" },
270 { SMEM_LOG_EVENT_WRITE, "WRITE" },
271 { SMEM_LOG_EVENT_SIGS1, "SIGS1" },
272 { SMEM_LOG_EVENT_SIGS2, "SIGS2" },
273 { SMEM_LOG_EVENT_WRITE_DM, "WRITE_DM" },
274 { SMEM_LOG_EVENT_READ_DM, "READ_DM" },
275 { SMEM_LOG_EVENT_SKIP_DM, "SKIP_DM" },
276 { SMEM_LOG_EVENT_STOP_DM, "STOP_DM" },
277 { SMEM_LOG_EVENT_ISR, "ISR" },
278 { SMEM_LOG_EVENT_TASK, "TASK" },
279 { SMEM_LOG_EVENT_RS, "RS" },
280 { ONCRPC_LOG_EVENT_SMD_WAIT, "SMD_WAIT" },
281 { ONCRPC_LOG_EVENT_RPC_WAIT, "RPC_WAIT" },
282 { ONCRPC_LOG_EVENT_RPC_BOTH_WAIT, "RPC_BOTH_WAIT" },
283 { ONCRPC_LOG_EVENT_RPC_INIT, "RPC_INIT" },
284 { ONCRPC_LOG_EVENT_RUNNING, "RUNNING" },
285 { ONCRPC_LOG_EVENT_APIS_INITED, "APIS_INITED" },
286 { ONCRPC_LOG_EVENT_AMSS_RESET, "AMSS_RESET" },
287 { ONCRPC_LOG_EVENT_SMD_RESET, "SMD_RESET" },
288 { ONCRPC_LOG_EVENT_ONCRPC_RESET, "ONCRPC_RESET" },
289 { ONCRPC_LOG_EVENT_CB, "CB" },
290 { ONCRPC_LOG_EVENT_STD_CALL, "STD_CALL" },
291 { ONCRPC_LOG_EVENT_STD_REPLY, "STD_REPLY" },
292 { ONCRPC_LOG_EVENT_STD_CALL_ASYNC, "STD_CALL_ASYNC" },
293 { NO_SLEEP_OLD, "NO_SLEEP_OLD" },
294 { INSUF_TIME, "INSUF_TIME" },
295 { MOD_UART_CLOCK, "MOD_UART_CLOCK" },
296 { SLEEP_INFO, "SLEEP_INFO" },
297 { MOD_TCXO_END, "MOD_TCXO_END" },
298 { MOD_ENTER_TCXO, "MOD_ENTER_TCXO" },
299 { NO_SLEEP_NEW, "NO_SLEEP_NEW" },
300 { RPC_ROUTER_LOG_EVENT_UNKNOWN, "UNKNOWN" },
301 { RPC_ROUTER_LOG_EVENT_MSG_READ, "MSG_READ" },
302 { RPC_ROUTER_LOG_EVENT_MSG_WRITTEN, "MSG_WRITTEN" },
303 { RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ, "MSG_CFM_REQ" },
304 { RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT, "MSG_CFM_SNT" },
305 { RPC_ROUTER_LOG_EVENT_MID_READ, "MID_READ" },
306 { RPC_ROUTER_LOG_EVENT_MID_WRITTEN, "MID_WRITTEN" },
307 { RPC_ROUTER_LOG_EVENT_MID_CFM_REQ, "MID_CFM_REQ" },
308};
309
310struct sym wakeup_syms[] = {
311 { 0x00000040, "OTHER" },
312 { 0x00000020, "RESET" },
313 { 0x00000010, "ALARM" },
314 { 0x00000008, "TIMER" },
315 { 0x00000004, "GPIO" },
316 { 0x00000002, "INT" },
317 { 0x00000001, "RPC" },
318 { 0x00000000, "NONE" },
319};
320
321struct sym wakeup_int_syms[] = {
322 { 0, "MDDI_EXT" },
323 { 1, "MDDI_PRI" },
324 { 2, "MDDI_CLIENT"},
325 { 3, "USB_OTG" },
326 { 4, "I2CC" },
327 { 5, "SDC1_0" },
328 { 6, "SDC1_1" },
329 { 7, "SDC2_0" },
330 { 8, "SDC2_1" },
331 { 9, "ADSP_A9A11" },
332 { 10, "UART1" },
333 { 11, "UART2" },
334 { 12, "UART3" },
335 { 13, "DP_RX_DATA" },
336 { 14, "DP_RX_DATA2" },
337 { 15, "DP_RX_DATA3" },
338 { 16, "DM_UART" },
339 { 17, "DM_DP_RX_DATA" },
340 { 18, "KEYSENSE" },
341 { 19, "HSSD" },
342 { 20, "NAND_WR_ER_DONE" },
343 { 21, "NAND_OP_DONE" },
344 { 22, "TCHSCRN1" },
345 { 23, "TCHSCRN2" },
346 { 24, "TCHSCRN_SSBI" },
347 { 25, "USB_HS" },
348 { 26, "UART2_DM_RX" },
349 { 27, "UART2_DM" },
350 { 28, "SDC4_1" },
351 { 29, "SDC4_0" },
352 { 30, "SDC3_1" },
353 { 31, "SDC3_0" },
354};
355
356struct sym smsm_syms[] = {
357 { 0x80000000, "UN" },
358 { 0x7F000000, "ERR" },
359 { 0x00800000, "SMLP" },
360 { 0x00400000, "ADWN" },
361 { 0x00200000, "PWRS" },
362 { 0x00100000, "DWLD" },
363 { 0x00080000, "SRBT" },
364 { 0x00040000, "SDWN" },
365 { 0x00020000, "ARBT" },
366 { 0x00010000, "REL" },
367 { 0x00008000, "SLE" },
368 { 0x00004000, "SLP" },
369 { 0x00002000, "WFPI" },
370 { 0x00001000, "EEX" },
371 { 0x00000800, "TIN" },
372 { 0x00000400, "TWT" },
373 { 0x00000200, "PWRC" },
374 { 0x00000100, "RUN" },
375 { 0x00000080, "SA" },
376 { 0x00000040, "RES" },
377 { 0x00000020, "RIN" },
378 { 0x00000010, "RWT" },
379 { 0x00000008, "SIN" },
380 { 0x00000004, "SWT" },
381 { 0x00000002, "OE" },
382 { 0x00000001, "I" },
383};
384
385/* never reorder */
386struct sym voter_d2_syms[] = {
387 { 0x00000001, NULL },
388 { 0x00000002, NULL },
389 { 0x00000004, NULL },
390 { 0x00000008, NULL },
391 { 0x00000010, NULL },
392 { 0x00000020, NULL },
393 { 0x00000040, NULL },
394 { 0x00000080, NULL },
395 { 0x00000100, NULL },
396 { 0x00000200, NULL },
397 { 0x00000400, NULL },
398 { 0x00000800, NULL },
399 { 0x00001000, NULL },
400 { 0x00002000, NULL },
401 { 0x00004000, NULL },
402 { 0x00008000, NULL },
403 { 0x00010000, NULL },
404 { 0x00020000, NULL },
405 { 0x00040000, NULL },
406 { 0x00080000, NULL },
407 { 0x00100000, NULL },
408 { 0x00200000, NULL },
409 { 0x00400000, NULL },
410 { 0x00800000, NULL },
411 { 0x01000000, NULL },
412 { 0x02000000, NULL },
413 { 0x04000000, NULL },
414 { 0x08000000, NULL },
415 { 0x10000000, NULL },
416 { 0x20000000, NULL },
417 { 0x40000000, NULL },
418 { 0x80000000, NULL },
419};
420
421/* never reorder */
422struct sym voter_d3_syms[] = {
423 { 0x00000001, NULL },
424 { 0x00000002, NULL },
425 { 0x00000004, NULL },
426 { 0x00000008, NULL },
427 { 0x00000010, NULL },
428 { 0x00000020, NULL },
429 { 0x00000040, NULL },
430 { 0x00000080, NULL },
431 { 0x00000100, NULL },
432 { 0x00000200, NULL },
433 { 0x00000400, NULL },
434 { 0x00000800, NULL },
435 { 0x00001000, NULL },
436 { 0x00002000, NULL },
437 { 0x00004000, NULL },
438 { 0x00008000, NULL },
439 { 0x00010000, NULL },
440 { 0x00020000, NULL },
441 { 0x00040000, NULL },
442 { 0x00080000, NULL },
443 { 0x00100000, NULL },
444 { 0x00200000, NULL },
445 { 0x00400000, NULL },
446 { 0x00800000, NULL },
447 { 0x01000000, NULL },
448 { 0x02000000, NULL },
449 { 0x04000000, NULL },
450 { 0x08000000, NULL },
451 { 0x10000000, NULL },
452 { 0x20000000, NULL },
453 { 0x40000000, NULL },
454 { 0x80000000, NULL },
455};
456
457struct sym dem_state_master_syms[] = {
458 { 0, "INIT" },
459 { 1, "RUN" },
460 { 2, "SLEEP_WAIT" },
461 { 3, "SLEEP_CONFIRMED" },
462 { 4, "SLEEP_EXIT" },
463 { 5, "RSA" },
464 { 6, "EARLY_EXIT" },
465 { 7, "RSA_DELAYED" },
466 { 8, "RSA_CHECK_INTS" },
467 { 9, "RSA_CONFIRMED" },
468 { 10, "RSA_WAKING" },
469 { 11, "RSA_RESTORE" },
470 { 12, "RESET" },
471};
472
473struct sym dem_state_slave_syms[] = {
474 { 0, "INIT" },
475 { 1, "RUN" },
476 { 2, "SLEEP_WAIT" },
477 { 3, "SLEEP_EXIT" },
478 { 4, "SLEEP_RUN_PENDING" },
479 { 5, "POWER_COLLAPSE" },
480 { 6, "CHECK_INTERRUPTS" },
481 { 7, "SWFI" },
482 { 8, "WFPI" },
483 { 9, "EARLY_EXIT" },
484 { 10, "RESET_RECOVER" },
485 { 11, "RESET_ACKNOWLEDGE" },
486 { 12, "ERROR" },
487};
488
489struct sym smsm_entry_type_syms[] = {
490 { 0, "SMSM_APPS_STATE" },
491 { 1, "SMSM_MODEM_STATE" },
492 { 2, "SMSM_Q6_STATE" },
493 { 3, "SMSM_APPS_DEM" },
494 { 4, "SMSM_MODEM_DEM" },
495 { 5, "SMSM_Q6_DEM" },
496 { 6, "SMSM_POWER_MASTER_DEM" },
497 { 7, "SMSM_TIME_MASTER_DEM" },
498};
499
500struct sym smsm_state_syms[] = {
501 { 0x00000001, "INIT" },
502 { 0x00000002, "OSENTERED" },
503 { 0x00000004, "SMDWAIT" },
504 { 0x00000008, "SMDINIT" },
505 { 0x00000010, "RPCWAIT" },
506 { 0x00000020, "RPCINIT" },
507 { 0x00000040, "RESET" },
508 { 0x00000080, "RSA" },
509 { 0x00000100, "RUN" },
510 { 0x00000200, "PWRC" },
511 { 0x00000400, "TIMEWAIT" },
512 { 0x00000800, "TIMEINIT" },
513 { 0x00001000, "PWRC_EARLY_EXIT" },
514 { 0x00002000, "WFPI" },
515 { 0x00004000, "SLEEP" },
516 { 0x00008000, "SLEEPEXIT" },
517 { 0x00010000, "OEMSBL_RELEASE" },
518 { 0x00020000, "APPS_REBOOT" },
519 { 0x00040000, "SYSTEM_POWER_DOWN" },
520 { 0x00080000, "SYSTEM_REBOOT" },
521 { 0x00100000, "SYSTEM_DOWNLOAD" },
522 { 0x00200000, "PWRC_SUSPEND" },
523 { 0x00400000, "APPS_SHUTDOWN" },
524 { 0x00800000, "SMD_LOOPBACK" },
525 { 0x01000000, "RUN_QUIET" },
526 { 0x02000000, "MODEM_WAIT" },
527 { 0x04000000, "MODEM_BREAK" },
528 { 0x08000000, "MODEM_CONTINUE" },
529 { 0x80000000, "UNKNOWN" },
530};
531
532#define ID_SYM 0
533#define BASE_SYM 1
534#define EVENT_SYM 2
535#define WAKEUP_SYM 3
536#define WAKEUP_INT_SYM 4
537#define SMSM_SYM 5
538#define VOTER_D2_SYM 6
539#define VOTER_D3_SYM 7
540#define DEM_STATE_MASTER_SYM 8
541#define DEM_STATE_SLAVE_SYM 9
542#define SMSM_ENTRY_TYPE_SYM 10
543#define SMSM_STATE_SYM 11
544
545static struct sym_tbl {
546 struct sym *data;
547 int size;
548 struct hlist_head hlist[HSIZE];
549} tbl[] = {
550 { id_syms, ARRAY_SIZE(id_syms) },
551 { base_syms, ARRAY_SIZE(base_syms) },
552 { event_syms, ARRAY_SIZE(event_syms) },
553 { wakeup_syms, ARRAY_SIZE(wakeup_syms) },
554 { wakeup_int_syms, ARRAY_SIZE(wakeup_int_syms) },
555 { smsm_syms, ARRAY_SIZE(smsm_syms) },
556 { voter_d2_syms, ARRAY_SIZE(voter_d2_syms) },
557 { voter_d3_syms, ARRAY_SIZE(voter_d3_syms) },
558 { dem_state_master_syms, ARRAY_SIZE(dem_state_master_syms) },
559 { dem_state_slave_syms, ARRAY_SIZE(dem_state_slave_syms) },
560 { smsm_entry_type_syms, ARRAY_SIZE(smsm_entry_type_syms) },
561 { smsm_state_syms, ARRAY_SIZE(smsm_state_syms) },
562};
563
564static void find_voters(void)
565{
566 void *x, *next;
567 unsigned size;
568 int i = 0, j = 0;
569
570 x = smem_get_entry(SMEM_SLEEP_STATIC, &size);
571 next = x;
572 while (next && (next < (x + size)) &&
573 ((i + j) < (ARRAY_SIZE(voter_d3_syms) +
574 ARRAY_SIZE(voter_d2_syms)))) {
575
576 if (i < ARRAY_SIZE(voter_d3_syms)) {
577 voter_d3_syms[i].str = (char *) next;
578 i++;
579 } else if (i >= ARRAY_SIZE(voter_d3_syms) &&
580 j < ARRAY_SIZE(voter_d2_syms)) {
581 voter_d2_syms[j].str = (char *) next;
582 j++;
583 }
584
585 next += 9;
586 }
587}
588
589#define hash(val) (val % HSIZE)
590
591static void init_syms(void)
592{
593 int i;
594 int j;
595
596 for (i = 0; i < ARRAY_SIZE(tbl); ++i)
597 for (j = 0; j < HSIZE; ++j)
598 INIT_HLIST_HEAD(&tbl[i].hlist[j]);
599
600 for (i = 0; i < ARRAY_SIZE(tbl); ++i)
601 for (j = 0; j < tbl[i].size; ++j) {
602 INIT_HLIST_NODE(&tbl[i].data[j].node);
603 hlist_add_head(&tbl[i].data[j].node,
604 &tbl[i].hlist[hash(tbl[i].data[j].val)]);
605 }
606}
607
608static char *find_sym(uint32_t id, uint32_t val)
609{
610 struct hlist_node *n;
611 struct sym *s;
612
613 hlist_for_each(n, &tbl[id].hlist[hash(val)]) {
614 s = hlist_entry(n, struct sym, node);
615 if (s->val == val)
616 return s->str;
617 }
618
619 return 0;
620}
621
622#else
623static void init_syms(void) {}
624#endif
625
626static inline unsigned int read_timestamp(void)
627{
628 unsigned int tick = 0;
629
630 /* no barriers necessary as the read value is a dependency for the
631 * comparison operation so the processor shouldn't be able to
632 * reorder things
633 */
634 do {
635 tick = __raw_readl(TIMESTAMP_ADDR);
636 } while (tick != __raw_readl(TIMESTAMP_ADDR));
637
638 return tick;
639}
640
641static void smem_log_event_from_user(struct smem_log_inst *inst,
642 const char __user *buf, int size, int num)
643{
644 uint32_t idx;
645 uint32_t next_idx;
646 unsigned long flags;
647 uint32_t identifier = 0;
648 uint32_t timetick = 0;
649 int first = 1;
650 int ret;
651
652 remote_spin_lock_irqsave(inst->remote_spinlock, flags);
653
654 while (num--) {
655 idx = *inst->idx;
656
657 if (idx < inst->num) {
658 ret = copy_from_user(&inst->events[idx],
659 buf, size);
660 if (ret) {
661 printk("ERROR %s:%i tried to write "
662 "%i got ret %i",
663 __func__, __LINE__,
664 size, size - ret);
665 goto out;
666 }
667
668 if (first) {
669 identifier =
670 inst->events[idx].
671 identifier;
672 timetick = read_timestamp();
673 first = 0;
674 } else {
675 identifier |= SMEM_LOG_CONT;
676 }
677 inst->events[idx].identifier =
678 identifier;
679 inst->events[idx].timetick =
680 timetick;
681 }
682
683 next_idx = idx + 1;
684 if (next_idx >= inst->num)
685 next_idx = 0;
686 *inst->idx = next_idx;
687 buf += sizeof(struct smem_log_item);
688 }
689
690 out:
691 wmb();
692 remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
693}
694
695static void _smem_log_event(
696 struct smem_log_item __iomem *events,
697 uint32_t __iomem *_idx,
698 remote_spinlock_t *lock,
699 int num,
700 uint32_t id, uint32_t data1, uint32_t data2,
701 uint32_t data3)
702{
703 struct smem_log_item item;
704 uint32_t idx;
705 uint32_t next_idx;
706 unsigned long flags;
707
708 item.timetick = read_timestamp();
709 item.identifier = id;
710 item.data1 = data1;
711 item.data2 = data2;
712 item.data3 = data3;
713
714 remote_spin_lock_irqsave(lock, flags);
715
716 idx = *_idx;
717
718 if (idx < num) {
719 memcpy(&events[idx],
720 &item, sizeof(item));
721 }
722
723 next_idx = idx + 1;
724 if (next_idx >= num)
725 next_idx = 0;
726 *_idx = next_idx;
727 wmb();
728
729 remote_spin_unlock_irqrestore(lock, flags);
730}
731
732static void _smem_log_event6(
733 struct smem_log_item __iomem *events,
734 uint32_t __iomem *_idx,
735 remote_spinlock_t *lock,
736 int num,
737 uint32_t id, uint32_t data1, uint32_t data2,
738 uint32_t data3, uint32_t data4, uint32_t data5,
739 uint32_t data6)
740{
741 struct smem_log_item item[2];
742 uint32_t idx;
743 uint32_t next_idx;
744 unsigned long flags;
745
746 item[0].timetick = read_timestamp();
747 item[0].identifier = id;
748 item[0].data1 = data1;
749 item[0].data2 = data2;
750 item[0].data3 = data3;
751 item[1].identifier = item[0].identifier;
752 item[1].timetick = item[0].timetick;
753 item[1].data1 = data4;
754 item[1].data2 = data5;
755 item[1].data3 = data6;
756
757 remote_spin_lock_irqsave(lock, flags);
758
759 idx = *_idx;
760
761 /* FIXME: Wrap around */
762 if (idx < (num-1)) {
763 memcpy(&events[idx],
764 &item, sizeof(item));
765 }
766
767 next_idx = idx + 2;
768 if (next_idx >= num)
769 next_idx = 0;
770 *_idx = next_idx;
771
772 wmb();
773 remote_spin_unlock_irqrestore(lock, flags);
774}
775
776void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
777 uint32_t data3)
778{
779 if (smem_log_enable)
780 _smem_log_event(inst[GEN].events, inst[GEN].idx,
781 inst[GEN].remote_spinlock,
782 SMEM_LOG_NUM_ENTRIES, id,
783 data1, data2, data3);
784}
785
786void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
787 uint32_t data3, uint32_t data4, uint32_t data5,
788 uint32_t data6)
789{
790 if (smem_log_enable)
791 _smem_log_event6(inst[GEN].events, inst[GEN].idx,
792 inst[GEN].remote_spinlock,
793 SMEM_LOG_NUM_ENTRIES, id,
794 data1, data2, data3, data4, data5, data6);
795}
796
797void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
798 uint32_t data3)
799{
800 if (smem_log_enable)
801 _smem_log_event(inst[STA].events, inst[STA].idx,
802 inst[STA].remote_spinlock,
803 SMEM_LOG_NUM_STATIC_ENTRIES, id,
804 data1, data2, data3);
805}
806
807void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
808 uint32_t data3, uint32_t data4, uint32_t data5,
809 uint32_t data6)
810{
811 if (smem_log_enable)
812 _smem_log_event6(inst[STA].events, inst[STA].idx,
813 inst[STA].remote_spinlock,
814 SMEM_LOG_NUM_STATIC_ENTRIES, id,
815 data1, data2, data3, data4, data5, data6);
816}
817
818static int _smem_log_init(void)
819{
820 int ret;
821
822 inst[GEN].which_log = GEN;
823 inst[GEN].events =
824 (struct smem_log_item *)smem_alloc(SMEM_SMEM_LOG_EVENTS,
825 SMEM_LOG_EVENTS_SIZE);
826 inst[GEN].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_IDX,
827 sizeof(uint32_t));
828 if (!inst[GEN].events || !inst[GEN].idx)
829 pr_info("%s: no log or log_idx allocated\n", __func__);
830
831 inst[GEN].num = SMEM_LOG_NUM_ENTRIES;
832 inst[GEN].read_idx = 0;
833 inst[GEN].last_read_avail = SMEM_LOG_NUM_ENTRIES;
834 init_waitqueue_head(&inst[GEN].read_wait);
835 inst[GEN].remote_spinlock = &remote_spinlock;
836
837 inst[STA].which_log = STA;
838 inst[STA].events =
839 (struct smem_log_item *)
840 smem_alloc(SMEM_SMEM_STATIC_LOG_EVENTS,
841 SMEM_STATIC_LOG_EVENTS_SIZE);
842 inst[STA].idx = (uint32_t *)smem_alloc(SMEM_SMEM_STATIC_LOG_IDX,
843 sizeof(uint32_t));
844 if (!inst[STA].events || !inst[STA].idx)
845 pr_info("%s: no static log or log_idx allocated\n", __func__);
846
847 inst[STA].num = SMEM_LOG_NUM_STATIC_ENTRIES;
848 inst[STA].read_idx = 0;
849 inst[STA].last_read_avail = SMEM_LOG_NUM_ENTRIES;
850 init_waitqueue_head(&inst[STA].read_wait);
851 inst[STA].remote_spinlock = &remote_spinlock_static;
852
853 inst[POW].which_log = POW;
854 inst[POW].events =
855 (struct smem_log_item *)
856 smem_alloc(SMEM_SMEM_LOG_POWER_EVENTS,
857 SMEM_POWER_LOG_EVENTS_SIZE);
858 inst[POW].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_POWER_IDX,
859 sizeof(uint32_t));
860 if (!inst[POW].events || !inst[POW].idx)
861 pr_info("%s: no power log or log_idx allocated\n", __func__);
862
863 inst[POW].num = SMEM_LOG_NUM_POWER_ENTRIES;
864 inst[POW].read_idx = 0;
865 inst[POW].last_read_avail = SMEM_LOG_NUM_ENTRIES;
866 init_waitqueue_head(&inst[POW].read_wait);
867 inst[POW].remote_spinlock = &remote_spinlock;
868
869 ret = remote_spin_lock_init(&remote_spinlock,
870 SMEM_SPINLOCK_SMEM_LOG);
871 if (ret) {
872 mb();
873 return ret;
874 }
875
876 ret = remote_spin_lock_init(&remote_spinlock_static,
877 SMEM_SPINLOCK_STATIC_LOG);
878 if (ret) {
879 mb();
880 return ret;
881 }
882
883 init_syms();
884 mb();
885
886 return 0;
887}
888
889static ssize_t smem_log_read_bin(struct file *fp, char __user *buf,
890 size_t count, loff_t *pos)
891{
892 int idx;
893 int orig_idx;
894 unsigned long flags;
895 int ret;
896 int tot_bytes = 0;
Eric Holmbergcf065312011-09-09 14:00:40 -0600897 struct smem_log_inst *local_inst;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898
Eric Holmbergcf065312011-09-09 14:00:40 -0600899 local_inst = fp->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900
Eric Holmbergcf065312011-09-09 14:00:40 -0600901 remote_spin_lock_irqsave(local_inst->remote_spinlock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902
Eric Holmbergcf065312011-09-09 14:00:40 -0600903 orig_idx = *local_inst->idx;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904 idx = orig_idx;
905
906 while (1) {
907 idx--;
908 if (idx < 0)
Eric Holmbergcf065312011-09-09 14:00:40 -0600909 idx = local_inst->num - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 if (idx == orig_idx) {
911 ret = tot_bytes;
912 break;
913 }
914
915 if ((tot_bytes + sizeof(struct smem_log_item)) > count) {
916 ret = tot_bytes;
917 break;
918 }
919
Eric Holmbergcf065312011-09-09 14:00:40 -0600920 ret = copy_to_user(buf, &local_inst->events[idx],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921 sizeof(struct smem_log_item));
922 if (ret) {
923 ret = -EIO;
924 break;
925 }
926
927 tot_bytes += sizeof(struct smem_log_item);
928
929 buf += sizeof(struct smem_log_item);
930 }
931
Eric Holmbergcf065312011-09-09 14:00:40 -0600932 remote_spin_unlock_irqrestore(local_inst->remote_spinlock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933
934 return ret;
935}
936
937static ssize_t smem_log_read(struct file *fp, char __user *buf,
938 size_t count, loff_t *pos)
939{
940 char loc_buf[128];
941 int i;
942 int idx;
943 int orig_idx;
944 unsigned long flags;
945 int ret;
946 int tot_bytes = 0;
947 struct smem_log_inst *inst;
948
949 inst = fp->private_data;
950
951 remote_spin_lock_irqsave(inst->remote_spinlock, flags);
952
953 orig_idx = *inst->idx;
954 idx = orig_idx;
955
956 while (1) {
957 idx--;
958 if (idx < 0)
959 idx = inst->num - 1;
960 if (idx == orig_idx) {
961 ret = tot_bytes;
962 break;
963 }
964
965 i = scnprintf(loc_buf, 128,
966 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
967 inst->events[idx].identifier,
968 inst->events[idx].timetick,
969 inst->events[idx].data1,
970 inst->events[idx].data2,
971 inst->events[idx].data3);
972 if (i == 0) {
973 ret = -EIO;
974 break;
975 }
976
977 if ((tot_bytes + i) > count) {
978 ret = tot_bytes;
979 break;
980 }
981
982 tot_bytes += i;
983
984 ret = copy_to_user(buf, loc_buf, i);
985 if (ret) {
986 ret = -EIO;
987 break;
988 }
989
990 buf += i;
991 }
992
993 remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
994
995 return ret;
996}
997
998static ssize_t smem_log_write_bin(struct file *fp, const char __user *buf,
999 size_t count, loff_t *pos)
1000{
1001 if (count < sizeof(struct smem_log_item))
1002 return -EINVAL;
1003
1004 if (smem_log_enable)
1005 smem_log_event_from_user(fp->private_data, buf,
1006 sizeof(struct smem_log_item),
1007 count / sizeof(struct smem_log_item));
1008 return count;
1009}
1010
1011static ssize_t smem_log_write(struct file *fp, const char __user *buf,
1012 size_t count, loff_t *pos)
1013{
1014 int ret;
1015 const char delimiters[] = " ,;";
1016 char locbuf[256] = {0};
1017 uint32_t val[10] = {0};
1018 int vals = 0;
1019 char *token;
1020 char *running;
1021 struct smem_log_inst *inst;
1022 unsigned long res;
1023
1024 inst = fp->private_data;
1025
1026 count = count > 255 ? 255 : count;
1027
1028 if (!smem_log_enable)
1029 return count;
1030
1031 locbuf[count] = '\0';
1032
1033 ret = copy_from_user(locbuf, buf, count);
1034 if (ret != 0) {
1035 printk(KERN_ERR "ERROR: %s could not copy %i bytes\n",
1036 __func__, ret);
1037 return -EINVAL;
1038 }
1039
1040 D(KERN_ERR "%s: ", __func__);
1041 D_DUMP_BUFFER("We got", len, locbuf);
1042
1043 running = locbuf;
1044
1045 token = strsep(&running, delimiters);
1046 while (token && vals < ARRAY_SIZE(val)) {
1047 if (*token != '\0') {
1048 D(KERN_ERR "%s: ", __func__);
1049 D_DUMP_BUFFER("", strlen(token), token);
1050 ret = strict_strtoul(token, 0, &res);
1051 if (ret) {
1052 printk(KERN_ERR "ERROR: %s:%i got bad char "
1053 "at strict_strtoul\n",
1054 __func__, __LINE__-4);
1055 return -EINVAL;
1056 }
1057 val[vals++] = res;
1058 }
1059 token = strsep(&running, delimiters);
1060 }
1061
1062 if (vals > 5) {
1063 if (inst->which_log == GEN)
1064 smem_log_event6(val[0], val[2], val[3], val[4],
1065 val[7], val[8], val[9]);
1066 else if (inst->which_log == STA)
1067 smem_log_event6_to_static(val[0],
1068 val[2], val[3], val[4],
1069 val[7], val[8], val[9]);
1070 else
1071 return -1;
1072 } else {
1073 if (inst->which_log == GEN)
1074 smem_log_event(val[0], val[2], val[3], val[4]);
1075 else if (inst->which_log == STA)
1076 smem_log_event_to_static(val[0],
1077 val[2], val[3], val[4]);
1078 else
1079 return -1;
1080 }
1081
1082 return count;
1083}
1084
1085static int smem_log_open(struct inode *ip, struct file *fp)
1086{
1087 fp->private_data = &inst[GEN];
1088
1089 return 0;
1090}
1091
1092
1093static int smem_log_release(struct inode *ip, struct file *fp)
1094{
1095 return 0;
1096}
1097
1098static long smem_log_ioctl(struct file *fp, unsigned int cmd,
1099 unsigned long arg);
1100
1101static const struct file_operations smem_log_fops = {
1102 .owner = THIS_MODULE,
1103 .read = smem_log_read,
1104 .write = smem_log_write,
1105 .open = smem_log_open,
1106 .release = smem_log_release,
1107 .unlocked_ioctl = smem_log_ioctl,
1108};
1109
1110static const struct file_operations smem_log_bin_fops = {
1111 .owner = THIS_MODULE,
1112 .read = smem_log_read_bin,
1113 .write = smem_log_write_bin,
1114 .open = smem_log_open,
1115 .release = smem_log_release,
1116 .unlocked_ioctl = smem_log_ioctl,
1117};
1118
1119static long smem_log_ioctl(struct file *fp,
1120 unsigned int cmd, unsigned long arg)
1121{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 switch (cmd) {
1123 default:
1124 return -ENOTTY;
1125
1126 case SMIOC_SETMODE:
1127 if (arg == SMIOC_TEXT) {
1128 D("%s set text mode\n", __func__);
1129 fp->f_op = &smem_log_fops;
1130 } else if (arg == SMIOC_BINARY) {
1131 D("%s set bin mode\n", __func__);
1132 fp->f_op = &smem_log_bin_fops;
1133 } else {
1134 return -EINVAL;
1135 }
1136 break;
1137 case SMIOC_SETLOG:
Eric Holmberg391ec1b2011-09-09 14:02:22 -06001138 if (arg == SMIOC_LOG) {
1139 if (inst[GEN].events)
1140 fp->private_data = &inst[GEN];
1141 else
1142 return -ENODEV;
1143 } else if (arg == SMIOC_STATIC_LOG) {
1144 if (inst[STA].events)
1145 fp->private_data = &inst[STA];
1146 else
1147 return -ENODEV;
1148 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149 return -EINVAL;
Eric Holmberg391ec1b2011-09-09 14:02:22 -06001150 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 break;
1152 }
1153
1154 return 0;
1155}
1156
1157static struct miscdevice smem_log_dev = {
1158 .minor = MISC_DYNAMIC_MINOR,
1159 .name = "smem_log",
1160 .fops = &smem_log_fops,
1161};
1162
1163#if defined(CONFIG_DEBUG_FS)
1164
1165#define SMEM_LOG_ITEM_PRINT_SIZE 160
1166
1167#define EVENTS_PRINT_SIZE \
1168(SMEM_LOG_ITEM_PRINT_SIZE * SMEM_LOG_NUM_ENTRIES)
1169
1170static uint32_t smem_log_timeout_ms;
1171module_param_named(timeout_ms, smem_log_timeout_ms,
1172 int, S_IRUGO | S_IWUSR | S_IWGRP);
1173
1174static int smem_log_debug_mask;
1175module_param_named(debug_mask, smem_log_debug_mask, int,
1176 S_IRUGO | S_IWUSR | S_IWGRP);
1177
1178#define DBG(x...) do {\
1179 if (smem_log_debug_mask) \
1180 printk(KERN_DEBUG x);\
1181 } while (0)
1182
1183static int update_read_avail(struct smem_log_inst *inst)
1184{
1185 int curr_read_avail;
1186 unsigned long flags = 0;
1187
1188 remote_spin_lock_irqsave(inst->remote_spinlock, flags);
1189
1190 curr_read_avail = (*inst->idx - inst->read_idx);
1191 if (curr_read_avail < 0)
1192 curr_read_avail = inst->num - inst->read_idx + *inst->idx;
1193
1194 DBG("%s: read = %d write = %d curr = %d last = %d\n", __func__,
1195 inst->read_idx, *inst->idx, curr_read_avail, inst->last_read_avail);
1196
1197 if (curr_read_avail < inst->last_read_avail) {
1198 if (inst->last_read_avail != inst->num)
1199 pr_info("smem_log: skipping %d log entries\n",
1200 inst->last_read_avail);
1201 inst->read_idx = *inst->idx + 1;
1202 inst->last_read_avail = inst->num - 1;
1203 } else
1204 inst->last_read_avail = curr_read_avail;
1205
1206 remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
1207
1208 DBG("%s: read = %d write = %d curr = %d last = %d\n", __func__,
1209 inst->read_idx, *inst->idx, curr_read_avail, inst->last_read_avail);
1210
1211 return inst->last_read_avail;
1212}
1213
1214static int _debug_dump(int log, char *buf, int max, uint32_t cont)
1215{
1216 unsigned int idx;
1217 int write_idx, read_avail = 0;
1218 unsigned long flags;
1219 int i = 0;
1220
1221 if (!inst[log].events)
1222 return 0;
1223
1224 if (cont && update_read_avail(&inst[log]) == 0)
1225 return 0;
1226
1227 remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
1228
1229 if (cont) {
1230 idx = inst[log].read_idx;
1231 write_idx = (inst[log].read_idx + inst[log].last_read_avail);
1232 if (write_idx >= inst[log].num)
1233 write_idx -= inst[log].num;
1234 } else {
1235 write_idx = *inst[log].idx;
1236 idx = (write_idx + 1);
1237 }
1238
1239 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1240 inst[log].read_idx, write_idx, idx, inst[log].num - 1);
1241
1242 while ((max - i) > 50) {
1243 if ((inst[log].num - 1) < idx)
1244 idx = 0;
1245
1246 if (idx == write_idx)
1247 break;
1248
1249 if (inst[log].events[idx].identifier) {
1250
1251 i += scnprintf(buf + i, max - i,
1252 "%08x %08x %08x %08x %08x\n",
1253 inst[log].events[idx].identifier,
1254 inst[log].events[idx].timetick,
1255 inst[log].events[idx].data1,
1256 inst[log].events[idx].data2,
1257 inst[log].events[idx].data3);
1258 }
1259 idx++;
1260 }
1261 if (cont) {
1262 inst[log].read_idx = idx;
1263 read_avail = (write_idx - inst[log].read_idx);
1264 if (read_avail < 0)
1265 read_avail = inst->num - inst->read_idx + write_idx;
1266 inst[log].last_read_avail = read_avail;
1267 }
1268
1269 remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
1270
1271 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1272 inst[log].read_idx, write_idx, idx, inst[log].num);
1273
1274 return i;
1275}
1276
1277static int _debug_dump_voters(char *buf, int max)
1278{
1279 int k, i = 0;
1280
1281 find_voters();
1282
1283 i += scnprintf(buf + i, max - i, "Voters:\n");
1284 for (k = 0; k < ARRAY_SIZE(voter_d3_syms); ++k)
1285 if (voter_d3_syms[k].str)
1286 i += scnprintf(buf + i, max - i, "%s ",
1287 voter_d3_syms[k].str);
1288 for (k = 0; k < ARRAY_SIZE(voter_d2_syms); ++k)
1289 if (voter_d2_syms[k].str)
1290 i += scnprintf(buf + i, max - i, "%s ",
1291 voter_d2_syms[k].str);
1292 i += scnprintf(buf + i, max - i, "\n");
1293
1294 return i;
1295}
1296
1297static int _debug_dump_sym(int log, char *buf, int max, uint32_t cont)
1298{
1299 unsigned int idx;
1300 int write_idx, read_avail = 0;
1301 unsigned long flags;
1302 int i = 0;
1303
1304 char *proc;
1305 char *sub;
1306 char *id;
1307 const char *sym = NULL;
1308
1309 uint32_t data[3];
1310
1311 uint32_t proc_val = 0;
1312 uint32_t sub_val = 0;
1313 uint32_t id_val = 0;
1314 uint32_t id_only_val = 0;
1315 uint32_t data1 = 0;
1316 uint32_t data2 = 0;
1317 uint32_t data3 = 0;
1318
1319 if (!inst[log].events)
1320 return 0;
1321
1322 find_voters();
1323
1324 if (cont && update_read_avail(&inst[log]) == 0)
1325 return 0;
1326
1327 remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
1328
1329 if (cont) {
1330 idx = inst[log].read_idx;
1331 write_idx = (inst[log].read_idx + inst[log].last_read_avail);
1332 if (write_idx >= inst[log].num)
1333 write_idx -= inst[log].num;
1334 } else {
1335 write_idx = *inst[log].idx;
1336 idx = (write_idx + 1);
1337 }
1338
1339 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1340 inst[log].read_idx, write_idx, idx, inst[log].num - 1);
1341
1342 for (; (max - i) > SMEM_LOG_ITEM_PRINT_SIZE; idx++) {
1343 if (idx > (inst[log].num - 1))
1344 idx = 0;
1345
1346 if (idx == write_idx)
1347 break;
1348
1349 if (idx < inst[log].num) {
1350 if (!inst[log].events[idx].identifier)
1351 continue;
1352
1353 proc_val = PROC & inst[log].events[idx].identifier;
1354 sub_val = SUB & inst[log].events[idx].identifier;
1355 id_val = (SUB | ID) & inst[log].events[idx].identifier;
1356 id_only_val = ID & inst[log].events[idx].identifier;
1357 data1 = inst[log].events[idx].data1;
1358 data2 = inst[log].events[idx].data2;
1359 data3 = inst[log].events[idx].data3;
1360
1361 if (!(proc_val & SMEM_LOG_CONT)) {
1362 i += scnprintf(buf + i, max - i, "\n");
1363
1364 proc = find_sym(ID_SYM, proc_val);
1365
1366 if (proc)
1367 i += scnprintf(buf + i, max - i,
1368 "%4s: ", proc);
1369 else
1370 i += scnprintf(buf + i, max - i,
1371 "%04x: ",
1372 PROC &
1373 inst[log].events[idx].
1374 identifier);
1375
1376 i += scnprintf(buf + i, max - i, "%10u ",
1377 inst[log].events[idx].timetick);
1378
1379 sub = find_sym(BASE_SYM, sub_val);
1380
1381 if (sub)
1382 i += scnprintf(buf + i, max - i,
1383 "%9s: ", sub);
1384 else
1385 i += scnprintf(buf + i, max - i,
1386 "%08x: ", sub_val);
1387
1388 id = find_sym(EVENT_SYM, id_val);
1389
1390 if (id)
1391 i += scnprintf(buf + i, max - i,
1392 "%11s: ", id);
1393 else
1394 i += scnprintf(buf + i, max - i,
1395 "%08x: ", id_only_val);
1396 }
1397
1398 if ((proc_val & SMEM_LOG_CONT) &&
1399 (id_val == ONCRPC_LOG_EVENT_STD_CALL ||
1400 id_val == ONCRPC_LOG_EVENT_STD_REPLY)) {
1401 data[0] = data1;
1402 data[1] = data2;
1403 data[2] = data3;
1404 i += scnprintf(buf + i, max - i,
1405 " %.16s", (char *) data);
1406 } else if (proc_val & SMEM_LOG_CONT) {
1407 i += scnprintf(buf + i, max - i,
1408 " %08x %08x %08x",
1409 data1, data2, data3);
1410 } else if (id_val == ONCRPC_LOG_EVENT_STD_CALL) {
1411 sym = smd_rpc_get_sym(data2);
1412
1413 if (sym)
1414 i += scnprintf(buf + i, max - i,
1415 "xid:%4i %8s proc:%3i",
1416 data1, sym, data3);
1417 else
1418 i += scnprintf(buf + i, max - i,
1419 "xid:%4i %08x proc:%3i",
1420 data1, data2, data3);
1421#if defined(CONFIG_MSM_N_WAY_SMSM)
1422 } else if (id_val == DEM_STATE_CHANGE) {
1423 if (data1 == 1) {
1424 i += scnprintf(buf + i, max - i,
1425 "MASTER: ");
1426 sym = find_sym(DEM_STATE_MASTER_SYM,
1427 data2);
1428 } else if (data1 == 0) {
1429 i += scnprintf(buf + i, max - i,
1430 " SLAVE: ");
1431 sym = find_sym(DEM_STATE_SLAVE_SYM,
1432 data2);
1433 } else {
1434 i += scnprintf(buf + i, max - i,
1435 "%x: ", data1);
1436 sym = NULL;
1437 }
1438 if (sym)
1439 i += scnprintf(buf + i, max - i,
1440 "from:%s ", sym);
1441 else
1442 i += scnprintf(buf + i, max - i,
1443 "from:0x%x ", data2);
1444
1445 if (data1 == 1)
1446 sym = find_sym(DEM_STATE_MASTER_SYM,
1447 data3);
1448 else if (data1 == 0)
1449 sym = find_sym(DEM_STATE_SLAVE_SYM,
1450 data3);
1451 else
1452 sym = NULL;
1453 if (sym)
1454 i += scnprintf(buf + i, max - i,
1455 "to:%s ", sym);
1456 else
1457 i += scnprintf(buf + i, max - i,
1458 "to:0x%x ", data3);
1459
1460 } else if (id_val == DEM_STATE_MACHINE_ENTER) {
1461 i += scnprintf(buf + i, max - i,
1462 "swfi:%i timer:%i manexit:%i",
1463 data1, data2, data3);
1464
1465 } else if (id_val == DEM_TIME_SYNC_REQUEST ||
1466 id_val == DEM_TIME_SYNC_POLL ||
1467 id_val == DEM_TIME_SYNC_INIT) {
1468 sym = find_sym(SMSM_ENTRY_TYPE_SYM,
1469 data1);
1470 if (sym)
1471 i += scnprintf(buf + i, max - i,
1472 "hostid:%s", sym);
1473 else
1474 i += scnprintf(buf + i, max - i,
1475 "hostid:%x", data1);
1476
1477 } else if (id_val == DEM_TIME_SYNC_START ||
1478 id_val == DEM_TIME_SYNC_SEND_VALUE) {
1479 unsigned mask = 0x1;
1480 unsigned tmp = 0;
1481 if (id_val == DEM_TIME_SYNC_START)
1482 i += scnprintf(buf + i, max - i,
1483 "req:");
1484 else
1485 i += scnprintf(buf + i, max - i,
1486 "pol:");
1487 while (mask) {
1488 if (mask & data1) {
1489 sym = find_sym(
1490 SMSM_ENTRY_TYPE_SYM,
1491 tmp);
1492 if (sym)
1493 i += scnprintf(buf + i,
1494 max - i,
1495 "%s ",
1496 sym);
1497 else
1498 i += scnprintf(buf + i,
1499 max - i,
1500 "%i ",
1501 tmp);
1502 }
1503 mask <<= 1;
1504 tmp++;
1505 }
1506 if (id_val == DEM_TIME_SYNC_SEND_VALUE)
1507 i += scnprintf(buf + i, max - i,
1508 "tick:%x", data2);
1509 } else if (id_val == DEM_SMSM_ISR) {
1510 unsigned vals[] = {data2, data3};
1511 unsigned j;
1512 unsigned mask;
1513 unsigned tmp;
1514 unsigned once;
1515 sym = find_sym(SMSM_ENTRY_TYPE_SYM,
1516 data1);
1517 if (sym)
1518 i += scnprintf(buf + i, max - i,
1519 "%s ", sym);
1520 else
1521 i += scnprintf(buf + i, max - i,
1522 "%x ", data1);
1523
1524 for (j = 0; j < ARRAY_SIZE(vals); ++j) {
1525 i += scnprintf(buf + i, max - i, "[");
1526 mask = 0x80000000;
1527 once = 0;
1528 while (mask) {
1529 tmp = vals[j] & mask;
1530 mask >>= 1;
1531 if (!tmp)
1532 continue;
1533 sym = find_sym(SMSM_STATE_SYM,
1534 tmp);
1535
1536 if (once)
1537 i += scnprintf(buf + i,
1538 max - i,
1539 " ");
1540 if (sym)
1541 i += scnprintf(buf + i,
1542 max - i,
1543 "%s",
1544 sym);
1545 else
1546 i += scnprintf(buf + i,
1547 max - i,
1548 "0x%x",
1549 tmp);
1550 once = 1;
1551 }
1552 i += scnprintf(buf + i, max - i, "] ");
1553 }
1554#else
1555 } else if (id_val == DEMAPPS_WAKEUP_REASON) {
1556 unsigned mask = 0x80000000;
1557 unsigned tmp = 0;
1558 while (mask) {
1559 tmp = data1 & mask;
1560 mask >>= 1;
1561 if (!tmp)
1562 continue;
1563 sym = find_sym(WAKEUP_SYM, tmp);
1564 if (sym)
1565 i += scnprintf(buf + i,
1566 max - i,
1567 "%s ",
1568 sym);
1569 else
1570 i += scnprintf(buf + i,
1571 max - i,
1572 "%08x ",
1573 tmp);
1574 }
1575 i += scnprintf(buf + i, max - i,
1576 "%08x %08x", data2, data3);
1577 } else if (id_val == DEMMOD_APPS_WAKEUP_INT) {
1578 sym = find_sym(WAKEUP_INT_SYM, data1);
1579
1580 if (sym)
1581 i += scnprintf(buf + i, max - i,
1582 "%s %08x %08x",
1583 sym, data2, data3);
1584 else
1585 i += scnprintf(buf + i, max - i,
1586 "%08x %08x %08x",
1587 data1, data2, data3);
1588 } else if (id_val == DEM_NO_SLEEP ||
1589 id_val == NO_SLEEP_NEW) {
1590 unsigned vals[] = {data3, data2};
1591 unsigned j;
1592 unsigned mask;
1593 unsigned tmp;
1594 unsigned once;
1595 i += scnprintf(buf + i, max - i, "%08x ",
1596 data1);
1597 i += scnprintf(buf + i, max - i, "[");
1598 once = 0;
1599 for (j = 0; j < ARRAY_SIZE(vals); ++j) {
1600 mask = 0x00000001;
1601 while (mask) {
1602 tmp = vals[j] & mask;
1603 mask <<= 1;
1604 if (!tmp)
1605 continue;
1606 if (j == 0)
1607 sym = find_sym(
1608 VOTER_D3_SYM,
1609 tmp);
1610 else
1611 sym = find_sym(
1612 VOTER_D2_SYM,
1613 tmp);
1614
1615 if (once)
1616 i += scnprintf(buf + i,
1617 max - i,
1618 " ");
1619 if (sym)
1620 i += scnprintf(buf + i,
1621 max - i,
1622 "%s",
1623 sym);
1624 else
1625 i += scnprintf(buf + i,
1626 max - i,
1627 "%08x",
1628 tmp);
1629 once = 1;
1630 }
1631 }
1632 i += scnprintf(buf + i, max - i, "] ");
1633#endif
1634 } else if (id_val == SMEM_LOG_EVENT_CB) {
1635 unsigned vals[] = {data2, data3};
1636 unsigned j;
1637 unsigned mask;
1638 unsigned tmp;
1639 unsigned once;
1640 i += scnprintf(buf + i, max - i, "%08x ",
1641 data1);
1642 for (j = 0; j < ARRAY_SIZE(vals); ++j) {
1643 i += scnprintf(buf + i, max - i, "[");
1644 mask = 0x80000000;
1645 once = 0;
1646 while (mask) {
1647 tmp = vals[j] & mask;
1648 mask >>= 1;
1649 if (!tmp)
1650 continue;
1651 sym = find_sym(SMSM_SYM, tmp);
1652
1653 if (once)
1654 i += scnprintf(buf + i,
1655 max - i,
1656 " ");
1657 if (sym)
1658 i += scnprintf(buf + i,
1659 max - i,
1660 "%s",
1661 sym);
1662 else
1663 i += scnprintf(buf + i,
1664 max - i,
1665 "%08x",
1666 tmp);
1667 once = 1;
1668 }
1669 i += scnprintf(buf + i, max - i, "] ");
1670 }
1671 } else {
1672 i += scnprintf(buf + i, max - i,
1673 "%08x %08x %08x",
1674 data1, data2, data3);
1675 }
1676 }
1677 }
1678 if (cont) {
1679 inst[log].read_idx = idx;
1680 read_avail = (write_idx - inst[log].read_idx);
1681 if (read_avail < 0)
1682 read_avail = inst->num - inst->read_idx + write_idx;
1683 inst[log].last_read_avail = read_avail;
1684 }
1685
1686 remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
1687
1688 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1689 inst[log].read_idx, write_idx, idx, inst[log].num);
1690
1691 return i;
1692}
1693
1694static int debug_dump(char *buf, int max, uint32_t cont)
1695{
1696 int r;
1697 while (cont) {
1698 update_read_avail(&inst[GEN]);
1699 r = wait_event_interruptible_timeout(inst[GEN].read_wait,
1700 inst[GEN].last_read_avail,
1701 smem_log_timeout_ms *
1702 HZ / 1000);
1703 DBG("%s: read available %d\n", __func__,
1704 inst[GEN].last_read_avail);
1705 if (r < 0)
1706 return 0;
1707 else if (inst[GEN].last_read_avail)
1708 break;
1709 }
1710
1711 return _debug_dump(GEN, buf, max, cont);
1712}
1713
1714static int debug_dump_sym(char *buf, int max, uint32_t cont)
1715{
1716 int r;
1717 while (cont) {
1718 update_read_avail(&inst[GEN]);
1719 r = wait_event_interruptible_timeout(inst[GEN].read_wait,
1720 inst[GEN].last_read_avail,
1721 smem_log_timeout_ms *
1722 HZ / 1000);
1723 DBG("%s: readavailable %d\n", __func__,
1724 inst[GEN].last_read_avail);
1725 if (r < 0)
1726 return 0;
1727 else if (inst[GEN].last_read_avail)
1728 break;
1729 }
1730
1731 return _debug_dump_sym(GEN, buf, max, cont);
1732}
1733
1734static int debug_dump_static(char *buf, int max, uint32_t cont)
1735{
1736 int r;
1737 while (cont) {
1738 update_read_avail(&inst[STA]);
1739 r = wait_event_interruptible_timeout(inst[STA].read_wait,
1740 inst[STA].last_read_avail,
1741 smem_log_timeout_ms *
1742 HZ / 1000);
1743 DBG("%s: readavailable %d\n", __func__,
1744 inst[STA].last_read_avail);
1745 if (r < 0)
1746 return 0;
1747 else if (inst[STA].last_read_avail)
1748 break;
1749 }
1750
1751 return _debug_dump(STA, buf, max, cont);
1752}
1753
1754static int debug_dump_static_sym(char *buf, int max, uint32_t cont)
1755{
1756 int r;
1757 while (cont) {
1758 update_read_avail(&inst[STA]);
1759 r = wait_event_interruptible_timeout(inst[STA].read_wait,
1760 inst[STA].last_read_avail,
1761 smem_log_timeout_ms *
1762 HZ / 1000);
1763 DBG("%s: readavailable %d\n", __func__,
1764 inst[STA].last_read_avail);
1765 if (r < 0)
1766 return 0;
1767 else if (inst[STA].last_read_avail)
1768 break;
1769 }
1770
1771 return _debug_dump_sym(STA, buf, max, cont);
1772}
1773
1774static int debug_dump_power(char *buf, int max, uint32_t cont)
1775{
1776 int r;
1777 while (cont) {
1778 update_read_avail(&inst[POW]);
1779 r = wait_event_interruptible_timeout(inst[POW].read_wait,
1780 inst[POW].last_read_avail,
1781 smem_log_timeout_ms *
1782 HZ / 1000);
1783 DBG("%s: readavailable %d\n", __func__,
1784 inst[POW].last_read_avail);
1785 if (r < 0)
1786 return 0;
1787 else if (inst[POW].last_read_avail)
1788 break;
1789 }
1790
1791 return _debug_dump(POW, buf, max, cont);
1792}
1793
1794static int debug_dump_power_sym(char *buf, int max, uint32_t cont)
1795{
1796 int r;
1797 while (cont) {
1798 update_read_avail(&inst[POW]);
1799 r = wait_event_interruptible_timeout(inst[POW].read_wait,
1800 inst[POW].last_read_avail,
1801 smem_log_timeout_ms *
1802 HZ / 1000);
1803 DBG("%s: readavailable %d\n", __func__,
1804 inst[POW].last_read_avail);
1805 if (r < 0)
1806 return 0;
1807 else if (inst[POW].last_read_avail)
1808 break;
1809 }
1810
1811 return _debug_dump_sym(POW, buf, max, cont);
1812}
1813
1814static int debug_dump_voters(char *buf, int max, uint32_t cont)
1815{
1816 return _debug_dump_voters(buf, max);
1817}
1818
1819static char debug_buffer[EVENTS_PRINT_SIZE];
1820
1821static ssize_t debug_read(struct file *file, char __user *buf,
1822 size_t count, loff_t *ppos)
1823{
1824 int r;
1825 static int bsize;
1826 int (*fill)(char *, int, uint32_t) = file->private_data;
1827 if (!(*ppos))
1828 bsize = fill(debug_buffer, EVENTS_PRINT_SIZE, 0);
1829 DBG("%s: count %d ppos %d\n", __func__, count, (unsigned int)*ppos);
1830 r = simple_read_from_buffer(buf, count, ppos, debug_buffer,
1831 bsize);
1832 return r;
1833}
1834
1835static ssize_t debug_read_cont(struct file *file, char __user *buf,
1836 size_t count, loff_t *ppos)
1837{
1838 int (*fill)(char *, int, uint32_t) = file->private_data;
1839 char *buffer = kmalloc(count, GFP_KERNEL);
1840 int bsize;
1841 if (!buffer)
1842 return -ENOMEM;
1843 bsize = fill(buffer, count, 1);
1844 DBG("%s: count %d bsize %d\n", __func__, count, bsize);
1845 if (copy_to_user(buf, buffer, bsize)) {
1846 kfree(buffer);
1847 return -EFAULT;
1848 }
1849 kfree(buffer);
1850 return bsize;
1851}
1852
1853static int debug_open(struct inode *inode, struct file *file)
1854{
1855 file->private_data = inode->i_private;
1856 return 0;
1857}
1858
1859static const struct file_operations debug_ops = {
1860 .read = debug_read,
1861 .open = debug_open,
1862};
1863
1864static const struct file_operations debug_ops_cont = {
1865 .read = debug_read_cont,
1866 .open = debug_open,
1867};
1868
1869static void debug_create(const char *name, mode_t mode,
1870 struct dentry *dent,
1871 int (*fill)(char *buf, int max, uint32_t cont),
1872 const struct file_operations *fops)
1873{
1874 debugfs_create_file(name, mode, dent, fill, fops);
1875}
1876
1877static void smem_log_debugfs_init(void)
1878{
1879 struct dentry *dent;
1880
1881 dent = debugfs_create_dir("smem_log", 0);
1882 if (IS_ERR(dent))
1883 return;
1884
1885 debug_create("dump", 0444, dent, debug_dump, &debug_ops);
1886 debug_create("dump_sym", 0444, dent, debug_dump_sym, &debug_ops);
1887 debug_create("dump_static", 0444, dent, debug_dump_static, &debug_ops);
1888 debug_create("dump_static_sym", 0444, dent,
1889 debug_dump_static_sym, &debug_ops);
1890 debug_create("dump_power", 0444, dent, debug_dump_power, &debug_ops);
1891 debug_create("dump_power_sym", 0444, dent,
1892 debug_dump_power_sym, &debug_ops);
1893 debug_create("dump_voters", 0444, dent,
1894 debug_dump_voters, &debug_ops);
1895
1896 debug_create("dump_cont", 0444, dent, debug_dump, &debug_ops_cont);
1897 debug_create("dump_sym_cont", 0444, dent,
1898 debug_dump_sym, &debug_ops_cont);
1899 debug_create("dump_static_cont", 0444, dent,
1900 debug_dump_static, &debug_ops_cont);
1901 debug_create("dump_static_sym_cont", 0444, dent,
1902 debug_dump_static_sym, &debug_ops_cont);
1903 debug_create("dump_power_cont", 0444, dent,
1904 debug_dump_power, &debug_ops_cont);
1905 debug_create("dump_power_sym_cont", 0444, dent,
1906 debug_dump_power_sym, &debug_ops_cont);
1907
1908 smem_log_timeout_ms = 500;
1909 smem_log_debug_mask = 0;
1910}
1911#else
1912static void smem_log_debugfs_init(void) {}
1913#endif
1914
1915static int smem_log_initialize(void)
1916{
1917 int ret;
1918
1919 ret = _smem_log_init();
1920 if (ret < 0) {
1921 pr_err("%s: init failed %d\n", __func__, ret);
1922 return ret;
1923 }
1924
1925 ret = misc_register(&smem_log_dev);
1926 if (ret < 0) {
1927 pr_err("%s: device register failed %d\n", __func__, ret);
1928 return ret;
1929 }
1930
1931 smem_log_enable = 1;
1932 smem_log_initialized = 1;
1933 smem_log_debugfs_init();
1934 return ret;
1935}
1936
1937static int modem_notifier(struct notifier_block *this,
1938 unsigned long code,
1939 void *_cmd)
1940{
1941 switch (code) {
1942 case MODEM_NOTIFIER_SMSM_INIT:
1943 if (!smem_log_initialized)
1944 smem_log_initialize();
1945 break;
1946 default:
1947 break;
1948 }
1949 return NOTIFY_DONE;
1950}
1951
1952static struct notifier_block nb = {
1953 .notifier_call = modem_notifier,
1954};
1955
1956static int __init smem_log_init(void)
1957{
1958 return modem_register_notifier(&nb);
1959}
1960
1961
1962module_init(smem_log_init);
1963
1964MODULE_DESCRIPTION("smem log");
1965MODULE_LICENSE("GPL v2");