summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-03-01 08:05:27 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2019-03-01 08:05:27 -0800
commitab42ea9b7e82baddeb19889ce7b8b45d983019dd (patch)
tree66e60235bd6a3ba1c4c309713bd3c712b94cbd1b
parente010e7ac73ecc418adb0efb361d2350763d074bc (diff)
parentb918ec8e0ae84f716d67693c3084c5608555dd9e (diff)
Merge "ASoC: msm: q6dspv2: vote for Glink Rx thread priority upgrade"
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr.c103
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr_tal_glink.c34
-rw-r--r--include/linux/qdsp6v2/apr.h4
-rw-r--r--include/linux/qdsp6v2/apr_tal.h10
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c22
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;