summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKuirong Wang <kuirongw@codeaurora.org>2016-09-23 15:11:15 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-09-30 10:56:00 -0700
commitcbd3e0cb0696906d3bdc3e1db45ac94f77fd6e26 (patch)
tree78510ea5d7d10b85bf3703fddecb0c769786be3a
parent46692be6dd06ce405cb09cf8338b1f0edbbfb295 (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.c18
-rw-r--r--include/sound/q6asm-v2.h2
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c21
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c34
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)
{