diff --git a/asoc/kalama.c b/asoc/kalama.c index fce5bf85ac..b89a258fff 100644 --- a/asoc/kalama.c +++ b/asoc/kalama.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022. Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -51,9 +51,6 @@ #define DEV_NAME_STR_LEN 32 #define WCD_MBHC_HS_V_MAX 1600 -#define MSM_LL_QOS_VALUE 300 /* time in us to ensure LPM doesn't go in C3/C4 */ - - #define WCN_CDC_SLIM_RX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX_LITO 3 @@ -123,53 +120,6 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .moisture_duty_cycle_en = true, }; -/* set audio task affinity to core 1 & 2 */ -static const unsigned int audio_core_list[] = {1, 2}; -static cpumask_t audio_cpu_map = CPU_MASK_NONE; -static struct dev_pm_qos_request *msm_audio_req = NULL; - -static void msm_audio_add_qos_request() -{ - int i; - int cpu = 0; - - msm_audio_req = kzalloc(sizeof(struct dev_pm_qos_request) * NR_CPUS, - GFP_KERNEL); - if (!msm_audio_req) { - pr_err("%s failed to alloc mem for qos req.\n", __func__); - return; - } - - for (i = 0; i < ARRAY_SIZE(audio_core_list); i++) { - if (audio_core_list[i] >= NR_CPUS) - pr_err("%s incorrect cpu id: %d specified.\n", __func__, audio_core_list[i]); - else - cpumask_set_cpu(audio_core_list[i], &audio_cpu_map); - } - - for_each_cpu(cpu, &audio_cpu_map) { - dev_pm_qos_add_request(get_cpu_device(cpu), - &msm_audio_req[cpu], - DEV_PM_QOS_RESUME_LATENCY, - PM_QOS_CPU_LATENCY_DEFAULT_VALUE); - pr_debug("%s set cpu affinity to core %d.\n", __func__, cpu); - } -} - -static void msm_audio_remove_qos_request() -{ - int cpu = 0; - - if (msm_audio_req) { - for_each_cpu(cpu, &audio_cpu_map) { - dev_pm_qos_remove_request( - &msm_audio_req[cpu]); - pr_debug("%s remove cpu affinity of core %d.\n", __func__, cpu); - } - kfree(msm_audio_req); - } -} - static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component, bool active) { struct snd_soc_card *card = component->card; @@ -1919,9 +1869,6 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) is_initial_boot = true; - /* Add QoS request for audio tasks */ - msm_audio_add_qos_request(); - /* change card status to ONLINE */ dev_dbg(&pdev->dev, "%s: setting snd_card to ONLINE\n", __func__); snd_card_set_card_status(SND_CARD_STATUS_ONLINE); @@ -1947,7 +1894,6 @@ static int msm_asoc_machine_remove(struct platform_device *pdev) msm_common_snd_deinit(common_pdata); snd_event_master_deregister(&pdev->dev); snd_soc_unregister_card(card); - msm_audio_remove_qos_request(); return 0; } diff --git a/asoc/msm_common.c b/asoc/msm_common.c index 0b609d40f2..44cbfd2b14 100644 --- a/asoc/msm_common.c +++ b/asoc/msm_common.c @@ -1,13 +1,7 @@ -/* Copyright (c) 2020-2021, 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 - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -79,6 +73,16 @@ struct chmap_pdata { #define MAX_USR_INPUT 10 +static int qos_vote_status; +static struct dev_pm_qos_request latency_pm_qos_req; /* pm_qos request */ +static unsigned int qos_client_active_cnt; +/* set audio task affinity to core 1 & 2 */ +static const unsigned int audio_core_list[] = {1, 2}; +static cpumask_t audio_cpu_map = CPU_MASK_NONE; +static struct dev_pm_qos_request *msm_audio_req = NULL; +static bool kregister_pm_qos_latency_controls = false; +#define MSM_LL_QOS_VALUE 300 /* time in us to ensure LPM doesn't go in C3/C4 */ + static ssize_t aud_dev_sysfs_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) @@ -594,6 +598,55 @@ void msm_common_snd_shutdown(struct snd_pcm_substream *substream) } } +static void msm_audio_add_qos_request() +{ + int i; + int cpu = 0; + int ret = 0; + + msm_audio_req = kcalloc(num_possible_cpus(), + sizeof(struct dev_pm_qos_request), GFP_KERNEL); + if (!msm_audio_req) + return; + + for (i = 0; i < ARRAY_SIZE(audio_core_list); i++) { + if (audio_core_list[i] >= num_possible_cpus()) + pr_err("%s incorrect cpu id: %d specified.\n", + __func__, audio_core_list[i]); + else + cpumask_set_cpu(audio_core_list[i], &audio_cpu_map); + } + + for_each_cpu(cpu, &audio_cpu_map) { + ret = dev_pm_qos_add_request(get_cpu_device(cpu), + &msm_audio_req[cpu], + DEV_PM_QOS_RESUME_LATENCY, + PM_QOS_CPU_LATENCY_DEFAULT_VALUE); + if (ret < 0) + pr_err("%s error (%d) adding resume latency to cpu %d.\n", + __func__, ret, cpu); + pr_debug("%s set cpu affinity to core %d.\n", __func__, cpu); + } +} + +static void msm_audio_remove_qos_request() +{ + int cpu = 0; + int ret = 0; + + if (msm_audio_req) { + for_each_cpu(cpu, &audio_cpu_map) { + ret = dev_pm_qos_remove_request( + &msm_audio_req[cpu]); + if (ret < 0) + pr_err("%s error (%d) removing request from cpu %d.\n", + __func__, ret, cpu); + pr_debug("%s remove cpu affinity of core %d.\n", __func__, cpu); + } + kfree(msm_audio_req); + } +} + int msm_common_snd_init(struct platform_device *pdev, struct snd_soc_card *card) { struct msm_common_pdata *common_pdata = NULL; @@ -699,6 +752,10 @@ int msm_common_snd_init(struct platform_device *pdev, struct snd_soc_card *card) aud_dev_sysfs_init(common_pdata); msm_common_set_pdata(card, common_pdata); + + /* Add QoS request for audio tasks */ + msm_audio_add_qos_request(); + return 0; }; @@ -709,6 +766,8 @@ void msm_common_snd_deinit(struct msm_common_pdata *common_pdata) if (!common_pdata) return; + msm_audio_remove_qos_request(); + for (count = 0; count < MI2S_TDM_AUXPCM_MAX; count++) { mutex_destroy(&common_pdata->lock[count]); } @@ -854,6 +913,88 @@ void msm_common_get_backend_name(const char *stream_name, char **backend_name) strlcpy(*backend_name, arg, ARRAY_SZ); } +static void msm_audio_update_qos_request(u32 latency) +{ + int cpu = 0; + int ret = -1; + + if (msm_audio_req) { + for_each_cpu(cpu, &audio_cpu_map) { + ret = dev_pm_qos_update_request( + &msm_audio_req[cpu], latency); + if (1 == ret ) { + pr_debug("%s: updated latency of core %d to %u.\n", + __func__, cpu, latency); + } else if (0 == ret) { + pr_debug("%s: latency of core %d not changed. latency %u.\n", + __func__, cpu, latency); + } else { + pr_err("%s: failed to update latency of core %d, error %d \n", + __func__, cpu, ret); + } + } + } +} + +static int msm_qos_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + qos_vote_status = ucontrol->value.enumerated.item[0]; + if (qos_vote_status) { + if (dev_pm_qos_request_active(&latency_pm_qos_req)) + dev_pm_qos_remove_request(&latency_pm_qos_req); + + qos_client_active_cnt++; + if (qos_client_active_cnt == 1) + msm_audio_update_qos_request(MSM_LL_QOS_VALUE); + } else { + if (qos_client_active_cnt > 0) + qos_client_active_cnt--; + if (qos_client_active_cnt == 0) + msm_audio_update_qos_request(PM_QOS_CPU_LATENCY_DEFAULT_VALUE); + } + + return 0; +} + +static int msm_qos_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = qos_vote_status; + return 0; +} + +static const char *const qos_text[] = {"Disable", "Enable"}; + +static SOC_ENUM_SINGLE_EXT_DECL(qos_vote, qos_text); + +static const struct snd_kcontrol_new card_pm_qos_controls[] = { + SOC_ENUM_EXT("PM_QOS Vote", qos_vote, + msm_qos_ctl_get, msm_qos_ctl_put), +}; + +static int msm_register_pm_qos_latency_controls(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *lpass_cdc_component = NULL; + int ret = 0; + + lpass_cdc_component = snd_soc_rtdcom_lookup(rtd, "lpass-cdc"); + if (!lpass_cdc_component) { + pr_err("%s: could not find component for lpass-cdc\n", + __func__); + return -EINVAL; + } + + ret = snd_soc_add_component_controls(lpass_cdc_component, + card_pm_qos_controls, ARRAY_SIZE(card_pm_qos_controls)); + if (ret < 0) { + pr_err("%s: add common snd controls failed: %d\n", + __func__, ret); + return -EINVAL; + } + return 0; +} + int msm_common_dai_link_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); @@ -933,9 +1074,20 @@ int msm_common_dai_link_init(struct snd_soc_pcm_runtime *rtd) } } kctl->private_data = pdata; + } + if (!kregister_pm_qos_latency_controls) { + if (!msm_register_pm_qos_latency_controls(rtd)) + kregister_pm_qos_latency_controls = true; + } + free_mixer_str: + if (backend_name) { kfree(backend_name); + backend_name = NULL; + } + if (mixer_str) { kfree(mixer_str); + mixer_str = NULL; } return ret; diff --git a/asoc/waipio.c b/asoc/waipio.c index c450bf00ad..1ffd5648d4 100644 --- a/asoc/waipio.c +++ b/asoc/waipio.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -50,9 +51,6 @@ #define DEV_NAME_STR_LEN 32 #define WCD_MBHC_HS_V_MAX 1600 -#define MSM_LL_QOS_VALUE 300 /* time in us to ensure LPM doesn't go in C3/C4 */ - - #define WCN_CDC_SLIM_RX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX_LITO 3 @@ -120,53 +118,6 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .moisture_duty_cycle_en = true, }; -/* set audio task affinity to core 1 & 2 */ -static const unsigned int audio_core_list[] = {1, 2}; -static cpumask_t audio_cpu_map = CPU_MASK_NONE; -static struct dev_pm_qos_request *msm_audio_req = NULL; - -static void msm_audio_add_qos_request() -{ - int i; - int cpu = 0; - - msm_audio_req = kzalloc(sizeof(struct dev_pm_qos_request) * NR_CPUS, - GFP_KERNEL); - if (!msm_audio_req) { - pr_err("%s failed to alloc mem for qos req.\n", __func__); - return; - } - - for (i = 0; i < ARRAY_SIZE(audio_core_list); i++) { - if (audio_core_list[i] >= NR_CPUS) - pr_err("%s incorrect cpu id: %d specified.\n", __func__, audio_core_list[i]); - else - cpumask_set_cpu(audio_core_list[i], &audio_cpu_map); - } - - for_each_cpu(cpu, &audio_cpu_map) { - dev_pm_qos_add_request(get_cpu_device(cpu), - &msm_audio_req[cpu], - DEV_PM_QOS_RESUME_LATENCY, - PM_QOS_CPU_LATENCY_DEFAULT_VALUE); - pr_debug("%s set cpu affinity to core %d.\n", __func__, cpu); - } -} - -static void msm_audio_remove_qos_request() -{ - int cpu = 0; - - if (msm_audio_req) { - for_each_cpu(cpu, &audio_cpu_map) { - dev_pm_qos_remove_request( - &msm_audio_req[cpu]); - pr_debug("%s remove cpu affinity of core %d.\n", __func__, cpu); - } - kfree(msm_audio_req); - } -} - static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component, bool active) { struct snd_soc_card *card = component->card; @@ -1891,9 +1842,6 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) is_initial_boot = true; - /* Add QoS request for audio tasks */ - msm_audio_add_qos_request(); - /* change card status to ONLINE */ dev_dbg(&pdev->dev, "%s: setting snd_card to ONLINE\n", __func__); snd_card_set_card_status(SND_CARD_STATUS_ONLINE); @@ -1919,7 +1867,6 @@ static int msm_asoc_machine_remove(struct platform_device *pdev) msm_common_snd_deinit(common_pdata); snd_event_master_deregister(&pdev->dev); snd_soc_unregister_card(card); - msm_audio_remove_qos_request(); return 0; }