diff options
| -rw-r--r-- | include/sound/q6asm-v2.h | 6 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 10 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/q6asm.c | 173 |
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) |
