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