diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2019-03-01 08:05:27 -0800 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2019-03-01 08:05:27 -0800 |
| commit | ab42ea9b7e82baddeb19889ce7b8b45d983019dd (patch) | |
| tree | 66e60235bd6a3ba1c4c309713bd3c712b94cbd1b | |
| parent | e010e7ac73ecc418adb0efb361d2350763d074bc (diff) | |
| parent | b918ec8e0ae84f716d67693c3084c5608555dd9e (diff) | |
Merge "ASoC: msm: q6dspv2: vote for Glink Rx thread priority upgrade"
| -rw-r--r-- | drivers/soc/qcom/qdsp6v2/apr.c | 103 | ||||
| -rw-r--r-- | drivers/soc/qcom/qdsp6v2/apr_tal_glink.c | 34 | ||||
| -rw-r--r-- | include/linux/qdsp6v2/apr.h | 4 | ||||
| -rw-r--r-- | include/linux/qdsp6v2/apr_tal.h | 10 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 22 |
5 files changed, 169 insertions, 4 deletions
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c index 8cd86915be98..9e55a25001ae 100644 --- a/drivers/soc/qcom/qdsp6v2/apr.c +++ b/drivers/soc/qcom/qdsp6v2/apr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2014, 2016, 2018 The Linux Foundation. +/* Copyright (c) 2010-2014, 2016, 2018-2019 The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -758,6 +758,107 @@ static void apr_reset_deregister(struct work_struct *work) kfree(apr_reset); } +/** + * apr_start_rx_rt - Clients call to vote for thread + * priority upgrade whenever needed. + * + * @handle: APR service handle + * + * Returns 0 on success or error otherwise. + */ +int apr_start_rx_rt(void *handle) +{ + int rc = 0; + struct apr_svc *svc = handle; + uint16_t dest_id = 0; + uint16_t client_id = 0; + + if (!svc) { + pr_err("%s: Invalid APR handle\n", __func__); + return -EINVAL; + } + + mutex_lock(&svc->m_lock); + dest_id = svc->dest_id; + client_id = svc->client_id; + + if ((client_id >= APR_CLIENT_MAX) || (dest_id >= APR_DEST_MAX)) { + pr_err("%s: %s invalid. client_id = %u, dest_id = %u\n", + __func__, + client_id >= APR_CLIENT_MAX ? "Client ID" : "Dest ID", + client_id, dest_id); + rc = -EINVAL; + goto exit; + } + + if (!client[dest_id][client_id].handle) { + pr_err("%s: Client handle is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + rc = apr_tal_start_rx_rt(client[dest_id][client_id].handle); + if (rc) + pr_err("%s: failed to set RT thread priority for APR RX. rc = %d\n", + __func__, rc); + +exit: + mutex_unlock(&svc->m_lock); + return rc; +} +EXPORT_SYMBOL(apr_start_rx_rt); + +/** + * apr_end_rx_rt - Clients call to unvote for thread + * priority upgrade (perviously voted with + * apr_start_rx_rt()). + * + * @handle: APR service handle + * + * Returns 0 on success or error otherwise. + */ +int apr_end_rx_rt(void *handle) +{ + int rc = 0; + struct apr_svc *svc = handle; + uint16_t dest_id = 0; + uint16_t client_id = 0; + + if (!svc) { + pr_err("%s: Invalid APR handle\n", __func__); + return -EINVAL; + } + + mutex_lock(&svc->m_lock); + dest_id = svc->dest_id; + client_id = svc->client_id; + + if ((client_id >= APR_CLIENT_MAX) || (dest_id >= APR_DEST_MAX)) { + pr_err("%s: %s invalid. client_id = %u, dest_id = %u\n", + __func__, + client_id >= APR_CLIENT_MAX ? "Client ID" : "Dest ID", + client_id, dest_id); + rc = -EINVAL; + goto exit; + } + + if (!client[dest_id][client_id].handle) { + pr_err("%s: Client handle is NULL\n", __func__); + rc = -EINVAL; + goto exit; + } + + rc = apr_tal_end_rx_rt(client[dest_id][client_id].handle); + if (rc) + pr_err("%s: failed to reset RT thread priority for APR RX. rc = %d\n", + __func__, rc); + +exit: + mutex_unlock(&svc->m_lock); + return rc; +} +EXPORT_SYMBOL(apr_end_rx_rt); + int apr_deregister(void *handle) { struct apr_svc *svc = handle; diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c index 8a2be787b70e..f11787deac47 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c +++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017 The Linux Foundation. +/* Copyright (c) 2016-2017, 2019 The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -358,6 +358,38 @@ unlock: return rc ? NULL : apr_ch; } +int apr_tal_start_rx_rt(struct apr_svc_ch_dev *apr_ch) +{ + int rc = 0; + + if (!apr_ch || !apr_ch->handle) { + rc = -EINVAL; + goto exit; + } + + mutex_lock(&apr_ch->m_lock); + rc = glink_start_rx_rt(apr_ch->handle); + mutex_unlock(&apr_ch->m_lock); +exit: + return rc; +} + +int apr_tal_end_rx_rt(struct apr_svc_ch_dev *apr_ch) +{ + int rc = 0; + + if (!apr_ch || !apr_ch->handle) { + rc = -EINVAL; + goto exit; + } + + mutex_lock(&apr_ch->m_lock); + rc = glink_end_rx_rt(apr_ch->handle); + mutex_unlock(&apr_ch->m_lock); +exit: + return rc; +} + int apr_tal_close(struct apr_svc_ch_dev *apr_ch) { int rc; diff --git a/include/linux/qdsp6v2/apr.h b/include/linux/qdsp6v2/apr.h index 98432952f278..31c552b8da07 100644 --- a/include/linux/qdsp6v2/apr.h +++ b/include/linux/qdsp6v2/apr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, 2019, 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 @@ -196,4 +196,6 @@ int apr_set_q6_state(enum apr_subsys_state state); void apr_set_subsys_state(void); const char *apr_get_lpass_subsys_name(void); uint16_t apr_get_reset_domain(uint16_t proc); +int apr_start_rx_rt(void *handle); +int apr_end_rx_rt(void *handle); #endif diff --git a/include/linux/qdsp6v2/apr_tal.h b/include/linux/qdsp6v2/apr_tal.h index 9b35c9f9882d..6100fe0b229c 100644 --- a/include/linux/qdsp6v2/apr_tal.h +++ b/include/linux/qdsp6v2/apr_tal.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2010-2011, 2016-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2011, 2016-2017, 2019 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 @@ -78,6 +79,9 @@ int apr_tal_rx_intents_config(struct apr_svc_ch_dev *apr_ch, #if defined(CONFIG_MSM_QDSP6_APRV2_GLINK) || \ defined(CONFIG_MSM_QDSP6_APRV3_GLINK) +int apr_tal_start_rx_rt(struct apr_svc_ch_dev *apr_ch); +int apr_tal_end_rx_rt(struct apr_svc_ch_dev *apr_ch); + struct apr_svc_ch_dev { void *handle; spinlock_t w_lock; @@ -90,6 +94,10 @@ struct apr_svc_ch_dev { bool if_remote_intent_ready; }; #else +static inline int apr_tal_start_rx_rt(struct apr_svc_ch_dev *apr_ch) +{ return 0; } +static inline int apr_tal_end_rx_rt(struct apr_svc_ch_dev *apr_ch) { return 0; } + struct apr_svc_ch_dev { struct smd_channel *ch; spinlock_t lock; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index 98a5c73785e0..1bb25eebe638 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -686,8 +686,15 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; struct msm_audio *prtd; + struct msm_plat_data *pdata; int ret = 0; + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: platform data not populated\n", __func__); + return -EINVAL; + } prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL); if (prtd == NULL) { pr_err("Failed to allocate memory for msm_audio\n"); @@ -767,6 +774,10 @@ static int msm_pcm_open(struct snd_pcm_substream *substream) prtd->reset_event = false; runtime->private_data = prtd; msm_adsp_init_mixer_ctl_pp_event_queue(soc_prtd); + /* Vote to update the Rx thread priority to RT Thread for playback */ + if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && + (pdata->perf_mode == LOW_LATENCY_PCM_MODE)) + apr_start_rx_rt(prtd->audio_client->apr); return 0; } @@ -874,6 +885,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; struct msm_audio *prtd = runtime->private_data; + struct msm_plat_data *pdata; uint32_t timeout; int dir = 0; int ret = 0; @@ -883,6 +895,16 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) if (prtd->audio_client) { dir = IN; + /* + * Unvote to downgrade the Rx thread priority from + * RT Thread for Low-Latency use case. + */ + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (pdata) { + if (pdata->perf_mode == LOW_LATENCY_PCM_MODE) + apr_end_rx_rt(prtd->audio_client->apr); + } /* determine timeout length */ if (runtime->frame_bits == 0 || runtime->rate == 0) { timeout = CMD_EOS_MIN_TIMEOUT_LENGTH; |
