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