blob: 5efdc149dfdab73ef343699acd598db88ce3abf0 [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
Eric Holmberg16653352012-03-28 16:16:47 -0600652 if (!inst->idx) {
653 pr_err("%s: invalid write index\n", __func__);
654 return;
655 }
656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 remote_spin_lock_irqsave(inst->remote_spinlock, flags);
658
659 while (num--) {
660 idx = *inst->idx;
661
662 if (idx < inst->num) {
663 ret = copy_from_user(&inst->events[idx],
664 buf, size);
665 if (ret) {
666 printk("ERROR %s:%i tried to write "
667 "%i got ret %i",
668 __func__, __LINE__,
669 size, size - ret);
670 goto out;
671 }
672
673 if (first) {
674 identifier =
675 inst->events[idx].
676 identifier;
677 timetick = read_timestamp();
678 first = 0;
679 } else {
680 identifier |= SMEM_LOG_CONT;
681 }
682 inst->events[idx].identifier =
683 identifier;
684 inst->events[idx].timetick =
685 timetick;
686 }
687
688 next_idx = idx + 1;
689 if (next_idx >= inst->num)
690 next_idx = 0;
691 *inst->idx = next_idx;
692 buf += sizeof(struct smem_log_item);
693 }
694
695 out:
696 wmb();
697 remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
698}
699
700static void _smem_log_event(
701 struct smem_log_item __iomem *events,
702 uint32_t __iomem *_idx,
703 remote_spinlock_t *lock,
704 int num,
705 uint32_t id, uint32_t data1, uint32_t data2,
706 uint32_t data3)
707{
708 struct smem_log_item item;
709 uint32_t idx;
710 uint32_t next_idx;
711 unsigned long flags;
712
713 item.timetick = read_timestamp();
714 item.identifier = id;
715 item.data1 = data1;
716 item.data2 = data2;
717 item.data3 = data3;
718
719 remote_spin_lock_irqsave(lock, flags);
720
721 idx = *_idx;
722
723 if (idx < num) {
724 memcpy(&events[idx],
725 &item, sizeof(item));
726 }
727
728 next_idx = idx + 1;
729 if (next_idx >= num)
730 next_idx = 0;
731 *_idx = next_idx;
732 wmb();
733
734 remote_spin_unlock_irqrestore(lock, flags);
735}
736
737static void _smem_log_event6(
738 struct smem_log_item __iomem *events,
739 uint32_t __iomem *_idx,
740 remote_spinlock_t *lock,
741 int num,
742 uint32_t id, uint32_t data1, uint32_t data2,
743 uint32_t data3, uint32_t data4, uint32_t data5,
744 uint32_t data6)
745{
746 struct smem_log_item item[2];
747 uint32_t idx;
748 uint32_t next_idx;
749 unsigned long flags;
750
751 item[0].timetick = read_timestamp();
752 item[0].identifier = id;
753 item[0].data1 = data1;
754 item[0].data2 = data2;
755 item[0].data3 = data3;
756 item[1].identifier = item[0].identifier;
757 item[1].timetick = item[0].timetick;
758 item[1].data1 = data4;
759 item[1].data2 = data5;
760 item[1].data3 = data6;
761
762 remote_spin_lock_irqsave(lock, flags);
763
764 idx = *_idx;
765
766 /* FIXME: Wrap around */
767 if (idx < (num-1)) {
768 memcpy(&events[idx],
769 &item, sizeof(item));
770 }
771
772 next_idx = idx + 2;
773 if (next_idx >= num)
774 next_idx = 0;
775 *_idx = next_idx;
776
777 wmb();
778 remote_spin_unlock_irqrestore(lock, flags);
779}
780
781void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
782 uint32_t data3)
783{
784 if (smem_log_enable)
785 _smem_log_event(inst[GEN].events, inst[GEN].idx,
786 inst[GEN].remote_spinlock,
787 SMEM_LOG_NUM_ENTRIES, id,
788 data1, data2, data3);
789}
790
791void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
792 uint32_t data3, uint32_t data4, uint32_t data5,
793 uint32_t data6)
794{
795 if (smem_log_enable)
796 _smem_log_event6(inst[GEN].events, inst[GEN].idx,
797 inst[GEN].remote_spinlock,
798 SMEM_LOG_NUM_ENTRIES, id,
799 data1, data2, data3, data4, data5, data6);
800}
801
802void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
803 uint32_t data3)
804{
805 if (smem_log_enable)
806 _smem_log_event(inst[STA].events, inst[STA].idx,
807 inst[STA].remote_spinlock,
808 SMEM_LOG_NUM_STATIC_ENTRIES, id,
809 data1, data2, data3);
810}
811
812void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
813 uint32_t data3, uint32_t data4, uint32_t data5,
814 uint32_t data6)
815{
816 if (smem_log_enable)
817 _smem_log_event6(inst[STA].events, inst[STA].idx,
818 inst[STA].remote_spinlock,
819 SMEM_LOG_NUM_STATIC_ENTRIES, id,
820 data1, data2, data3, data4, data5, data6);
821}
822
823static int _smem_log_init(void)
824{
825 int ret;
826
827 inst[GEN].which_log = GEN;
828 inst[GEN].events =
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -0600829 (struct smem_log_item *)smem_alloc2(SMEM_SMEM_LOG_EVENTS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 SMEM_LOG_EVENTS_SIZE);
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -0600831 inst[GEN].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_LOG_IDX,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832 sizeof(uint32_t));
833 if (!inst[GEN].events || !inst[GEN].idx)
834 pr_info("%s: no log or log_idx allocated\n", __func__);
835
836 inst[GEN].num = SMEM_LOG_NUM_ENTRIES;
837 inst[GEN].read_idx = 0;
838 inst[GEN].last_read_avail = SMEM_LOG_NUM_ENTRIES;
839 init_waitqueue_head(&inst[GEN].read_wait);
840 inst[GEN].remote_spinlock = &remote_spinlock;
841
842 inst[STA].which_log = STA;
843 inst[STA].events =
844 (struct smem_log_item *)
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -0600845 smem_alloc2(SMEM_SMEM_STATIC_LOG_EVENTS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700846 SMEM_STATIC_LOG_EVENTS_SIZE);
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -0600847 inst[STA].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_STATIC_LOG_IDX,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 sizeof(uint32_t));
849 if (!inst[STA].events || !inst[STA].idx)
850 pr_info("%s: no static log or log_idx allocated\n", __func__);
851
852 inst[STA].num = SMEM_LOG_NUM_STATIC_ENTRIES;
853 inst[STA].read_idx = 0;
854 inst[STA].last_read_avail = SMEM_LOG_NUM_ENTRIES;
855 init_waitqueue_head(&inst[STA].read_wait);
856 inst[STA].remote_spinlock = &remote_spinlock_static;
857
858 inst[POW].which_log = POW;
859 inst[POW].events =
860 (struct smem_log_item *)
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -0600861 smem_alloc2(SMEM_SMEM_LOG_POWER_EVENTS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 SMEM_POWER_LOG_EVENTS_SIZE);
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -0600863 inst[POW].idx = (uint32_t *)smem_alloc2(SMEM_SMEM_LOG_POWER_IDX,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 sizeof(uint32_t));
865 if (!inst[POW].events || !inst[POW].idx)
866 pr_info("%s: no power log or log_idx allocated\n", __func__);
867
868 inst[POW].num = SMEM_LOG_NUM_POWER_ENTRIES;
869 inst[POW].read_idx = 0;
870 inst[POW].last_read_avail = SMEM_LOG_NUM_ENTRIES;
871 init_waitqueue_head(&inst[POW].read_wait);
872 inst[POW].remote_spinlock = &remote_spinlock;
873
874 ret = remote_spin_lock_init(&remote_spinlock,
875 SMEM_SPINLOCK_SMEM_LOG);
876 if (ret) {
877 mb();
878 return ret;
879 }
880
881 ret = remote_spin_lock_init(&remote_spinlock_static,
882 SMEM_SPINLOCK_STATIC_LOG);
883 if (ret) {
884 mb();
885 return ret;
886 }
887
888 init_syms();
889 mb();
890
891 return 0;
892}
893
894static ssize_t smem_log_read_bin(struct file *fp, char __user *buf,
895 size_t count, loff_t *pos)
896{
897 int idx;
898 int orig_idx;
899 unsigned long flags;
900 int ret;
901 int tot_bytes = 0;
Eric Holmbergcf065312011-09-09 14:00:40 -0600902 struct smem_log_inst *local_inst;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903
Eric Holmbergcf065312011-09-09 14:00:40 -0600904 local_inst = fp->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905
Eric Holmberg16653352012-03-28 16:16:47 -0600906 if (!local_inst->idx)
907 return -ENODEV;
908
Eric Holmbergcf065312011-09-09 14:00:40 -0600909 remote_spin_lock_irqsave(local_inst->remote_spinlock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910
Eric Holmbergcf065312011-09-09 14:00:40 -0600911 orig_idx = *local_inst->idx;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 idx = orig_idx;
913
914 while (1) {
915 idx--;
916 if (idx < 0)
Eric Holmbergcf065312011-09-09 14:00:40 -0600917 idx = local_inst->num - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918 if (idx == orig_idx) {
919 ret = tot_bytes;
920 break;
921 }
922
923 if ((tot_bytes + sizeof(struct smem_log_item)) > count) {
924 ret = tot_bytes;
925 break;
926 }
927
Eric Holmbergcf065312011-09-09 14:00:40 -0600928 ret = copy_to_user(buf, &local_inst->events[idx],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929 sizeof(struct smem_log_item));
930 if (ret) {
931 ret = -EIO;
932 break;
933 }
934
935 tot_bytes += sizeof(struct smem_log_item);
936
937 buf += sizeof(struct smem_log_item);
938 }
939
Eric Holmbergcf065312011-09-09 14:00:40 -0600940 remote_spin_unlock_irqrestore(local_inst->remote_spinlock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941
942 return ret;
943}
944
945static ssize_t smem_log_read(struct file *fp, char __user *buf,
946 size_t count, loff_t *pos)
947{
948 char loc_buf[128];
949 int i;
950 int idx;
951 int orig_idx;
952 unsigned long flags;
953 int ret;
954 int tot_bytes = 0;
955 struct smem_log_inst *inst;
956
957 inst = fp->private_data;
Eric Holmberg16653352012-03-28 16:16:47 -0600958 if (!inst->idx)
959 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960
961 remote_spin_lock_irqsave(inst->remote_spinlock, flags);
962
963 orig_idx = *inst->idx;
964 idx = orig_idx;
965
966 while (1) {
967 idx--;
968 if (idx < 0)
969 idx = inst->num - 1;
970 if (idx == orig_idx) {
971 ret = tot_bytes;
972 break;
973 }
974
975 i = scnprintf(loc_buf, 128,
976 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
977 inst->events[idx].identifier,
978 inst->events[idx].timetick,
979 inst->events[idx].data1,
980 inst->events[idx].data2,
981 inst->events[idx].data3);
982 if (i == 0) {
983 ret = -EIO;
984 break;
985 }
986
987 if ((tot_bytes + i) > count) {
988 ret = tot_bytes;
989 break;
990 }
991
992 tot_bytes += i;
993
994 ret = copy_to_user(buf, loc_buf, i);
995 if (ret) {
996 ret = -EIO;
997 break;
998 }
999
1000 buf += i;
1001 }
1002
1003 remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
1004
1005 return ret;
1006}
1007
1008static ssize_t smem_log_write_bin(struct file *fp, const char __user *buf,
1009 size_t count, loff_t *pos)
1010{
1011 if (count < sizeof(struct smem_log_item))
1012 return -EINVAL;
1013
1014 if (smem_log_enable)
1015 smem_log_event_from_user(fp->private_data, buf,
1016 sizeof(struct smem_log_item),
1017 count / sizeof(struct smem_log_item));
1018 return count;
1019}
1020
1021static ssize_t smem_log_write(struct file *fp, const char __user *buf,
1022 size_t count, loff_t *pos)
1023{
1024 int ret;
1025 const char delimiters[] = " ,;";
1026 char locbuf[256] = {0};
1027 uint32_t val[10] = {0};
1028 int vals = 0;
1029 char *token;
1030 char *running;
1031 struct smem_log_inst *inst;
1032 unsigned long res;
1033
1034 inst = fp->private_data;
1035
1036 count = count > 255 ? 255 : count;
1037
1038 if (!smem_log_enable)
1039 return count;
1040
1041 locbuf[count] = '\0';
1042
1043 ret = copy_from_user(locbuf, buf, count);
1044 if (ret != 0) {
1045 printk(KERN_ERR "ERROR: %s could not copy %i bytes\n",
1046 __func__, ret);
1047 return -EINVAL;
1048 }
1049
1050 D(KERN_ERR "%s: ", __func__);
1051 D_DUMP_BUFFER("We got", len, locbuf);
1052
1053 running = locbuf;
1054
1055 token = strsep(&running, delimiters);
1056 while (token && vals < ARRAY_SIZE(val)) {
1057 if (*token != '\0') {
1058 D(KERN_ERR "%s: ", __func__);
1059 D_DUMP_BUFFER("", strlen(token), token);
1060 ret = strict_strtoul(token, 0, &res);
1061 if (ret) {
1062 printk(KERN_ERR "ERROR: %s:%i got bad char "
1063 "at strict_strtoul\n",
1064 __func__, __LINE__-4);
1065 return -EINVAL;
1066 }
1067 val[vals++] = res;
1068 }
1069 token = strsep(&running, delimiters);
1070 }
1071
1072 if (vals > 5) {
1073 if (inst->which_log == GEN)
1074 smem_log_event6(val[0], val[2], val[3], val[4],
1075 val[7], val[8], val[9]);
1076 else if (inst->which_log == STA)
1077 smem_log_event6_to_static(val[0],
1078 val[2], val[3], val[4],
1079 val[7], val[8], val[9]);
1080 else
1081 return -1;
1082 } else {
1083 if (inst->which_log == GEN)
1084 smem_log_event(val[0], val[2], val[3], val[4]);
1085 else if (inst->which_log == STA)
1086 smem_log_event_to_static(val[0],
1087 val[2], val[3], val[4]);
1088 else
1089 return -1;
1090 }
1091
1092 return count;
1093}
1094
1095static int smem_log_open(struct inode *ip, struct file *fp)
1096{
1097 fp->private_data = &inst[GEN];
1098
1099 return 0;
1100}
1101
1102
1103static int smem_log_release(struct inode *ip, struct file *fp)
1104{
1105 return 0;
1106}
1107
1108static long smem_log_ioctl(struct file *fp, unsigned int cmd,
1109 unsigned long arg);
1110
1111static const struct file_operations smem_log_fops = {
1112 .owner = THIS_MODULE,
1113 .read = smem_log_read,
1114 .write = smem_log_write,
1115 .open = smem_log_open,
1116 .release = smem_log_release,
1117 .unlocked_ioctl = smem_log_ioctl,
1118};
1119
1120static const struct file_operations smem_log_bin_fops = {
1121 .owner = THIS_MODULE,
1122 .read = smem_log_read_bin,
1123 .write = smem_log_write_bin,
1124 .open = smem_log_open,
1125 .release = smem_log_release,
1126 .unlocked_ioctl = smem_log_ioctl,
1127};
1128
1129static long smem_log_ioctl(struct file *fp,
1130 unsigned int cmd, unsigned long arg)
1131{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 switch (cmd) {
1133 default:
1134 return -ENOTTY;
1135
1136 case SMIOC_SETMODE:
1137 if (arg == SMIOC_TEXT) {
1138 D("%s set text mode\n", __func__);
1139 fp->f_op = &smem_log_fops;
1140 } else if (arg == SMIOC_BINARY) {
1141 D("%s set bin mode\n", __func__);
1142 fp->f_op = &smem_log_bin_fops;
1143 } else {
1144 return -EINVAL;
1145 }
1146 break;
1147 case SMIOC_SETLOG:
Eric Holmberg391ec1b2011-09-09 14:02:22 -06001148 if (arg == SMIOC_LOG) {
1149 if (inst[GEN].events)
1150 fp->private_data = &inst[GEN];
1151 else
1152 return -ENODEV;
1153 } else if (arg == SMIOC_STATIC_LOG) {
1154 if (inst[STA].events)
1155 fp->private_data = &inst[STA];
1156 else
1157 return -ENODEV;
1158 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 return -EINVAL;
Eric Holmberg391ec1b2011-09-09 14:02:22 -06001160 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 break;
1162 }
1163
1164 return 0;
1165}
1166
1167static struct miscdevice smem_log_dev = {
1168 .minor = MISC_DYNAMIC_MINOR,
1169 .name = "smem_log",
1170 .fops = &smem_log_fops,
1171};
1172
1173#if defined(CONFIG_DEBUG_FS)
1174
1175#define SMEM_LOG_ITEM_PRINT_SIZE 160
1176
1177#define EVENTS_PRINT_SIZE \
1178(SMEM_LOG_ITEM_PRINT_SIZE * SMEM_LOG_NUM_ENTRIES)
1179
1180static uint32_t smem_log_timeout_ms;
1181module_param_named(timeout_ms, smem_log_timeout_ms,
1182 int, S_IRUGO | S_IWUSR | S_IWGRP);
1183
1184static int smem_log_debug_mask;
1185module_param_named(debug_mask, smem_log_debug_mask, int,
1186 S_IRUGO | S_IWUSR | S_IWGRP);
1187
1188#define DBG(x...) do {\
1189 if (smem_log_debug_mask) \
1190 printk(KERN_DEBUG x);\
1191 } while (0)
1192
1193static int update_read_avail(struct smem_log_inst *inst)
1194{
1195 int curr_read_avail;
1196 unsigned long flags = 0;
1197
Eric Holmberg16653352012-03-28 16:16:47 -06001198 if (!inst->idx)
1199 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200
Eric Holmberg16653352012-03-28 16:16:47 -06001201 remote_spin_lock_irqsave(inst->remote_spinlock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 curr_read_avail = (*inst->idx - inst->read_idx);
1203 if (curr_read_avail < 0)
1204 curr_read_avail = inst->num - inst->read_idx + *inst->idx;
1205
1206 DBG("%s: read = %d write = %d curr = %d last = %d\n", __func__,
1207 inst->read_idx, *inst->idx, curr_read_avail, inst->last_read_avail);
1208
1209 if (curr_read_avail < inst->last_read_avail) {
1210 if (inst->last_read_avail != inst->num)
1211 pr_info("smem_log: skipping %d log entries\n",
1212 inst->last_read_avail);
1213 inst->read_idx = *inst->idx + 1;
1214 inst->last_read_avail = inst->num - 1;
1215 } else
1216 inst->last_read_avail = curr_read_avail;
1217
1218 remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
1219
1220 DBG("%s: read = %d write = %d curr = %d last = %d\n", __func__,
1221 inst->read_idx, *inst->idx, curr_read_avail, inst->last_read_avail);
1222
1223 return inst->last_read_avail;
1224}
1225
1226static int _debug_dump(int log, char *buf, int max, uint32_t cont)
1227{
1228 unsigned int idx;
1229 int write_idx, read_avail = 0;
1230 unsigned long flags;
1231 int i = 0;
1232
1233 if (!inst[log].events)
1234 return 0;
1235
1236 if (cont && update_read_avail(&inst[log]) == 0)
1237 return 0;
1238
1239 remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
1240
1241 if (cont) {
1242 idx = inst[log].read_idx;
1243 write_idx = (inst[log].read_idx + inst[log].last_read_avail);
1244 if (write_idx >= inst[log].num)
1245 write_idx -= inst[log].num;
1246 } else {
1247 write_idx = *inst[log].idx;
1248 idx = (write_idx + 1);
1249 }
1250
1251 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1252 inst[log].read_idx, write_idx, idx, inst[log].num - 1);
1253
1254 while ((max - i) > 50) {
1255 if ((inst[log].num - 1) < idx)
1256 idx = 0;
1257
1258 if (idx == write_idx)
1259 break;
1260
1261 if (inst[log].events[idx].identifier) {
1262
1263 i += scnprintf(buf + i, max - i,
1264 "%08x %08x %08x %08x %08x\n",
1265 inst[log].events[idx].identifier,
1266 inst[log].events[idx].timetick,
1267 inst[log].events[idx].data1,
1268 inst[log].events[idx].data2,
1269 inst[log].events[idx].data3);
1270 }
1271 idx++;
1272 }
1273 if (cont) {
1274 inst[log].read_idx = idx;
1275 read_avail = (write_idx - inst[log].read_idx);
1276 if (read_avail < 0)
1277 read_avail = inst->num - inst->read_idx + write_idx;
1278 inst[log].last_read_avail = read_avail;
1279 }
1280
1281 remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
1282
1283 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1284 inst[log].read_idx, write_idx, idx, inst[log].num);
1285
1286 return i;
1287}
1288
1289static int _debug_dump_voters(char *buf, int max)
1290{
1291 int k, i = 0;
1292
1293 find_voters();
1294
1295 i += scnprintf(buf + i, max - i, "Voters:\n");
1296 for (k = 0; k < ARRAY_SIZE(voter_d3_syms); ++k)
1297 if (voter_d3_syms[k].str)
1298 i += scnprintf(buf + i, max - i, "%s ",
1299 voter_d3_syms[k].str);
1300 for (k = 0; k < ARRAY_SIZE(voter_d2_syms); ++k)
1301 if (voter_d2_syms[k].str)
1302 i += scnprintf(buf + i, max - i, "%s ",
1303 voter_d2_syms[k].str);
1304 i += scnprintf(buf + i, max - i, "\n");
1305
1306 return i;
1307}
1308
1309static int _debug_dump_sym(int log, char *buf, int max, uint32_t cont)
1310{
1311 unsigned int idx;
1312 int write_idx, read_avail = 0;
1313 unsigned long flags;
1314 int i = 0;
1315
1316 char *proc;
1317 char *sub;
1318 char *id;
1319 const char *sym = NULL;
1320
1321 uint32_t data[3];
1322
1323 uint32_t proc_val = 0;
1324 uint32_t sub_val = 0;
1325 uint32_t id_val = 0;
1326 uint32_t id_only_val = 0;
1327 uint32_t data1 = 0;
1328 uint32_t data2 = 0;
1329 uint32_t data3 = 0;
1330
1331 if (!inst[log].events)
1332 return 0;
1333
1334 find_voters();
1335
1336 if (cont && update_read_avail(&inst[log]) == 0)
1337 return 0;
1338
1339 remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
1340
1341 if (cont) {
1342 idx = inst[log].read_idx;
1343 write_idx = (inst[log].read_idx + inst[log].last_read_avail);
1344 if (write_idx >= inst[log].num)
1345 write_idx -= inst[log].num;
1346 } else {
1347 write_idx = *inst[log].idx;
1348 idx = (write_idx + 1);
1349 }
1350
1351 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1352 inst[log].read_idx, write_idx, idx, inst[log].num - 1);
1353
1354 for (; (max - i) > SMEM_LOG_ITEM_PRINT_SIZE; idx++) {
1355 if (idx > (inst[log].num - 1))
1356 idx = 0;
1357
1358 if (idx == write_idx)
1359 break;
1360
1361 if (idx < inst[log].num) {
1362 if (!inst[log].events[idx].identifier)
1363 continue;
1364
1365 proc_val = PROC & inst[log].events[idx].identifier;
1366 sub_val = SUB & inst[log].events[idx].identifier;
1367 id_val = (SUB | ID) & inst[log].events[idx].identifier;
1368 id_only_val = ID & inst[log].events[idx].identifier;
1369 data1 = inst[log].events[idx].data1;
1370 data2 = inst[log].events[idx].data2;
1371 data3 = inst[log].events[idx].data3;
1372
1373 if (!(proc_val & SMEM_LOG_CONT)) {
1374 i += scnprintf(buf + i, max - i, "\n");
1375
1376 proc = find_sym(ID_SYM, proc_val);
1377
1378 if (proc)
1379 i += scnprintf(buf + i, max - i,
1380 "%4s: ", proc);
1381 else
1382 i += scnprintf(buf + i, max - i,
1383 "%04x: ",
1384 PROC &
1385 inst[log].events[idx].
1386 identifier);
1387
1388 i += scnprintf(buf + i, max - i, "%10u ",
1389 inst[log].events[idx].timetick);
1390
1391 sub = find_sym(BASE_SYM, sub_val);
1392
1393 if (sub)
1394 i += scnprintf(buf + i, max - i,
1395 "%9s: ", sub);
1396 else
1397 i += scnprintf(buf + i, max - i,
1398 "%08x: ", sub_val);
1399
1400 id = find_sym(EVENT_SYM, id_val);
1401
1402 if (id)
1403 i += scnprintf(buf + i, max - i,
1404 "%11s: ", id);
1405 else
1406 i += scnprintf(buf + i, max - i,
1407 "%08x: ", id_only_val);
1408 }
1409
1410 if ((proc_val & SMEM_LOG_CONT) &&
1411 (id_val == ONCRPC_LOG_EVENT_STD_CALL ||
1412 id_val == ONCRPC_LOG_EVENT_STD_REPLY)) {
1413 data[0] = data1;
1414 data[1] = data2;
1415 data[2] = data3;
1416 i += scnprintf(buf + i, max - i,
1417 " %.16s", (char *) data);
1418 } else if (proc_val & SMEM_LOG_CONT) {
1419 i += scnprintf(buf + i, max - i,
1420 " %08x %08x %08x",
1421 data1, data2, data3);
1422 } else if (id_val == ONCRPC_LOG_EVENT_STD_CALL) {
1423 sym = smd_rpc_get_sym(data2);
1424
1425 if (sym)
1426 i += scnprintf(buf + i, max - i,
1427 "xid:%4i %8s proc:%3i",
1428 data1, sym, data3);
1429 else
1430 i += scnprintf(buf + i, max - i,
1431 "xid:%4i %08x proc:%3i",
1432 data1, data2, data3);
1433#if defined(CONFIG_MSM_N_WAY_SMSM)
1434 } else if (id_val == DEM_STATE_CHANGE) {
1435 if (data1 == 1) {
1436 i += scnprintf(buf + i, max - i,
1437 "MASTER: ");
1438 sym = find_sym(DEM_STATE_MASTER_SYM,
1439 data2);
1440 } else if (data1 == 0) {
1441 i += scnprintf(buf + i, max - i,
1442 " SLAVE: ");
1443 sym = find_sym(DEM_STATE_SLAVE_SYM,
1444 data2);
1445 } else {
1446 i += scnprintf(buf + i, max - i,
1447 "%x: ", data1);
1448 sym = NULL;
1449 }
1450 if (sym)
1451 i += scnprintf(buf + i, max - i,
1452 "from:%s ", sym);
1453 else
1454 i += scnprintf(buf + i, max - i,
1455 "from:0x%x ", data2);
1456
1457 if (data1 == 1)
1458 sym = find_sym(DEM_STATE_MASTER_SYM,
1459 data3);
1460 else if (data1 == 0)
1461 sym = find_sym(DEM_STATE_SLAVE_SYM,
1462 data3);
1463 else
1464 sym = NULL;
1465 if (sym)
1466 i += scnprintf(buf + i, max - i,
1467 "to:%s ", sym);
1468 else
1469 i += scnprintf(buf + i, max - i,
1470 "to:0x%x ", data3);
1471
1472 } else if (id_val == DEM_STATE_MACHINE_ENTER) {
1473 i += scnprintf(buf + i, max - i,
1474 "swfi:%i timer:%i manexit:%i",
1475 data1, data2, data3);
1476
1477 } else if (id_val == DEM_TIME_SYNC_REQUEST ||
1478 id_val == DEM_TIME_SYNC_POLL ||
1479 id_val == DEM_TIME_SYNC_INIT) {
1480 sym = find_sym(SMSM_ENTRY_TYPE_SYM,
1481 data1);
1482 if (sym)
1483 i += scnprintf(buf + i, max - i,
1484 "hostid:%s", sym);
1485 else
1486 i += scnprintf(buf + i, max - i,
1487 "hostid:%x", data1);
1488
1489 } else if (id_val == DEM_TIME_SYNC_START ||
1490 id_val == DEM_TIME_SYNC_SEND_VALUE) {
1491 unsigned mask = 0x1;
1492 unsigned tmp = 0;
1493 if (id_val == DEM_TIME_SYNC_START)
1494 i += scnprintf(buf + i, max - i,
1495 "req:");
1496 else
1497 i += scnprintf(buf + i, max - i,
1498 "pol:");
1499 while (mask) {
1500 if (mask & data1) {
1501 sym = find_sym(
1502 SMSM_ENTRY_TYPE_SYM,
1503 tmp);
1504 if (sym)
1505 i += scnprintf(buf + i,
1506 max - i,
1507 "%s ",
1508 sym);
1509 else
1510 i += scnprintf(buf + i,
1511 max - i,
1512 "%i ",
1513 tmp);
1514 }
1515 mask <<= 1;
1516 tmp++;
1517 }
1518 if (id_val == DEM_TIME_SYNC_SEND_VALUE)
1519 i += scnprintf(buf + i, max - i,
1520 "tick:%x", data2);
1521 } else if (id_val == DEM_SMSM_ISR) {
1522 unsigned vals[] = {data2, data3};
1523 unsigned j;
1524 unsigned mask;
1525 unsigned tmp;
1526 unsigned once;
1527 sym = find_sym(SMSM_ENTRY_TYPE_SYM,
1528 data1);
1529 if (sym)
1530 i += scnprintf(buf + i, max - i,
1531 "%s ", sym);
1532 else
1533 i += scnprintf(buf + i, max - i,
1534 "%x ", data1);
1535
1536 for (j = 0; j < ARRAY_SIZE(vals); ++j) {
1537 i += scnprintf(buf + i, max - i, "[");
1538 mask = 0x80000000;
1539 once = 0;
1540 while (mask) {
1541 tmp = vals[j] & mask;
1542 mask >>= 1;
1543 if (!tmp)
1544 continue;
1545 sym = find_sym(SMSM_STATE_SYM,
1546 tmp);
1547
1548 if (once)
1549 i += scnprintf(buf + i,
1550 max - i,
1551 " ");
1552 if (sym)
1553 i += scnprintf(buf + i,
1554 max - i,
1555 "%s",
1556 sym);
1557 else
1558 i += scnprintf(buf + i,
1559 max - i,
1560 "0x%x",
1561 tmp);
1562 once = 1;
1563 }
1564 i += scnprintf(buf + i, max - i, "] ");
1565 }
1566#else
1567 } else if (id_val == DEMAPPS_WAKEUP_REASON) {
1568 unsigned mask = 0x80000000;
1569 unsigned tmp = 0;
1570 while (mask) {
1571 tmp = data1 & mask;
1572 mask >>= 1;
1573 if (!tmp)
1574 continue;
1575 sym = find_sym(WAKEUP_SYM, tmp);
1576 if (sym)
1577 i += scnprintf(buf + i,
1578 max - i,
1579 "%s ",
1580 sym);
1581 else
1582 i += scnprintf(buf + i,
1583 max - i,
1584 "%08x ",
1585 tmp);
1586 }
1587 i += scnprintf(buf + i, max - i,
1588 "%08x %08x", data2, data3);
1589 } else if (id_val == DEMMOD_APPS_WAKEUP_INT) {
1590 sym = find_sym(WAKEUP_INT_SYM, data1);
1591
1592 if (sym)
1593 i += scnprintf(buf + i, max - i,
1594 "%s %08x %08x",
1595 sym, data2, data3);
1596 else
1597 i += scnprintf(buf + i, max - i,
1598 "%08x %08x %08x",
1599 data1, data2, data3);
1600 } else if (id_val == DEM_NO_SLEEP ||
1601 id_val == NO_SLEEP_NEW) {
1602 unsigned vals[] = {data3, data2};
1603 unsigned j;
1604 unsigned mask;
1605 unsigned tmp;
1606 unsigned once;
1607 i += scnprintf(buf + i, max - i, "%08x ",
1608 data1);
1609 i += scnprintf(buf + i, max - i, "[");
1610 once = 0;
1611 for (j = 0; j < ARRAY_SIZE(vals); ++j) {
1612 mask = 0x00000001;
1613 while (mask) {
1614 tmp = vals[j] & mask;
1615 mask <<= 1;
1616 if (!tmp)
1617 continue;
1618 if (j == 0)
1619 sym = find_sym(
1620 VOTER_D3_SYM,
1621 tmp);
1622 else
1623 sym = find_sym(
1624 VOTER_D2_SYM,
1625 tmp);
1626
1627 if (once)
1628 i += scnprintf(buf + i,
1629 max - i,
1630 " ");
1631 if (sym)
1632 i += scnprintf(buf + i,
1633 max - i,
1634 "%s",
1635 sym);
1636 else
1637 i += scnprintf(buf + i,
1638 max - i,
1639 "%08x",
1640 tmp);
1641 once = 1;
1642 }
1643 }
1644 i += scnprintf(buf + i, max - i, "] ");
1645#endif
1646 } else if (id_val == SMEM_LOG_EVENT_CB) {
1647 unsigned vals[] = {data2, data3};
1648 unsigned j;
1649 unsigned mask;
1650 unsigned tmp;
1651 unsigned once;
1652 i += scnprintf(buf + i, max - i, "%08x ",
1653 data1);
1654 for (j = 0; j < ARRAY_SIZE(vals); ++j) {
1655 i += scnprintf(buf + i, max - i, "[");
1656 mask = 0x80000000;
1657 once = 0;
1658 while (mask) {
1659 tmp = vals[j] & mask;
1660 mask >>= 1;
1661 if (!tmp)
1662 continue;
1663 sym = find_sym(SMSM_SYM, tmp);
1664
1665 if (once)
1666 i += scnprintf(buf + i,
1667 max - i,
1668 " ");
1669 if (sym)
1670 i += scnprintf(buf + i,
1671 max - i,
1672 "%s",
1673 sym);
1674 else
1675 i += scnprintf(buf + i,
1676 max - i,
1677 "%08x",
1678 tmp);
1679 once = 1;
1680 }
1681 i += scnprintf(buf + i, max - i, "] ");
1682 }
1683 } else {
1684 i += scnprintf(buf + i, max - i,
1685 "%08x %08x %08x",
1686 data1, data2, data3);
1687 }
1688 }
1689 }
1690 if (cont) {
1691 inst[log].read_idx = idx;
1692 read_avail = (write_idx - inst[log].read_idx);
1693 if (read_avail < 0)
1694 read_avail = inst->num - inst->read_idx + write_idx;
1695 inst[log].last_read_avail = read_avail;
1696 }
1697
1698 remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
1699
1700 DBG("%s: read %d write %d idx %d num %d\n", __func__,
1701 inst[log].read_idx, write_idx, idx, inst[log].num);
1702
1703 return i;
1704}
1705
1706static int debug_dump(char *buf, int max, uint32_t cont)
1707{
1708 int r;
Eric Holmberg16653352012-03-28 16:16:47 -06001709
1710 if (!inst[GEN].idx || !inst[GEN].events)
1711 return -ENODEV;
1712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713 while (cont) {
1714 update_read_avail(&inst[GEN]);
1715 r = wait_event_interruptible_timeout(inst[GEN].read_wait,
1716 inst[GEN].last_read_avail,
1717 smem_log_timeout_ms *
1718 HZ / 1000);
1719 DBG("%s: read available %d\n", __func__,
1720 inst[GEN].last_read_avail);
1721 if (r < 0)
1722 return 0;
1723 else if (inst[GEN].last_read_avail)
1724 break;
1725 }
1726
1727 return _debug_dump(GEN, buf, max, cont);
1728}
1729
1730static int debug_dump_sym(char *buf, int max, uint32_t cont)
1731{
1732 int r;
Eric Holmberg16653352012-03-28 16:16:47 -06001733
1734 if (!inst[GEN].idx || !inst[GEN].events)
1735 return -ENODEV;
1736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 while (cont) {
1738 update_read_avail(&inst[GEN]);
1739 r = wait_event_interruptible_timeout(inst[GEN].read_wait,
1740 inst[GEN].last_read_avail,
1741 smem_log_timeout_ms *
1742 HZ / 1000);
1743 DBG("%s: readavailable %d\n", __func__,
1744 inst[GEN].last_read_avail);
1745 if (r < 0)
1746 return 0;
1747 else if (inst[GEN].last_read_avail)
1748 break;
1749 }
1750
1751 return _debug_dump_sym(GEN, buf, max, cont);
1752}
1753
1754static int debug_dump_static(char *buf, int max, uint32_t cont)
1755{
1756 int r;
Eric Holmberg16653352012-03-28 16:16:47 -06001757
1758 if (!inst[STA].idx || !inst[STA].events)
1759 return -ENODEV;
1760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 while (cont) {
1762 update_read_avail(&inst[STA]);
1763 r = wait_event_interruptible_timeout(inst[STA].read_wait,
1764 inst[STA].last_read_avail,
1765 smem_log_timeout_ms *
1766 HZ / 1000);
1767 DBG("%s: readavailable %d\n", __func__,
1768 inst[STA].last_read_avail);
1769 if (r < 0)
1770 return 0;
1771 else if (inst[STA].last_read_avail)
1772 break;
1773 }
1774
1775 return _debug_dump(STA, buf, max, cont);
1776}
1777
1778static int debug_dump_static_sym(char *buf, int max, uint32_t cont)
1779{
1780 int r;
Eric Holmberg16653352012-03-28 16:16:47 -06001781
1782 if (!inst[STA].idx || !inst[STA].events)
1783 return -ENODEV;
1784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 while (cont) {
1786 update_read_avail(&inst[STA]);
1787 r = wait_event_interruptible_timeout(inst[STA].read_wait,
1788 inst[STA].last_read_avail,
1789 smem_log_timeout_ms *
1790 HZ / 1000);
1791 DBG("%s: readavailable %d\n", __func__,
1792 inst[STA].last_read_avail);
1793 if (r < 0)
1794 return 0;
1795 else if (inst[STA].last_read_avail)
1796 break;
1797 }
1798
1799 return _debug_dump_sym(STA, buf, max, cont);
1800}
1801
1802static int debug_dump_power(char *buf, int max, uint32_t cont)
1803{
1804 int r;
Eric Holmberg16653352012-03-28 16:16:47 -06001805
1806 if (!inst[POW].idx || !inst[POW].events)
1807 return -ENODEV;
1808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 while (cont) {
1810 update_read_avail(&inst[POW]);
1811 r = wait_event_interruptible_timeout(inst[POW].read_wait,
1812 inst[POW].last_read_avail,
1813 smem_log_timeout_ms *
1814 HZ / 1000);
1815 DBG("%s: readavailable %d\n", __func__,
1816 inst[POW].last_read_avail);
1817 if (r < 0)
1818 return 0;
1819 else if (inst[POW].last_read_avail)
1820 break;
1821 }
1822
1823 return _debug_dump(POW, buf, max, cont);
1824}
1825
1826static int debug_dump_power_sym(char *buf, int max, uint32_t cont)
1827{
1828 int r;
Eric Holmberg16653352012-03-28 16:16:47 -06001829
1830 if (!inst[POW].idx || !inst[POW].events)
1831 return -ENODEV;
1832
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 while (cont) {
1834 update_read_avail(&inst[POW]);
1835 r = wait_event_interruptible_timeout(inst[POW].read_wait,
1836 inst[POW].last_read_avail,
1837 smem_log_timeout_ms *
1838 HZ / 1000);
1839 DBG("%s: readavailable %d\n", __func__,
1840 inst[POW].last_read_avail);
1841 if (r < 0)
1842 return 0;
1843 else if (inst[POW].last_read_avail)
1844 break;
1845 }
1846
1847 return _debug_dump_sym(POW, buf, max, cont);
1848}
1849
1850static int debug_dump_voters(char *buf, int max, uint32_t cont)
1851{
1852 return _debug_dump_voters(buf, max);
1853}
1854
1855static char debug_buffer[EVENTS_PRINT_SIZE];
1856
1857static ssize_t debug_read(struct file *file, char __user *buf,
1858 size_t count, loff_t *ppos)
1859{
1860 int r;
Eric Holmberg16653352012-03-28 16:16:47 -06001861 int bsize = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001862 int (*fill)(char *, int, uint32_t) = file->private_data;
Eric Holmberg16653352012-03-28 16:16:47 -06001863 if (!(*ppos)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 bsize = fill(debug_buffer, EVENTS_PRINT_SIZE, 0);
Eric Holmberg16653352012-03-28 16:16:47 -06001865
1866 if (bsize < 0)
1867 bsize = scnprintf(debug_buffer,
1868 EVENTS_PRINT_SIZE, "Log not available\n");
1869 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 DBG("%s: count %d ppos %d\n", __func__, count, (unsigned int)*ppos);
1871 r = simple_read_from_buffer(buf, count, ppos, debug_buffer,
1872 bsize);
1873 return r;
1874}
1875
1876static ssize_t debug_read_cont(struct file *file, char __user *buf,
1877 size_t count, loff_t *ppos)
1878{
1879 int (*fill)(char *, int, uint32_t) = file->private_data;
1880 char *buffer = kmalloc(count, GFP_KERNEL);
1881 int bsize;
1882 if (!buffer)
1883 return -ENOMEM;
Eric Holmberg16653352012-03-28 16:16:47 -06001884
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885 bsize = fill(buffer, count, 1);
Eric Holmberg16653352012-03-28 16:16:47 -06001886 if (bsize < 0) {
1887 if (*ppos == 0)
1888 bsize = scnprintf(buffer, count, "Log not available\n");
1889 else
1890 bsize = 0;
1891 }
1892
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001893 DBG("%s: count %d bsize %d\n", __func__, count, bsize);
1894 if (copy_to_user(buf, buffer, bsize)) {
1895 kfree(buffer);
1896 return -EFAULT;
1897 }
Eric Holmberg16653352012-03-28 16:16:47 -06001898 *ppos += bsize;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899 kfree(buffer);
1900 return bsize;
1901}
1902
1903static int debug_open(struct inode *inode, struct file *file)
1904{
1905 file->private_data = inode->i_private;
1906 return 0;
1907}
1908
1909static const struct file_operations debug_ops = {
1910 .read = debug_read,
1911 .open = debug_open,
1912};
1913
1914static const struct file_operations debug_ops_cont = {
1915 .read = debug_read_cont,
1916 .open = debug_open,
1917};
1918
1919static void debug_create(const char *name, mode_t mode,
1920 struct dentry *dent,
1921 int (*fill)(char *buf, int max, uint32_t cont),
1922 const struct file_operations *fops)
1923{
1924 debugfs_create_file(name, mode, dent, fill, fops);
1925}
1926
1927static void smem_log_debugfs_init(void)
1928{
1929 struct dentry *dent;
1930
1931 dent = debugfs_create_dir("smem_log", 0);
1932 if (IS_ERR(dent))
1933 return;
1934
1935 debug_create("dump", 0444, dent, debug_dump, &debug_ops);
1936 debug_create("dump_sym", 0444, dent, debug_dump_sym, &debug_ops);
1937 debug_create("dump_static", 0444, dent, debug_dump_static, &debug_ops);
1938 debug_create("dump_static_sym", 0444, dent,
1939 debug_dump_static_sym, &debug_ops);
1940 debug_create("dump_power", 0444, dent, debug_dump_power, &debug_ops);
1941 debug_create("dump_power_sym", 0444, dent,
1942 debug_dump_power_sym, &debug_ops);
1943 debug_create("dump_voters", 0444, dent,
1944 debug_dump_voters, &debug_ops);
1945
1946 debug_create("dump_cont", 0444, dent, debug_dump, &debug_ops_cont);
1947 debug_create("dump_sym_cont", 0444, dent,
1948 debug_dump_sym, &debug_ops_cont);
1949 debug_create("dump_static_cont", 0444, dent,
1950 debug_dump_static, &debug_ops_cont);
1951 debug_create("dump_static_sym_cont", 0444, dent,
1952 debug_dump_static_sym, &debug_ops_cont);
1953 debug_create("dump_power_cont", 0444, dent,
1954 debug_dump_power, &debug_ops_cont);
1955 debug_create("dump_power_sym_cont", 0444, dent,
1956 debug_dump_power_sym, &debug_ops_cont);
1957
1958 smem_log_timeout_ms = 500;
1959 smem_log_debug_mask = 0;
1960}
1961#else
1962static void smem_log_debugfs_init(void) {}
1963#endif
1964
1965static int smem_log_initialize(void)
1966{
1967 int ret;
1968
1969 ret = _smem_log_init();
1970 if (ret < 0) {
1971 pr_err("%s: init failed %d\n", __func__, ret);
1972 return ret;
1973 }
1974
1975 ret = misc_register(&smem_log_dev);
1976 if (ret < 0) {
1977 pr_err("%s: device register failed %d\n", __func__, ret);
1978 return ret;
1979 }
1980
1981 smem_log_enable = 1;
1982 smem_log_initialized = 1;
1983 smem_log_debugfs_init();
1984 return ret;
1985}
1986
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -06001987static int smsm_driver_state_notifier(struct notifier_block *this,
1988 unsigned long code,
1989 void *_cmd)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990{
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -06001991 int ret = 0;
1992 if (code & SMSM_INIT) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 if (!smem_log_initialized)
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -06001994 ret = smem_log_initialize();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001995 }
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -06001996 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997}
1998
1999static struct notifier_block nb = {
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -06002000 .notifier_call = smsm_driver_state_notifier,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001};
2002
2003static int __init smem_log_init(void)
2004{
Karthikeyan Ramasubramanian867a9292012-03-22 17:20:20 -06002005 return smsm_driver_state_notifier_register(&nb);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006}
2007
2008
2009module_init(smem_log_init);
2010
2011MODULE_DESCRIPTION("smem log");
2012MODULE_LICENSE("GPL v2");