diff options
| author | Kuirong Wang <kuirongw@codeaurora.org> | 2016-09-23 15:11:15 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-09-30 10:56:00 -0700 |
| commit | cbd3e0cb0696906d3bdc3e1db45ac94f77fd6e26 (patch) | |
| tree | 78510ea5d7d10b85bf3703fddecb0c769786be3a | |
| parent | 46692be6dd06ce405cb09cf8338b1f0edbbfb295 (diff) | |
ASoC: msm: Update the error handling when APR sends packet failed
Update the error handling when APR sends packet failed so that audio
driver can perform proper error recovery.
CRs-Fixed: 1050605
Change-Id: I6210e244e6299ec747836f40d03e92c15c6e53ee
Signed-off-by: Kuirong Wang <kuirongw@codeaurora.org>
| -rw-r--r-- | drivers/soc/qcom/qdsp6v2/apr.c | 18 | ||||
| -rw-r--r-- | include/sound/q6asm-v2.h | 2 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 21 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/q6asm.c | 34 |
4 files changed, 70 insertions, 5 deletions
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index 5517f20f310c..ee9b054dcc24 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -304,6 +304,7 @@ int apr_send_pkt(void *handle, uint32_t *buf) uint16_t dest_id; uint16_t client_id; uint16_t w_len; + int rc; unsigned long flags; if (!handle || !buf) { @@ -345,14 +346,23 @@ int apr_send_pkt(void *handle, uint32_t *buf) APR_PKT_INFO("Tx: dest_svc[%d], opcode[0x%X], size[%d]", hdr->dest_svc, hdr->opcode, hdr->pkt_size); - w_len = apr_tal_write(clnt->handle, buf, + rc = apr_tal_write(clnt->handle, buf, (struct apr_pkt_priv *)&svc->pkt_owner, hdr->pkt_size); - if (w_len != hdr->pkt_size) - pr_err("Unable to write APR pkt successfully: %d\n", w_len); + if (rc >= 0) { + w_len = rc; + if (w_len != hdr->pkt_size) { + pr_err("%s: Unable to write whole APR pkt successfully: %d\n", + __func__, rc); + rc = -EINVAL; + } + } else { + pr_err("%s: Write APR pkt failed with error %d\n", + __func__, rc); + } spin_unlock_irqrestore(&svc->w_lock, flags); - return w_len; + return rc; } int apr_pkt_config(void *handle, struct apr_pkt_cfg *cfg) diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 8525f2e7f738..00129eb08888 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -339,6 +339,8 @@ int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd, void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size, uint32_t *idx); +int q6asm_cpu_buf_release(int dir, struct audio_client *ac); + void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac, uint32_t *size, uint32_t *idx); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 4e3745d4d976..4e93780c4da0 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -57,6 +57,7 @@ struct snd_msm { #define CMD_EOS_MIN_TIMEOUT_LENGTH 50 #define CMD_EOS_TIMEOUT_MULTIPLIER (HZ * 50) +#define MAX_PB_COPY_RETRIES 3 static struct snd_pcm_hardware msm_pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | @@ -629,6 +630,7 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a, void *data = NULL; uint32_t idx = 0; uint32_t size = 0; + uint32_t retries = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct msm_audio *prtd = runtime->private_data; @@ -637,7 +639,7 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a, pr_debug("%s: prtd->out_count = %d\n", __func__, atomic_read(&prtd->out_count)); - while (fbytes > 0) { + while ((fbytes > 0) && (retries < MAX_PB_COPY_RETRIES)) { if (prtd->reset_event) { pr_err("%s: In SSR return ENETRESET before wait\n", __func__); @@ -666,6 +668,13 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a, data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx); + if (data == NULL) { + retries++; + continue; + } else { + retries = 0; + } + if (fbytes > size) xfer = size; else @@ -677,6 +686,9 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a, __func__, fbytes, xfer, size); if (copy_from_user(bufptr, buf, xfer)) { ret = -EFAULT; + pr_err("%s: copy_from_user failed\n", + __func__); + q6asm_cpu_buf_release(IN, prtd->audio_client); goto fail; } buf += xfer; @@ -690,6 +702,8 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a, 0, 0, NO_TIMESTAMP); if (ret < 0) { ret = -EFAULT; + q6asm_cpu_buf_release(IN, + prtd->audio_client); goto fail; } } else @@ -698,6 +712,9 @@ static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a, } } fail: + if (retries >= MAX_PB_COPY_RETRIES) + ret = -ENOMEM; + return ret; } @@ -802,6 +819,7 @@ static int msm_pcm_capture_copy(struct snd_pcm_substream *substream, if (copy_to_user(buf, bufptr+offset, xfer)) { pr_err("Failed to copy buf to user\n"); ret = -EFAULT; + q6asm_cpu_buf_release(OUT, prtd->audio_client); goto fail; } fbytes -= xfer; @@ -817,6 +835,7 @@ static int msm_pcm_capture_copy(struct snd_pcm_substream *substream, if (ret < 0) { pr_err("q6asm read failed\n"); ret = -EFAULT; + q6asm_cpu_buf_release(OUT, prtd->audio_client); goto fail; } } else diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 206fbec249fa..b4257f990aa5 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -1996,6 +1996,40 @@ void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size, return NULL; } +int q6asm_cpu_buf_release(int dir, struct audio_client *ac) +{ + struct audio_port_data *port; + int ret = 0; + int idx; + + if (!ac || ((dir != IN) && (dir != OUT))) { + pr_err("%s: ac %pK dir %d\n", __func__, ac, dir); + ret = -EINVAL; + goto exit; + } + + if (ac->io_mode & SYNC_IO_MODE) { + port = &ac->port[dir]; + mutex_lock(&port->lock); + idx = port->cpu_buf; + if (port->cpu_buf == 0) { + port->cpu_buf = port->max_buf_cnt - 1; + } else if (port->cpu_buf < port->max_buf_cnt) { + port->cpu_buf = port->cpu_buf - 1; + } else { + pr_err("%s: buffer index(%d) out of range\n", + __func__, port->cpu_buf); + ret = -EINVAL; + mutex_unlock(&port->lock); + goto exit; + } + port->buf[port->cpu_buf].used = dir ^ 1; + mutex_unlock(&port->lock); + } +exit: + return ret; +} + void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac, uint32_t *size, uint32_t *index) { |
