879 lines
22 KiB
C
879 lines
22 KiB
C
/* arch/arm/mach-msm/smd_debug.c
|
|
*
|
|
* Copyright (C) 2007 Google, Inc.
|
|
* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
|
|
* Author: Brian Swetland <swetland@google.com>
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#include <linux/debugfs.h>
|
|
#include <linux/list.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/jiffies.h>
|
|
|
|
#include <mach/msm_iomap.h>
|
|
#include <mach/msm_smem.h>
|
|
|
|
#include "smd_private.h"
|
|
#include "smem_private.h"
|
|
|
|
#if defined(CONFIG_DEBUG_FS)
|
|
|
|
static char *chstate(unsigned n)
|
|
{
|
|
switch (n) {
|
|
case SMD_SS_CLOSED:
|
|
return "CLOSED";
|
|
case SMD_SS_OPENING:
|
|
return "OPENING";
|
|
case SMD_SS_OPENED:
|
|
return "OPENED";
|
|
case SMD_SS_FLUSHING:
|
|
return "FLUSHING";
|
|
case SMD_SS_CLOSING:
|
|
return "CLOSING";
|
|
case SMD_SS_RESET:
|
|
return "RESET";
|
|
case SMD_SS_RESET_OPENING:
|
|
return "ROPENING";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static int debug_f3(char *buf, int max)
|
|
{
|
|
char *x;
|
|
int size;
|
|
int i = 0, j = 0;
|
|
unsigned cols = 0;
|
|
char str[4*sizeof(unsigned)+1] = {0};
|
|
|
|
i += scnprintf(buf + i, max - i,
|
|
"Printing to log\n");
|
|
|
|
x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size);
|
|
if (x != 0) {
|
|
pr_info("smem: F3 TRACE LOG\n");
|
|
while (size > 0) {
|
|
if (size >= sizeof(unsigned)) {
|
|
pr_info("%08x", *((unsigned *) x));
|
|
for (j = 0; j < sizeof(unsigned); ++j)
|
|
if (isprint(*(x+j)))
|
|
str[cols*sizeof(unsigned) + j]
|
|
= *(x+j);
|
|
else
|
|
str[cols*sizeof(unsigned) + j]
|
|
= '-';
|
|
x += sizeof(unsigned);
|
|
size -= sizeof(unsigned);
|
|
} else {
|
|
while (size-- > 0)
|
|
pr_info("%02x", (unsigned) *x++);
|
|
break;
|
|
}
|
|
if (cols == 3) {
|
|
cols = 0;
|
|
str[4*sizeof(unsigned)] = 0;
|
|
pr_info(" %s\n", str);
|
|
str[0] = 0;
|
|
} else {
|
|
cols++;
|
|
pr_info(" ");
|
|
}
|
|
}
|
|
pr_info("\n");
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
static int debug_int_stats(char *buf, int max)
|
|
{
|
|
int i = 0;
|
|
int subsys;
|
|
struct interrupt_stat *stats = interrupt_stats;
|
|
const char *subsys_name;
|
|
|
|
i += scnprintf(buf + i, max - i,
|
|
" Subsystem | Interrupt ID | In | Out (Hardcoded) |"
|
|
" Out (Configured)|\n");
|
|
|
|
for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
|
|
subsys_name = smd_pid_to_subsystem(subsys);
|
|
if (subsys_name) {
|
|
i += scnprintf(buf + i, max - i,
|
|
"%-10s %4s | %9d | %9u | %9u | %9u |\n",
|
|
smd_pid_to_subsystem(subsys), "smd",
|
|
stats->smd_interrupt_id,
|
|
stats->smd_in_count,
|
|
stats->smd_out_hardcode_count,
|
|
stats->smd_out_config_count);
|
|
|
|
i += scnprintf(buf + i, max - i,
|
|
"%-10s %4s | %9d | %9u | %9u | %9u |\n",
|
|
smd_pid_to_subsystem(subsys), "smsm",
|
|
stats->smsm_interrupt_id,
|
|
stats->smsm_in_count,
|
|
stats->smsm_out_hardcode_count,
|
|
stats->smsm_out_config_count);
|
|
}
|
|
++stats;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_int_stats_reset(char *buf, int max)
|
|
{
|
|
int i = 0;
|
|
int subsys;
|
|
struct interrupt_stat *stats = interrupt_stats;
|
|
|
|
i += scnprintf(buf + i, max - i, "Resetting interrupt stats.\n");
|
|
|
|
for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
|
|
stats->smd_in_count = 0;
|
|
stats->smd_out_hardcode_count = 0;
|
|
stats->smd_out_config_count = 0;
|
|
stats->smsm_in_count = 0;
|
|
stats->smsm_out_hardcode_count = 0;
|
|
stats->smsm_out_config_count = 0;
|
|
++stats;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_diag(char *buf, int max)
|
|
{
|
|
int i = 0;
|
|
|
|
i += scnprintf(buf + i, max - i,
|
|
"Printing to log\n");
|
|
smd_diag();
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_modem_err_f3(char *buf, int max)
|
|
{
|
|
char *x;
|
|
int size;
|
|
int i = 0, j = 0;
|
|
unsigned cols = 0;
|
|
char str[4*sizeof(unsigned)+1] = {0};
|
|
|
|
x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size);
|
|
if (x != 0) {
|
|
pr_info("smem: F3 TRACE LOG\n");
|
|
while (size > 0 && max - i) {
|
|
if (size >= sizeof(unsigned)) {
|
|
i += scnprintf(buf + i, max - i, "%08x",
|
|
*((unsigned *) x));
|
|
for (j = 0; j < sizeof(unsigned); ++j)
|
|
if (isprint(*(x+j)))
|
|
str[cols*sizeof(unsigned) + j]
|
|
= *(x+j);
|
|
else
|
|
str[cols*sizeof(unsigned) + j]
|
|
= '-';
|
|
x += sizeof(unsigned);
|
|
size -= sizeof(unsigned);
|
|
} else {
|
|
while (size-- > 0 && max - i)
|
|
i += scnprintf(buf + i, max - i,
|
|
"%02x",
|
|
(unsigned) *x++);
|
|
break;
|
|
}
|
|
if (cols == 3) {
|
|
cols = 0;
|
|
str[4*sizeof(unsigned)] = 0;
|
|
i += scnprintf(buf + i, max - i, " %s\n",
|
|
str);
|
|
str[0] = 0;
|
|
} else {
|
|
cols++;
|
|
i += scnprintf(buf + i, max - i, " ");
|
|
}
|
|
}
|
|
i += scnprintf(buf + i, max - i, "\n");
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_modem_err(char *buf, int max)
|
|
{
|
|
char *x;
|
|
int size;
|
|
int i = 0;
|
|
|
|
x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
|
|
if (x != 0) {
|
|
x[SZ_DIAG_ERR_MSG - 1] = 0;
|
|
i += scnprintf(buf + i, max - i,
|
|
"smem: DIAG '%s'\n", x);
|
|
}
|
|
|
|
x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size);
|
|
if (x != 0) {
|
|
x[size - 1] = 0;
|
|
i += scnprintf(buf + i, max - i,
|
|
"smem: CRASH LOG\n'%s'\n", x);
|
|
}
|
|
i += scnprintf(buf + i, max - i, "\n");
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_read_diag_msg(char *buf, int max)
|
|
{
|
|
char *msg;
|
|
int i = 0;
|
|
|
|
msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
|
|
|
|
if (msg) {
|
|
msg[SZ_DIAG_ERR_MSG - 1] = 0;
|
|
i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static int dump_ch(char *buf, int max, int n,
|
|
void *half_ch_s,
|
|
void *half_ch_r,
|
|
struct smd_half_channel_access *half_ch_funcs,
|
|
unsigned size)
|
|
{
|
|
return scnprintf(
|
|
buf, max,
|
|
"ch%02d:"
|
|
" %8s(%04d/%04d) %c%c%c%c%c%c%c%c <->"
|
|
" %8s(%04d/%04d) %c%c%c%c%c%c%c%c : %5x\n", n,
|
|
chstate(half_ch_funcs->get_state(half_ch_s)),
|
|
half_ch_funcs->get_tail(half_ch_s),
|
|
half_ch_funcs->get_head(half_ch_s),
|
|
half_ch_funcs->get_fDSR(half_ch_s) ? 'D' : 'd',
|
|
half_ch_funcs->get_fCTS(half_ch_s) ? 'C' : 'c',
|
|
half_ch_funcs->get_fCD(half_ch_s) ? 'C' : 'c',
|
|
half_ch_funcs->get_fRI(half_ch_s) ? 'I' : 'i',
|
|
half_ch_funcs->get_fHEAD(half_ch_s) ? 'W' : 'w',
|
|
half_ch_funcs->get_fTAIL(half_ch_s) ? 'R' : 'r',
|
|
half_ch_funcs->get_fSTATE(half_ch_s) ? 'S' : 's',
|
|
half_ch_funcs->get_fBLOCKREADINTR(half_ch_s) ? 'B' : 'b',
|
|
chstate(half_ch_funcs->get_state(half_ch_r)),
|
|
half_ch_funcs->get_tail(half_ch_r),
|
|
half_ch_funcs->get_head(half_ch_r),
|
|
half_ch_funcs->get_fDSR(half_ch_r) ? 'D' : 'd',
|
|
half_ch_funcs->get_fCTS(half_ch_r) ? 'C' : 'c',
|
|
half_ch_funcs->get_fCD(half_ch_r) ? 'C' : 'c',
|
|
half_ch_funcs->get_fRI(half_ch_r) ? 'I' : 'i',
|
|
half_ch_funcs->get_fHEAD(half_ch_r) ? 'W' : 'w',
|
|
half_ch_funcs->get_fTAIL(half_ch_r) ? 'R' : 'r',
|
|
half_ch_funcs->get_fSTATE(half_ch_r) ? 'S' : 's',
|
|
half_ch_funcs->get_fBLOCKREADINTR(half_ch_r) ? 'B' : 'b',
|
|
size
|
|
);
|
|
}
|
|
|
|
static int debug_read_smsm_state(char *buf, int max)
|
|
{
|
|
uint32_t *smsm;
|
|
int n, i = 0;
|
|
|
|
smsm = smem_find(ID_SHARED_STATE,
|
|
SMSM_NUM_ENTRIES * sizeof(uint32_t));
|
|
|
|
if (smsm)
|
|
for (n = 0; n < SMSM_NUM_ENTRIES; n++)
|
|
i += scnprintf(buf + i, max - i, "entry %d: 0x%08x\n",
|
|
n, smsm[n]);
|
|
|
|
return i;
|
|
}
|
|
|
|
struct SMSM_CB_DATA {
|
|
int cb_count;
|
|
void *data;
|
|
uint32_t old_state;
|
|
uint32_t new_state;
|
|
};
|
|
static struct SMSM_CB_DATA smsm_cb_data;
|
|
static struct completion smsm_cb_completion;
|
|
|
|
static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
|
|
{
|
|
smsm_cb_data.cb_count++;
|
|
smsm_cb_data.old_state = old_state;
|
|
smsm_cb_data.new_state = new_state;
|
|
smsm_cb_data.data = data;
|
|
complete_all(&smsm_cb_completion);
|
|
}
|
|
|
|
#define UT_EQ_INT(a, b) \
|
|
if ((a) != (b)) { \
|
|
i += scnprintf(buf + i, max - i, \
|
|
"%s:%d " #a "(%d) != " #b "(%d)\n", \
|
|
__func__, __LINE__, \
|
|
a, b); \
|
|
break; \
|
|
} \
|
|
do {} while (0)
|
|
|
|
#define UT_GT_INT(a, b) \
|
|
if ((a) <= (b)) { \
|
|
i += scnprintf(buf + i, max - i, \
|
|
"%s:%d " #a "(%d) > " #b "(%d)\n", \
|
|
__func__, __LINE__, \
|
|
a, b); \
|
|
break; \
|
|
} \
|
|
do {} while (0)
|
|
|
|
#define SMSM_CB_TEST_INIT() \
|
|
do { \
|
|
smsm_cb_data.cb_count = 0; \
|
|
smsm_cb_data.old_state = 0; \
|
|
smsm_cb_data.new_state = 0; \
|
|
smsm_cb_data.data = 0; \
|
|
} while (0)
|
|
|
|
|
|
static int debug_test_smsm(char *buf, int max)
|
|
{
|
|
int i = 0;
|
|
int test_num = 0;
|
|
int ret;
|
|
|
|
/* Test case 1 - Register new callback for notification */
|
|
do {
|
|
test_num++;
|
|
SMSM_CB_TEST_INIT();
|
|
ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_SMDINIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 0);
|
|
|
|
/* de-assert SMSM_SMD_INIT to trigger state update */
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 0);
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 1);
|
|
UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, SMSM_SMDINIT);
|
|
UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, 0x0);
|
|
UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
|
|
|
|
/* re-assert SMSM_SMD_INIT to trigger state update */
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 2);
|
|
UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, 0x0);
|
|
UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, SMSM_SMDINIT);
|
|
|
|
/* deregister callback */
|
|
ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_SMDINIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 2);
|
|
|
|
/* make sure state change doesn't cause any more callbacks */
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
|
|
UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 2);
|
|
|
|
i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
|
|
} while (0);
|
|
|
|
/* Test case 2 - Update already registered callback */
|
|
do {
|
|
test_num++;
|
|
SMSM_CB_TEST_INIT();
|
|
ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_SMDINIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 0);
|
|
ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_INIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 1);
|
|
|
|
/* verify both callback bits work */
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 0);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 1);
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 2);
|
|
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 3);
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 4);
|
|
|
|
/* deregister 1st callback */
|
|
ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_SMDINIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 1);
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
|
|
UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 4);
|
|
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 5);
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 6);
|
|
|
|
/* deregister 2nd callback */
|
|
ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_INIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 2);
|
|
|
|
/* make sure state change doesn't cause any more callbacks */
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
|
|
UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 6);
|
|
|
|
i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
|
|
} while (0);
|
|
|
|
/* Test case 3 - Two callback registrations with different data */
|
|
do {
|
|
test_num++;
|
|
SMSM_CB_TEST_INIT();
|
|
ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_SMDINIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 0);
|
|
ret = smsm_state_cb_register(SMSM_APPS_STATE, SMSM_INIT,
|
|
smsm_state_cb, (void *)0x3456);
|
|
UT_EQ_INT(ret, 0);
|
|
|
|
/* verify both callbacks work */
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 0);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 1);
|
|
UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
|
|
|
|
INIT_COMPLETION(smsm_cb_completion);
|
|
smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
|
|
UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
|
|
msecs_to_jiffies(20)), 0);
|
|
UT_EQ_INT(smsm_cb_data.cb_count, 2);
|
|
UT_EQ_INT((int)smsm_cb_data.data, 0x3456);
|
|
|
|
/* cleanup and unregister
|
|
* degregister in reverse to verify data field is
|
|
* being used
|
|
*/
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
|
|
smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
|
|
ret = smsm_state_cb_deregister(SMSM_APPS_STATE,
|
|
SMSM_INIT,
|
|
smsm_state_cb, (void *)0x3456);
|
|
UT_EQ_INT(ret, 2);
|
|
ret = smsm_state_cb_deregister(SMSM_APPS_STATE,
|
|
SMSM_SMDINIT,
|
|
smsm_state_cb, (void *)0x1234);
|
|
UT_EQ_INT(ret, 2);
|
|
|
|
i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
|
|
} while (0);
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_read_mem(char *buf, int max)
|
|
{
|
|
unsigned n;
|
|
struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
|
|
struct smem_heap_entry *toc = shared->heap_toc;
|
|
int i = 0;
|
|
|
|
i += scnprintf(buf + i, max - i,
|
|
"heap: init=%d free=%d remain=%d\n",
|
|
shared->heap_info.initialized,
|
|
shared->heap_info.free_offset,
|
|
shared->heap_info.heap_remaining);
|
|
|
|
for (n = 0; n < SMEM_NUM_ITEMS; n++) {
|
|
if (toc[n].allocated == 0)
|
|
continue;
|
|
i += scnprintf(buf + i, max - i,
|
|
"%04d: offset %08x size %08x\n",
|
|
n, toc[n].offset, toc[n].size);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
#if (!defined(CONFIG_MSM_SMD_PKG4) && !defined(CONFIG_MSM_SMD_PKG3))
|
|
static int debug_read_ch(char *buf, int max)
|
|
{
|
|
void *shared;
|
|
int n, i = 0;
|
|
struct smd_alloc_elm *ch_tbl;
|
|
unsigned ch_type;
|
|
unsigned shared_size;
|
|
|
|
ch_tbl = smem_find(ID_CH_ALLOC_TBL, sizeof(*ch_tbl) * 64);
|
|
if (!ch_tbl)
|
|
goto fail;
|
|
|
|
for (n = 0; n < SMD_CHANNELS; n++) {
|
|
ch_type = SMD_CHANNEL_TYPE(ch_tbl[n].type);
|
|
if (is_word_access_ch(ch_type))
|
|
shared_size =
|
|
sizeof(struct smd_half_channel_word_access);
|
|
else
|
|
shared_size = sizeof(struct smd_half_channel);
|
|
shared = smem_find(ID_SMD_CHANNELS + n,
|
|
2 * shared_size + SMD_BUF_SIZE);
|
|
|
|
if (shared == 0)
|
|
continue;
|
|
i += dump_ch(buf + i, max - i, n, shared,
|
|
(shared + shared_size +
|
|
SMD_BUF_SIZE), get_half_ch_funcs(ch_type),
|
|
SMD_BUF_SIZE);
|
|
}
|
|
|
|
fail:
|
|
return i;
|
|
}
|
|
#else
|
|
static int debug_read_ch(char *buf, int max)
|
|
{
|
|
void *shared, *buffer;
|
|
unsigned buffer_sz;
|
|
int n, i = 0;
|
|
struct smd_alloc_elm *ch_tbl;
|
|
unsigned ch_type;
|
|
unsigned shared_size;
|
|
|
|
ch_tbl = smem_find(ID_CH_ALLOC_TBL, sizeof(*ch_tbl) * 64);
|
|
if (!ch_tbl)
|
|
goto fail;
|
|
|
|
for (n = 0; n < SMD_CHANNELS; n++) {
|
|
ch_type = SMD_CHANNEL_TYPE(ch_tbl[n].type);
|
|
if (is_word_access_ch(ch_type))
|
|
shared_size =
|
|
sizeof(struct smd_half_channel_word_access);
|
|
else
|
|
shared_size = sizeof(struct smd_half_channel);
|
|
|
|
shared = smem_find(ID_SMD_CHANNELS + n, 2 * shared_size);
|
|
|
|
if (shared == 0)
|
|
continue;
|
|
|
|
buffer = smem_get_entry(SMEM_SMD_FIFO_BASE_ID + n, &buffer_sz);
|
|
|
|
if (buffer == 0)
|
|
continue;
|
|
|
|
i += dump_ch(buf + i, max - i, n, shared,
|
|
(shared + shared_size),
|
|
get_half_ch_funcs(ch_type),
|
|
buffer_sz / 2);
|
|
}
|
|
|
|
fail:
|
|
return i;
|
|
}
|
|
#endif
|
|
|
|
static int debug_read_smem_version(char *buf, int max)
|
|
{
|
|
struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
|
|
uint32_t n, version, i = 0;
|
|
|
|
for (n = 0; n < 32; n++) {
|
|
version = shared->version[n];
|
|
i += scnprintf(buf + i, max - i,
|
|
"entry %d: smem = %d proc_comm = %d\n", n,
|
|
version >> 16,
|
|
version & 0xffff);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
/* NNV: revist, it may not be smd version */
|
|
static int debug_read_smd_version(char *buf, int max)
|
|
{
|
|
uint32_t *smd_ver;
|
|
uint32_t n, version, i = 0;
|
|
|
|
smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t));
|
|
|
|
if (smd_ver)
|
|
for (n = 0; n < 32; n++) {
|
|
version = smd_ver[n];
|
|
i += scnprintf(buf + i, max - i,
|
|
"entry %d: %d.%d\n", n,
|
|
version >> 16,
|
|
version & 0xffff);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_read_build_id(char *buf, int max)
|
|
{
|
|
unsigned size;
|
|
void *data;
|
|
|
|
data = smem_get_entry(SMEM_HW_SW_BUILD_ID, &size);
|
|
if (!data)
|
|
return 0;
|
|
|
|
if (size >= max)
|
|
size = max;
|
|
memcpy(buf, data, size);
|
|
|
|
return size;
|
|
}
|
|
|
|
static int debug_read_alloc_tbl(char *buf, int max)
|
|
{
|
|
struct smd_alloc_elm *shared;
|
|
int n, i = 0;
|
|
|
|
shared = smem_find(ID_CH_ALLOC_TBL, sizeof(struct smd_alloc_elm[64]));
|
|
|
|
if (!shared)
|
|
return 0;
|
|
|
|
for (n = 0; n < 64; n++) {
|
|
i += scnprintf(buf + i, max - i,
|
|
"name=%s cid=%d ch type=%d "
|
|
"xfer type=%d ref_count=%d\n",
|
|
shared[n].name,
|
|
shared[n].cid,
|
|
SMD_CHANNEL_TYPE(shared[n].type),
|
|
SMD_XFER_TYPE(shared[n].type),
|
|
shared[n].ref_count);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_read_intr_mask(char *buf, int max)
|
|
{
|
|
uint32_t *smsm;
|
|
int m, n, i = 0;
|
|
|
|
smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK,
|
|
SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t));
|
|
|
|
if (smsm)
|
|
for (m = 0; m < SMSM_NUM_ENTRIES; m++) {
|
|
i += scnprintf(buf + i, max - i, "entry %d:", m);
|
|
for (n = 0; n < SMSM_NUM_HOSTS; n++)
|
|
i += scnprintf(buf + i, max - i,
|
|
" host %d: 0x%08x",
|
|
n, smsm[m * SMSM_NUM_HOSTS + n]);
|
|
i += scnprintf(buf + i, max - i, "\n");
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static int debug_read_intr_mux(char *buf, int max)
|
|
{
|
|
uint32_t *smsm;
|
|
int n, i = 0;
|
|
|
|
smsm = smem_alloc(SMEM_SMD_SMSM_INTR_MUX,
|
|
SMSM_NUM_INTR_MUX * sizeof(uint32_t));
|
|
|
|
if (smsm)
|
|
for (n = 0; n < SMSM_NUM_INTR_MUX; n++)
|
|
i += scnprintf(buf + i, max - i, "entry %d: %d\n",
|
|
n, smsm[n]);
|
|
|
|
return i;
|
|
}
|
|
|
|
#define DEBUG_BUFMAX 4096
|
|
static char debug_buffer[DEBUG_BUFMAX];
|
|
|
|
static ssize_t debug_read(struct file *file, char __user *buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
int (*fill)(char *buf, int max) = file->private_data;
|
|
int bsize;
|
|
|
|
if (*ppos != 0)
|
|
return 0;
|
|
|
|
bsize = fill(debug_buffer, DEBUG_BUFMAX);
|
|
return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
|
|
}
|
|
|
|
static const struct file_operations debug_ops = {
|
|
.read = debug_read,
|
|
.open = simple_open,
|
|
};
|
|
|
|
static void debug_create(const char *name, umode_t mode,
|
|
struct dentry *dent,
|
|
int (*fill)(char *buf, int max))
|
|
{
|
|
debugfs_create_file(name, mode, dent, fill, &debug_ops);
|
|
}
|
|
|
|
static int __init smd_debugfs_init(void)
|
|
{
|
|
struct dentry *dent;
|
|
|
|
dent = debugfs_create_dir("smd", 0);
|
|
if (IS_ERR(dent))
|
|
return PTR_ERR(dent);
|
|
|
|
debug_create("ch", 0444, dent, debug_read_ch);
|
|
debug_create("diag", 0444, dent, debug_read_diag_msg);
|
|
debug_create("mem", 0444, dent, debug_read_mem);
|
|
debug_create("version", 0444, dent, debug_read_smd_version);
|
|
debug_create("tbl", 0444, dent, debug_read_alloc_tbl);
|
|
debug_create("modem_err", 0444, dent, debug_modem_err);
|
|
debug_create("modem_err_f3", 0444, dent, debug_modem_err_f3);
|
|
debug_create("print_diag", 0444, dent, debug_diag);
|
|
debug_create("print_f3", 0444, dent, debug_f3);
|
|
debug_create("int_stats", 0444, dent, debug_int_stats);
|
|
debug_create("int_stats_reset", 0444, dent, debug_int_stats_reset);
|
|
|
|
/* NNV: this is google only stuff */
|
|
debug_create("build", 0444, dent, debug_read_build_id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __init smsm_debugfs_init(void)
|
|
{
|
|
struct dentry *dent;
|
|
|
|
dent = debugfs_create_dir("smsm", 0);
|
|
if (IS_ERR(dent))
|
|
return PTR_ERR(dent);
|
|
|
|
debug_create("state", 0444, dent, debug_read_smsm_state);
|
|
debug_create("intr_mask", 0444, dent, debug_read_intr_mask);
|
|
debug_create("intr_mux", 0444, dent, debug_read_intr_mux);
|
|
debug_create("version", 0444, dent, debug_read_smem_version);
|
|
debug_create("smsm_test", 0444, dent, debug_test_smsm);
|
|
|
|
init_completion(&smsm_cb_completion);
|
|
|
|
return 0;
|
|
}
|
|
|
|
late_initcall(smd_debugfs_init);
|
|
late_initcall(smsm_debugfs_init);
|
|
#endif
|
|
|
|
|
|
#define MAX_NUM_SLEEP_CLIENTS 64
|
|
#define MAX_SLEEP_NAME_LEN 8
|
|
|
|
#define NUM_GPIO_INT_REGISTERS 6
|
|
#define GPIO_SMEM_NUM_GROUPS 2
|
|
#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
|
|
|
|
struct tramp_gpio_save {
|
|
unsigned int enable;
|
|
unsigned int detect;
|
|
unsigned int polarity;
|
|
};
|
|
|
|
struct tramp_gpio_smem {
|
|
uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
|
|
uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
|
|
uint32_t enabled[NUM_GPIO_INT_REGISTERS];
|
|
uint32_t detection[NUM_GPIO_INT_REGISTERS];
|
|
uint32_t polarity[NUM_GPIO_INT_REGISTERS];
|
|
};
|
|
|
|
/*
|
|
* Print debug information on shared memory sleep variables
|
|
*/
|
|
void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
|
|
uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs)
|
|
{
|
|
unsigned long flags;
|
|
uint32_t *ptr;
|
|
struct tramp_gpio_smem *gpio;
|
|
|
|
spin_lock_irqsave(&smem_lock, flags);
|
|
|
|
pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", sleep_delay);
|
|
pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", sleep_limit);
|
|
|
|
ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr));
|
|
if (ptr)
|
|
pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr);
|
|
else
|
|
pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: missing\n");
|
|
|
|
pr_info("SMEM_SMSM_INT_INFO %x %x %x\n",
|
|
irq_mask, pending_irqs, wakeup_reason);
|
|
|
|
gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio));
|
|
if (gpio) {
|
|
int i;
|
|
for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++)
|
|
pr_info("SMEM_GPIO_INT: %d: e %x d %x p %x\n",
|
|
i, gpio->enabled[i], gpio->detection[i],
|
|
gpio->polarity[i]);
|
|
|
|
for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
|
|
pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n",
|
|
i, gpio->num_fired[i], gpio->fired[i][0],
|
|
gpio->fired[i][1]);
|
|
} else
|
|
pr_info("SMEM_GPIO_INT: missing\n");
|
|
|
|
spin_unlock_irqrestore(&smem_lock, flags);
|
|
}
|