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