ASoC: wcd934x: WDSP debug enhancement
Add interface to trigger WDSP dumps for debug use. Important register dump and WDSP ramdump are both collected when DEBUG_DUMP string is sent from userspace via WDSP misc node or when WDSP boot timeout happens. CRs-Fixed: 2117755 Change-Id: I8b91a8939201a54512a5e3557ce771b4ff2ff075 Signed-off-by: Walter Yang <yandongy@codeaurora.org>
This commit is contained in:
@@ -838,6 +838,45 @@ static int wdsp_ssr_handler(struct wdsp_mgr_priv *wdsp, void *arg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
static int wdsp_debug_dump_handler(struct wdsp_mgr_priv *wdsp, void *arg)
|
||||||
|
{
|
||||||
|
struct wdsp_err_signal_arg *err_data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
WDSP_MGR_MUTEX_LOCK(wdsp, wdsp->ssr_mutex);
|
||||||
|
/* If there is no SSR, set the SSR type to collect ramdumps */
|
||||||
|
if (wdsp->ssr_type == WDSP_SSR_TYPE_NO_SSR) {
|
||||||
|
wdsp->ssr_type = WDSP_SSR_TYPE_WDSP_DOWN;
|
||||||
|
} else {
|
||||||
|
WDSP_DBG(wdsp, "SSR handling is running, skip debug ramdump");
|
||||||
|
ret = 0;
|
||||||
|
WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (arg) {
|
||||||
|
err_data = (struct wdsp_err_signal_arg *) arg;
|
||||||
|
memcpy(&wdsp->dump_data.err_data, err_data,
|
||||||
|
sizeof(*err_data));
|
||||||
|
} else {
|
||||||
|
WDSP_DBG(wdsp, "Invalid input, arg is NULL");
|
||||||
|
ret = -EINVAL;
|
||||||
|
WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
wdsp_collect_ramdumps(wdsp);
|
||||||
|
wdsp->ssr_type = WDSP_SSR_TYPE_NO_SSR;
|
||||||
|
WDSP_MGR_MUTEX_UNLOCK(wdsp, wdsp->ssr_mutex);
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int wdsp_debug_dump_handler(struct wdsp_mgr_priv *wdsp, void *arg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int wdsp_signal_handler(struct device *wdsp_dev,
|
static int wdsp_signal_handler(struct device *wdsp_dev,
|
||||||
enum wdsp_signal signal, void *arg)
|
enum wdsp_signal signal, void *arg)
|
||||||
{
|
{
|
||||||
@@ -866,6 +905,9 @@ static int wdsp_signal_handler(struct device *wdsp_dev,
|
|||||||
case WDSP_CDC_UP_SIGNAL:
|
case WDSP_CDC_UP_SIGNAL:
|
||||||
ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_CDC_UP);
|
ret = wdsp_ssr_handler(wdsp, arg, WDSP_SSR_TYPE_CDC_UP);
|
||||||
break;
|
break;
|
||||||
|
case WDSP_DEBUG_DUMP:
|
||||||
|
ret = wdsp_debug_dump_handler(wdsp, arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#define WCD_PROCFS_ENTRY_MAX_LEN 16
|
#define WCD_PROCFS_ENTRY_MAX_LEN 16
|
||||||
#define WCD_934X_RAMDUMP_START_ADDR 0x20100000
|
#define WCD_934X_RAMDUMP_START_ADDR 0x20100000
|
||||||
#define WCD_934X_RAMDUMP_SIZE ((1024 * 1024) - 128)
|
#define WCD_934X_RAMDUMP_SIZE ((1024 * 1024) - 128)
|
||||||
|
#define WCD_MISCDEV_CMD_MAX_LEN 11
|
||||||
|
|
||||||
#define WCD_CNTL_MUTEX_LOCK(codec, lock) \
|
#define WCD_CNTL_MUTEX_LOCK(codec, lock) \
|
||||||
{ \
|
{ \
|
||||||
@@ -76,6 +77,95 @@ static u8 mem_enable_values[] = {
|
|||||||
0xE0, 0xC0, 0x80, 0x00,
|
0xE0, 0xC0, 0x80, 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
#define WCD_CNTL_SET_ERR_IRQ_FLAG(cntl)\
|
||||||
|
atomic_cmpxchg(&cntl->err_irq_flag, 0, 1)
|
||||||
|
#define WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl)\
|
||||||
|
atomic_set(&cntl->err_irq_flag, 0)
|
||||||
|
|
||||||
|
static u16 wdsp_reg_for_debug_dump[] = {
|
||||||
|
WCD934X_CPE_SS_CPE_CTL,
|
||||||
|
WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0,
|
||||||
|
WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1,
|
||||||
|
WCD934X_CPE_SS_PWR_CPEFLL_CTL,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5,
|
||||||
|
WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN,
|
||||||
|
WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL,
|
||||||
|
WCD934X_CPE_SS_MAD_CTL,
|
||||||
|
WCD934X_CPE_SS_CPAR_CTL,
|
||||||
|
WCD934X_CPE_SS_WDOG_CFG,
|
||||||
|
WCD934X_CPE_SS_STATUS,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A,
|
||||||
|
WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void wcd_cntl_collect_debug_dumps(struct wcd_dsp_cntl *cntl)
|
||||||
|
{
|
||||||
|
struct snd_soc_codec *codec = cntl->codec;
|
||||||
|
struct wdsp_err_signal_arg arg;
|
||||||
|
int i;
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
/* If WDSP SSR happens, skip collecting debug dumps */
|
||||||
|
if (WCD_CNTL_SET_ERR_IRQ_FLAG(cntl) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Mask all error interrupts */
|
||||||
|
snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A,
|
||||||
|
0xFF);
|
||||||
|
snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B,
|
||||||
|
0xFF);
|
||||||
|
|
||||||
|
/* Collect important WDSP registers dump for debug use */
|
||||||
|
pr_err("%s: Dump the WDSP registers for debug use\n", __func__);
|
||||||
|
for (i = 0; i < sizeof(wdsp_reg_for_debug_dump)/sizeof(u16); i++) {
|
||||||
|
val = snd_soc_read(codec, wdsp_reg_for_debug_dump[i]);
|
||||||
|
pr_err("%s: reg = 0x%x, val = 0x%x\n", __func__,
|
||||||
|
wdsp_reg_for_debug_dump[i], val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trigger NMI in WDSP to sync and update the memory */
|
||||||
|
snd_soc_write(codec, WCD934X_CPE_SS_BACKUP_INT, 0x02);
|
||||||
|
|
||||||
|
/* Collect WDSP ramdump for debug use */
|
||||||
|
if (cntl->m_dev && cntl->m_ops && cntl->m_ops->signal_handler) {
|
||||||
|
arg.mem_dumps_enabled = cntl->ramdump_enable;
|
||||||
|
arg.remote_start_addr = WCD_934X_RAMDUMP_START_ADDR;
|
||||||
|
arg.dump_size = WCD_934X_RAMDUMP_SIZE;
|
||||||
|
cntl->m_ops->signal_handler(cntl->m_dev, WDSP_DEBUG_DUMP,
|
||||||
|
&arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unmask the fatal irqs */
|
||||||
|
snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A,
|
||||||
|
~(cntl->irqs.fatal_irqs & 0xFF));
|
||||||
|
snd_soc_write(codec, WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B,
|
||||||
|
~((cntl->irqs.fatal_irqs >> 8) & 0xFF));
|
||||||
|
|
||||||
|
WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define WCD_CNTL_SET_ERR_IRQ_FLAG(cntl) 0
|
||||||
|
#define WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl) do {} while (0)
|
||||||
|
static void wcd_cntl_collect_debug_dumps(struct wcd_dsp_cntl *cntl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static ssize_t wdsp_boot_show(struct wcd_dsp_cntl *cntl, char *buf)
|
static ssize_t wdsp_boot_show(struct wcd_dsp_cntl *cntl, char *buf)
|
||||||
{
|
{
|
||||||
return snprintf(buf, WCD_SYSFS_ENTRY_MAX_LEN,
|
return snprintf(buf, WCD_SYSFS_ENTRY_MAX_LEN,
|
||||||
@@ -663,6 +753,7 @@ static int wcd_cntl_do_boot(struct wcd_dsp_cntl *cntl)
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
dev_err(codec->dev, "%s: WDSP boot timed out\n",
|
dev_err(codec->dev, "%s: WDSP boot timed out\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
wcd_cntl_collect_debug_dumps(cntl);
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
goto err_boot;
|
goto err_boot;
|
||||||
} else {
|
} else {
|
||||||
@@ -719,7 +810,7 @@ static irqreturn_t wcd_cntl_err_irq(int irq, void *data)
|
|||||||
struct wdsp_err_signal_arg arg;
|
struct wdsp_err_signal_arg arg;
|
||||||
u16 status = 0;
|
u16 status = 0;
|
||||||
u8 reg_val;
|
u8 reg_val;
|
||||||
int ret = 0;
|
int rc, ret = 0;
|
||||||
|
|
||||||
reg_val = snd_soc_read(codec, WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A);
|
reg_val = snd_soc_read(codec, WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A);
|
||||||
status = status | reg_val;
|
status = status | reg_val;
|
||||||
@@ -732,6 +823,12 @@ static irqreturn_t wcd_cntl_err_irq(int irq, void *data)
|
|||||||
|
|
||||||
if ((status & cntl->irqs.fatal_irqs) &&
|
if ((status & cntl->irqs.fatal_irqs) &&
|
||||||
(cntl->m_dev && cntl->m_ops && cntl->m_ops->signal_handler)) {
|
(cntl->m_dev && cntl->m_ops && cntl->m_ops->signal_handler)) {
|
||||||
|
/*
|
||||||
|
* If WDSP SSR happens, skip collecting debug dumps.
|
||||||
|
* If debug dumps collecting happens first, WDSP_ERR_INTR
|
||||||
|
* will be blocked in signal_handler and get processed later.
|
||||||
|
*/
|
||||||
|
rc = WCD_CNTL_SET_ERR_IRQ_FLAG(cntl);
|
||||||
arg.mem_dumps_enabled = cntl->ramdump_enable;
|
arg.mem_dumps_enabled = cntl->ramdump_enable;
|
||||||
arg.remote_start_addr = WCD_934X_RAMDUMP_START_ADDR;
|
arg.remote_start_addr = WCD_934X_RAMDUMP_START_ADDR;
|
||||||
arg.dump_size = WCD_934X_RAMDUMP_SIZE;
|
arg.dump_size = WCD_934X_RAMDUMP_SIZE;
|
||||||
@@ -742,6 +839,8 @@ static irqreturn_t wcd_cntl_err_irq(int irq, void *data)
|
|||||||
"%s: Failed to handle fatal irq 0x%x\n",
|
"%s: Failed to handle fatal irq 0x%x\n",
|
||||||
__func__, status & cntl->irqs.fatal_irqs);
|
__func__, status & cntl->irqs.fatal_irqs);
|
||||||
wcd_cntl_change_online_state(cntl, 0);
|
wcd_cntl_change_online_state(cntl, 0);
|
||||||
|
if (rc == 0)
|
||||||
|
WCD_CNTL_CLR_ERR_IRQ_FLAG(cntl);
|
||||||
} else {
|
} else {
|
||||||
dev_err(cntl->codec->dev, "%s: Invalid signal_handler\n",
|
dev_err(cntl->codec->dev, "%s: Invalid signal_handler\n",
|
||||||
__func__);
|
__func__);
|
||||||
@@ -912,7 +1011,7 @@ static ssize_t wcd_miscdev_write(struct file *filep, const char __user *ubuf,
|
|||||||
bool vote;
|
bool vote;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (count == 0 || count > 2) {
|
if (count == 0 || count > WCD_MISCDEV_CMD_MAX_LEN) {
|
||||||
pr_err("%s: Invalid count = %zd\n", __func__, count);
|
pr_err("%s: Invalid count = %zd\n", __func__, count);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
@@ -939,6 +1038,11 @@ static ssize_t wcd_miscdev_write(struct file *filep, const char __user *ubuf,
|
|||||||
}
|
}
|
||||||
cntl->boot_reqs--;
|
cntl->boot_reqs--;
|
||||||
vote = false;
|
vote = false;
|
||||||
|
} else if (!strcmp(val, "DEBUG_DUMP")) {
|
||||||
|
dev_dbg(cntl->codec->dev,
|
||||||
|
"%s: Collect dumps for debug use\n", __func__);
|
||||||
|
wcd_cntl_collect_debug_dumps(cntl);
|
||||||
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
dev_err(cntl->codec->dev, "%s: Invalid value %s\n",
|
dev_err(cntl->codec->dev, "%s: Invalid value %s\n",
|
||||||
__func__, val);
|
__func__, val);
|
||||||
@@ -1309,6 +1413,7 @@ void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
|
|||||||
mutex_init(&control->clk_mutex);
|
mutex_init(&control->clk_mutex);
|
||||||
mutex_init(&control->ssr_mutex);
|
mutex_init(&control->ssr_mutex);
|
||||||
init_waitqueue_head(&control->ssr_entry.offline_poll_wait);
|
init_waitqueue_head(&control->ssr_entry.offline_poll_wait);
|
||||||
|
WCD_CNTL_CLR_ERR_IRQ_FLAG(control);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default state of WDSP is in SVS mode.
|
* The default state of WDSP is in SVS mode.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 and
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
@@ -109,6 +109,10 @@ struct wcd_dsp_cntl {
|
|||||||
/* Misc device related */
|
/* Misc device related */
|
||||||
char miscdev_name[256];
|
char miscdev_name[256];
|
||||||
struct miscdevice miscdev;
|
struct miscdevice miscdev;
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
/* Debug dump related */
|
||||||
|
atomic_t err_irq_flag;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
|
void wcd_dsp_cntl_init(struct snd_soc_codec *codec,
|
||||||
|
Reference in New Issue
Block a user