summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/q6asm-v2.h6
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c10
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c173
3 files changed, 141 insertions, 48 deletions
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 9df3e77da05b..3523fac586ce 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* 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
@@ -309,6 +309,10 @@ int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
int q6asm_open_write_v5(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample);
+
+int q6asm_open_write_with_retry(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample);
+
int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, int32_t stream_id,
bool is_gapless_mode);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 280c665dded4..9ab17d87b268 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -385,16 +385,10 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
return -ENOMEM;
}
} else {
- if (q6asm_get_svc_version(APR_SVC_ASM) >=
- ADSP_ASM_API_VERSION_V2)
- ret = q6asm_open_write_v5(prtd->audio_client,
+ ret = q6asm_open_write_with_retry(prtd->audio_client,
fmt_type, bits_per_sample);
- else
- ret = q6asm_open_write_v4(prtd->audio_client,
- fmt_type, bits_per_sample);
-
if (ret < 0) {
- pr_err("%s: q6asm_open_write_v4 failed (%d)\n",
+ pr_err("%s: q6asm_open_write_with_retry failed (%d)\n",
__func__, ret);
q6asm_audio_client_free(prtd->audio_client);
prtd->audio_client = NULL;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 567534e1599d..9d3fa1afeb6d 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -98,6 +98,7 @@ static struct asm_mmap this_mmap;
struct audio_session {
struct audio_client *ac;
spinlock_t session_lock;
+ bool ignore;
};
/* session id: 0 reserved */
static struct audio_session session[ASM_ACTIVE_STREAMS_ALLOWED + 1];
@@ -597,6 +598,7 @@ int q6asm_mmap_apr_dereg(void)
static int q6asm_session_alloc(struct audio_client *ac)
{
int n;
+
for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
if (!(session[n].ac)) {
session[n].ac = ac;
@@ -607,6 +609,87 @@ static int q6asm_session_alloc(struct audio_client *ac)
return -ENOMEM;
}
+static void q6asm_session_set_ignore(int id)
+{
+ session[id].ignore = true;
+}
+
+static void q6asm_session_clean_ignore(void)
+{
+ int i;
+
+ for (i = 1; i <= ASM_ACTIVE_STREAMS_ALLOWED; i++)
+ session[i].ignore = false;
+}
+
+static void q6asm_session_deregister(struct audio_client *ac)
+{
+ rtac_set_asm_handle(ac->session, NULL);
+ apr_deregister(ac->apr2);
+ apr_deregister(ac->apr);
+ q6asm_mmap_apr_dereg();
+ ac->apr2 = NULL;
+ ac->apr = NULL;
+ ac->mmap_apr = NULL;
+}
+
+static int q6asm_session_register(struct audio_client *ac)
+{
+ ac->apr = apr_register("ADSP", "ASM",
+ (apr_fn)q6asm_callback,
+ ((ac->session) << 8 | 0x0001),
+ ac);
+ if (ac->apr == NULL) {
+ pr_err("%s: Registration with APR failed\n", __func__);
+ goto fail_apr1;
+ }
+
+ ac->apr2 = apr_register("ADSP", "ASM",
+ (apr_fn)q6asm_callback,
+ ((ac->session) << 8 | 0x0002),
+ ac);
+ if (ac->apr2 == NULL) {
+ pr_err("%s: Registration with APR-2 failed\n", __func__);
+ goto fail_apr2;
+ }
+
+ rtac_set_asm_handle(ac->session, ac->apr);
+
+ pr_debug("%s: Registering the common port with APR\n", __func__);
+ ac->mmap_apr = q6asm_mmap_apr_reg();
+ if (ac->mmap_apr == NULL)
+ goto fail_mmap;
+
+ return 0;
+
+fail_mmap:
+ apr_deregister(ac->apr2);
+fail_apr2:
+ apr_deregister(ac->apr);
+fail_apr1:
+ return -EINVAL;
+}
+
+static int q6asm_session_try_next(struct audio_client *ac)
+{
+ int n;
+ int s = ac->session;
+
+ for (n = 1; n <= ASM_ACTIVE_STREAMS_ALLOWED; n++) {
+ if (++s > ASM_ACTIVE_STREAMS_ALLOWED)
+ s -= ASM_ACTIVE_STREAMS_ALLOWED;
+ if (!session[s].ignore && !session[s].ac) {
+ q6asm_session_deregister(ac);
+ session[ac->session].ac = NULL;
+ session[s].ac = ac;
+ ac->session = s;
+ return q6asm_session_register(ac);
+ }
+ }
+ pr_debug("%s: session not available\n", __func__);
+ return -EINVAL;
+}
+
static int q6asm_get_session_id_from_audio_client(struct audio_client *ac)
{
int n;
@@ -1139,13 +1222,7 @@ void q6asm_audio_client_free(struct audio_client *ac)
}
}
- rtac_set_asm_handle(ac->session, NULL);
- apr_deregister(ac->apr2);
- apr_deregister(ac->apr);
- q6asm_mmap_apr_dereg();
- ac->apr2 = NULL;
- ac->apr = NULL;
- ac->mmap_apr = NULL;
+ q6asm_session_deregister(ac);
q6asm_session_free(ac);
pr_debug("%s: APR De-Register\n", __func__);
@@ -1307,34 +1384,11 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
ac->fptr_cache_ops = NULL;
/* DSP expects stream id from 1 */
ac->stream_id = 1;
- ac->apr = apr_register("ADSP", "ASM", \
- (apr_fn)q6asm_callback,\
- ((ac->session) << 8 | 0x0001),\
- ac);
-
- if (ac->apr == NULL) {
- pr_err("%s: Registration with APR failed\n", __func__);
- mutex_unlock(&session_lock);
- goto fail_apr1;
- }
- ac->apr2 = apr_register("ADSP", "ASM",
- (apr_fn)q6asm_callback,
- ((ac->session) << 8 | 0x0002),
- ac);
- if (ac->apr2 == NULL) {
- pr_err("%s: Registration with APR-2 failed\n", __func__);
- mutex_unlock(&session_lock);
- goto fail_apr2;
- }
-
- rtac_set_asm_handle(n, ac->apr);
-
- pr_debug("%s: Registering the common port with APR\n", __func__);
- ac->mmap_apr = q6asm_mmap_apr_reg();
- if (ac->mmap_apr == NULL) {
+ rc = q6asm_session_register(ac);
+ if (rc < 0) {
mutex_unlock(&session_lock);
- goto fail_mmap;
+ goto fail_register;
}
init_waitqueue_head(&ac->cmd_wait);
@@ -1357,7 +1411,7 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
rc = send_asm_custom_topology(ac);
if (rc < 0) {
mutex_unlock(&session_lock);
- goto fail_mmap;
+ goto fail_send;
}
pr_debug("%s: session[%d]\n", __func__, ac->session);
@@ -1365,11 +1419,9 @@ struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
mutex_unlock(&session_lock);
return ac;
-fail_mmap:
- apr_deregister(ac->apr2);
-fail_apr2:
- apr_deregister(ac->apr);
-fail_apr1:
+fail_send:
+ q6asm_session_deregister(ac);
+fail_register:
q6asm_session_free(ac);
fail_session:
return NULL;
@@ -3241,6 +3293,49 @@ int q6asm_open_write_v5(struct audio_client *ac, uint32_t format,
}
EXPORT_SYMBOL(q6asm_open_write_v5);
+static int q6asm_open_write_version_adaptor(struct audio_client *ac,
+ uint32_t format, uint16_t bits_per_sample)
+{
+ if (q6asm_get_svc_version(APR_SVC_ASM) >= ADSP_ASM_API_VERSION_V2)
+ return q6asm_open_write_v5(ac, format, bits_per_sample);
+ else
+ return q6asm_open_write_v4(ac, format, bits_per_sample);
+}
+
+/*
+ * q6asm_open_write_with_retry - Opens audio playback session, with retrying
+ * in case of session ID conflict
+ *
+ * @ac: Client session handle
+ * @format: decoder format
+ * @bits_per_sample: bit width of playback session
+ */
+int q6asm_open_write_with_retry(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample)
+{
+ int i, rc;
+
+ mutex_lock(&session_lock);
+ for (i = 0; i < ASM_ACTIVE_STREAMS_ALLOWED; i++) {
+ rc = q6asm_open_write_version_adaptor(ac, format,
+ bits_per_sample);
+ if (rc != -EALREADY)
+ break;
+
+ pr_debug("%s: session %d is occupied, try next\n",
+ __func__, ac->session);
+ q6asm_session_set_ignore(ac->session);
+ rc = q6asm_session_try_next(ac);
+ if (rc < 0)
+ break;
+ }
+ q6asm_session_clean_ignore();
+ mutex_unlock(&session_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_open_write_with_retry);
+
int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample, int32_t stream_id,
bool is_gapless_mode)