ASoC: wcd_cpe_core: Improve exception error handling

CPE (Codec Processing Engine) block in the hardware has multiple
exception interrupts. When CPE crashes, it is possible it will generate
multiple and spurious exception interrupts. This is causing some
interrupts to be missed. Fix this by making sure interrupts that are
serviced are masked to avoid spurious interrupts and pending interrupts
are serviced to avoid missing interrupts.

CRs-fixed: 874196
Change-Id: I63f3ef2eac3f194d5e535c607893236d3ae6a4ab
Signed-off-by: Bhalchandra Gajare <gajare@codeaurora.org>
This commit is contained in:
Bhalchandra Gajare 2015-09-01 17:44:36 -07:00 committed by Gerrit - the friendly Code Review server
parent 8a995b66eb
commit f08ff54ccb

View file

@ -1069,23 +1069,46 @@ static irqreturn_t svass_exception_irq(int irq, void *data)
struct wcd_cpe_core *core = data; struct wcd_cpe_core *core = data;
u8 status = 0; u8 status = 0;
if (CPE_ERR_IRQ_CB(core)) if (!core || !CPE_ERR_IRQ_CB(core)) {
core->cpe_cdc_cb->cpe_err_irq_control( pr_err("%s: Invalid %s\n",
core->codec, __func__,
CPE_ERR_IRQ_STATUS, (!core) ? "core" : "cdc control");
&status); return IRQ_HANDLED;
dev_err(core->dev, }
"%s: err_interrupt status = 0x%x\n",
__func__, status);
if (status & core->irq_info.cpe_fatal_irqs) { core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
wcd_cpe_ssr_event(core, WCD_CPE_SSR_EVENT); CPE_ERR_IRQ_STATUS, &status);
} else {
/* Make sure all error interrupts are cleared */ while (status != 0) {
if (CPE_ERR_IRQ_CB(core)) if (status & core->irq_info.cpe_fatal_irqs) {
core->cpe_cdc_cb->cpe_err_irq_control( dev_err(core->dev,
core->codec, "%s: CPE SSR event,err_status = 0x%02x\n",
CPE_ERR_IRQ_CLEAR, NULL); __func__, status);
wcd_cpe_ssr_event(core, WCD_CPE_SSR_EVENT);
/*
* If fatal interrupt is received,
* trigger SSR and stop processing
* further interrupts
*/
break;
}
/*
* Mask the interrupt that was raised to
* avoid spurious interrupts
*/
core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
CPE_ERR_IRQ_MASK, &status);
/* Clear only the interrupt that was raised */
core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
CPE_ERR_IRQ_CLEAR, &status);
dev_err(core->dev,
"%s: err_interrupt status = 0x%x\n",
__func__, status);
/* Read status for pending interrupts */
core->cpe_cdc_cb->cpe_err_irq_control(core->codec,
CPE_ERR_IRQ_STATUS, &status);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -2902,6 +2925,7 @@ static int wcd_cpe_lab_ch_setup(void *core_handle,
struct wcd_cpe_core *core = core_handle; struct wcd_cpe_core *core = core_handle;
struct snd_soc_codec *codec; struct snd_soc_codec *codec;
int rc = 0; int rc = 0;
u8 cpe_intr_bits;
if (!core || !core->codec) { if (!core || !core->codec) {
pr_err("%s: Invalid handle to %s\n", pr_err("%s: Invalid handle to %s\n",
@ -2956,6 +2980,17 @@ static int wcd_cpe_lab_ch_setup(void *core_handle,
break; break;
case WCD_CPE_PRE_DISABLE: case WCD_CPE_PRE_DISABLE:
/*
* Mask the non-fatal interrupts in CPE as they will
* be generated during lab teardown and may flood.
*/
cpe_intr_bits = ~(core->irq_info.cpe_fatal_irqs & 0xFF);
if (CPE_ERR_IRQ_CB(core))
core->cpe_cdc_cb->cpe_err_irq_control(
core->codec,
CPE_ERR_IRQ_MASK,
&cpe_intr_bits);
rc = core->cpe_cdc_cb->lab_cdc_ch_ctl(codec, rc = core->cpe_cdc_cb->lab_cdc_ch_ctl(codec,
false); false);
if (rc) if (rc)
@ -2979,13 +3014,18 @@ static int wcd_cpe_lab_ch_setup(void *core_handle,
/* Continue with disabling even if toggle lab fails */ /* Continue with disabling even if toggle lab fails */
rc = core->cpe_cdc_cb->cdc_ext_clk(codec, false, false); rc = core->cpe_cdc_cb->cdc_ext_clk(codec, false, false);
if (rc) { if (rc)
dev_err(core->dev, dev_err(core->dev,
"%s: failed to disable cdc clk, err = %d\n", "%s: failed to disable cdc clk, err = %d\n",
__func__, rc); __func__, rc);
goto done;
}
/* Unmask non-fatal CPE interrupts */
cpe_intr_bits = ~(core->irq_info.cpe_fatal_irqs & 0xFF);
if (CPE_ERR_IRQ_CB(core))
core->cpe_cdc_cb->cpe_err_irq_control(
core->codec,
CPE_ERR_IRQ_UNMASK,
&cpe_intr_bits);
break; break;
default: default: