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