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

Commit da0a39d6 authored by Viraja Kommaraju's avatar Viraja Kommaraju Committed by Hongtao Peng
Browse files

q6asm: retry asm_open_read and asm_open_loopback during 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 & capture stream to try all
available session ids in case of session id conflict error, to support
concurrent playback from multiple virtual machines.

Change-Id: Ibdde0b21643f135066b017ab678d999841b23475
Signed-off-by: default avatarViraja Kommaraju <virajak@codeaurora.org>
parent 9f0c6704
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -345,11 +345,12 @@ static int msm_pcm_open(struct snd_pcm_substream *substream)
		}

		pcm->audio_client->fedai_id = rtd->dai_link->id;
		pcm->session_id = pcm->audio_client->session;
		pcm->audio_client->perf_mode = pdata->perf_mode;
		pcm->audio_client->stream_type = substream->stream;
		ret = q6asm_open_loopback_v2(pcm->audio_client,
		ret = q6asm_open_loopback_with_retry(pcm->audio_client,
					bits_per_sample);
		pcm->session_id = pcm->audio_client->session;

		if (ret < 0) {
			dev_err(component->dev,
				"%s: pcm out open failed\n", __func__);

asoc/msm-pcm-q6-v2.c

100644 → 100755
+4 −18
Original line number Diff line number Diff line
@@ -435,15 +435,8 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
			return -ENOMEM;
		}
	} else {
		if ((q6core_get_avcs_api_version_per_service(
				APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
				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 failed (%d)\n",
			__func__, ret);
@@ -576,16 +569,9 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
		prtd->audio_client->stream_type = SNDRV_PCM_STREAM_CAPTURE;
		prtd->audio_client->fedai_id = soc_prtd->dai_link->id;

		if ((q6core_get_avcs_api_version_per_service(
				APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
				ADSP_ASM_API_VERSION_V2))
			ret = q6asm_open_read_v5(prtd->audio_client,
				FORMAT_LINEAR_PCM,
				bits_per_sample, false, ENC_CFG_ID_NONE);
		else
			ret = q6asm_open_read_v4(prtd->audio_client,
		ret = q6asm_open_read_with_retry(prtd->audio_client,
					FORMAT_LINEAR_PCM,
				bits_per_sample, false, ENC_CFG_ID_NONE);
					bits_per_sample, false);
		if (ret < 0) {
			pr_err("%s: q6asm_open_read failed\n", __func__);
			q6asm_audio_client_free(prtd->audio_client);
+213 −39
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ struct audio_session {
	struct audio_client *ac;
	spinlock_t session_lock;
	struct mutex mutex_lock_per_session;
	bool ignore;
};
/* session id: 0 reserved */
static struct audio_session session[ASM_ACTIVE_STREAMS_ALLOWED + 1];
@@ -585,6 +586,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;
@@ -1225,13 +1307,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__);
@@ -1436,34 +1512,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);
@@ -1486,7 +1539,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);
@@ -1494,11 +1547,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;
@@ -3428,6 +3479,53 @@ int q6asm_open_read_v5(struct audio_client *ac, uint32_t format,
}
EXPORT_SYMBOL(q6asm_open_read_v5);

static int q6asm_open_read_version_adaptor(struct audio_client *ac,
			uint32_t format, uint16_t bits_per_sample, bool ts_mode)
{
	if (q6core_get_avcs_api_version_per_service(
			APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
			ADSP_ASM_API_VERSION_V2)
		return q6asm_open_read_v5(ac, FORMAT_LINEAR_PCM,
						bits_per_sample, false, ENC_CFG_ID_NONE);
	else
		return q6asm_open_read_v4(ac, FORMAT_LINEAR_PCM,
						bits_per_sample, false, ENC_CFG_ID_NONE);
}

/*
 * q6asm_open_read_with_retry - Opens audio capture session, with retrying
 * in case of session ID conflict
 *
 * @ac: Client session handle
 * @format: encoder format
 * @bits_per_sample: bit width of capture session
 * @ts_mode: timestamp mode
 */
int q6asm_open_read_with_retry(struct audio_client *ac, uint32_t format,
			uint16_t bits_per_sample, bool ts_mode)
{
	int i, rc;

	mutex_lock(&session_lock);
	for (i = 0; i < ASM_ACTIVE_STREAMS_ALLOWED; i++) {
		rc = q6asm_open_read_version_adaptor(ac, format,
				bits_per_sample, ts_mode);
		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_read_with_retry);

/**
 * q6asm_open_write_compressed -
@@ -3759,6 +3857,51 @@ int q6asm_open_write_v4(struct audio_client *ac, uint32_t format,
}
EXPORT_SYMBOL(q6asm_open_write_v4);

static int q6asm_open_write_version_adaptor(struct audio_client *ac,
			uint32_t format, uint16_t bits_per_sample)
{
	if (q6core_get_avcs_api_version_per_service(
			APRV2_IDS_SERVICE_ID_ADSP_ASM_V) >=
			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)
@@ -4171,6 +4314,37 @@ int q6asm_open_loopback_v2(struct audio_client *ac, uint16_t bits_per_sample)
}
EXPORT_SYMBOL(q6asm_open_loopback_v2);

/*
 * q6asm_open_loopback_with_retry - Opens audio loopback session, with retrying
 * in case of session ID conflict
 *
 * @ac: Client session handle
 * @bits_per_sample: bit width of sample
 */
int q6asm_open_loopback_with_retry(struct audio_client *ac,
				uint16_t bits_per_sample)
{
	int i, rc;

	mutex_lock(&session_lock);
	for (i = 0; i < ASM_ACTIVE_STREAMS_ALLOWED; i++) {
		rc = q6asm_open_loopback_v2(ac, 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_loopback_with_retry);

/**
 * q6asm_open_transcode_loopback -
 *       command to open ASM in transcode loopback mode
+9 −0
Original line number Diff line number Diff line
@@ -304,6 +304,9 @@ int q6asm_open_read_v5(struct audio_client *ac, uint32_t format,
			uint16_t bits_per_sample, bool ts_mode,
			uint32_t enc_cfg_id);

int q6asm_open_read_with_retry(struct audio_client *ac, uint32_t format,
			uint16_t bits_per_sample, bool ts_mode);

int q6asm_open_write(struct audio_client *ac, uint32_t format
		/*, uint16_t bits_per_sample*/);

@@ -323,6 +326,9 @@ 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);
@@ -357,6 +363,9 @@ int q6asm_open_read_write_v2(struct audio_client *ac, uint32_t rd_format,
int q6asm_open_loopback_v2(struct audio_client *ac,
			   uint16_t bits_per_sample);

int q6asm_open_loopback_with_retry(struct audio_client *ac,
			   uint16_t bits_per_sample);

int q6asm_open_transcode_loopback(struct audio_client *ac,
			   uint16_t bits_per_sample, uint32_t source_format,
			   uint32_t sink_format);