Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53c8faf4 authored by Han Lu's avatar Han Lu Committed by Gerrit - the friendly Code Review server
Browse files

q6asm: retry asm open in case of session id conflict



The ADSP asm session ids are managed by the kernel driver. It's all right
for native use cases. But for virtualization use cases, there's no way to
synchronize the session ids' status among virtual machines.  Playing back
in one virtual machine is probably failed, because the session id may had
been occupied by a use case in another virtual machine.

The patch allowed audio playback stream to try all available session ids
in case of session id conflict error, to support concurrent playback from
multiple virtual machines.

Change-Id: If98d05898cec3f05d80c750ec8a014add3b1f34c
Signed-off-by: default avatarHan Lu <hanlu@codeaurora.org>
parent fd95dadf
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
/* 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);
+2 −8
Original line number Diff line number Diff line
@@ -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;
+134 −39
Original line number Diff line number Diff line
@@ -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)