diff options
Diffstat (limited to 'sound/soc/codecs/wm_adsp.c')
| -rw-r--r-- | sound/soc/codecs/wm_adsp.c | 40 | 
1 files changed, 33 insertions, 7 deletions
| diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b93fdc8d2d6f..b0b48eb9c7c9 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2905,6 +2905,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,  		if (wm_adsp_fw[dsp->fw].num_caps != 0)  			wm_adsp_buffer_free(dsp); +		dsp->fatal_error = false; +  		mutex_unlock(&dsp->pwr_lock);  		adsp_dbg(dsp, "Execution stopped\n"); @@ -3000,6 +3002,9 @@ static int wm_adsp_compr_attach(struct wm_adsp_compr *compr)  {  	struct wm_adsp_compr_buf *buf = NULL, *tmp; +	if (compr->dsp->fatal_error) +		return -EINVAL; +  	list_for_each_entry(tmp, &compr->dsp->buffer_list, list) {  		if (!tmp->name || !strcmp(compr->name, tmp->name)) {  			buf = tmp; @@ -3535,11 +3540,11 @@ static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf)  	ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error);  	if (ret < 0) { -		adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); +		compr_err(buf, "Failed to check buffer error: %d\n", ret);  		return ret;  	}  	if (buf->error != 0) { -		adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); +		compr_err(buf, "Buffer error occurred: %d\n", buf->error);  		return -EIO;  	} @@ -3571,8 +3576,6 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)  		if (ret < 0)  			break; -		wm_adsp_buffer_clear(compr->buf); -  		/* Trigger the IRQ at one fragment of data */  		ret = wm_adsp_buffer_write(compr->buf,  					   HOST_BUFFER_FIELD(high_water_mark), @@ -3584,6 +3587,8 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd)  		}  		break;  	case SNDRV_PCM_TRIGGER_STOP: +		if (wm_adsp_compr_attached(compr)) +			wm_adsp_buffer_clear(compr->buf);  		break;  	default:  		ret = -EINVAL; @@ -3917,22 +3922,40 @@ int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions)  }  EXPORT_SYMBOL_GPL(wm_adsp2_lock); +static void wm_adsp_fatal_error(struct wm_adsp *dsp) +{ +	struct wm_adsp_compr *compr; + +	dsp->fatal_error = true; + +	list_for_each_entry(compr, &dsp->compr_list, list) { +		if (compr->stream) { +			snd_compr_stop_error(compr->stream, +					     SNDRV_PCM_STATE_XRUN); +			snd_compr_fragment_elapsed(compr->stream); +		} +	} +} +  irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)  {  	unsigned int val;  	struct regmap *regmap = dsp->regmap;  	int ret = 0; +	mutex_lock(&dsp->pwr_lock); +  	ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val);  	if (ret) {  		adsp_err(dsp,  			"Failed to read Region Lock Ctrl register: %d\n", ret); -		return IRQ_HANDLED; +		goto error;  	}  	if (val & ADSP2_WDT_TIMEOUT_STS_MASK) {  		adsp_err(dsp, "watchdog timeout error\n");  		wm_adsp_stop_watchdog(dsp); +		wm_adsp_fatal_error(dsp);  	}  	if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { @@ -3946,7 +3969,7 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)  			adsp_err(dsp,  				 "Failed to read Bus Err Addr register: %d\n",  				 ret); -			return IRQ_HANDLED; +			goto error;  		}  		adsp_err(dsp, "bus error address = 0x%x\n", @@ -3959,7 +3982,7 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)  			adsp_err(dsp,  				 "Failed to read Pmem Xmem Err Addr register: %d\n",  				 ret); -			return IRQ_HANDLED; +			goto error;  		}  		adsp_err(dsp, "xmem error address = 0x%x\n", @@ -3972,6 +3995,9 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp)  	regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL,  			   ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); +error: +	mutex_unlock(&dsp->pwr_lock); +  	return IRQ_HANDLED;  }  EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); |