ASoC: tegra: Add shutdown callback

- Added mutex protection for init_done flag reads in
  mixer control callbacks relevant to "ADSP init". Otherwise
  during shutdown sequence that includes alsa store service,
  this leads to inconsistent behaviour
- Shutdown callback is added to deinit ADSP OS during
  abrupt shutdown.
- In case ADSP OS is crashed during boot/boot has not
  started yet, shutdown does not issue OS deinit as
  init is not complete yet

Bug 3391964

Change-Id: I207e2141af9386f5914e07a8dd231d0fcd803a6e
Signed-off-by: Asha Talambedu <atalambedu@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-5.10/+/2607727
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Sameer Pujar <spujar@nvidia.com>
Reviewed-by: Mohan Kumar D <mkumard@nvidia.com>
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: Sharad Gupta <sharadg@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Asha Talambedu
2021-10-08 16:08:31 +05:30
committed by Sameer Pujar
parent 9d520f3d07
commit 39cc4081e3

View File

@@ -3,7 +3,7 @@
* tegra210_adsp.c - Tegra ADSP audio driver * tegra210_adsp.c - Tegra ADSP audio driver
* *
* Author: Sumit Bhattacharya <sumitb@nvidia.com> * Author: Sumit Bhattacharya <sumitb@nvidia.com>
* Copyright (c) 2014-2020 NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2021 NVIDIA CORPORATION. All rights reserved.
* *
*/ */
@@ -52,6 +52,7 @@
#define NETLINK_ADSP_EVENT 31 #define NETLINK_ADSP_EVENT 31
#define NETLINK_ADSP_EVENT_GROUP 1 #define NETLINK_ADSP_EVENT_GROUP 1
#define ADSP_SHUTDOWN_TIMEOUT 500
struct adsp_event_nlmsg { struct adsp_event_nlmsg {
uint32_t err; uint32_t err;
@@ -164,6 +165,7 @@ struct tegra210_adsp {
uint32_t i2s_rate; uint32_t i2s_rate;
struct mutex mutex; struct mutex mutex;
int init_done; int init_done;
struct completion init_complete;
int adsp_started; int adsp_started;
uint32_t adma_ch_page; uint32_t adma_ch_page;
uint32_t adma_ch_start; uint32_t adma_ch_start;
@@ -382,6 +384,10 @@ static int tegra210_adsp_init(struct tegra210_adsp *adsp)
int i, ret = 0; int i, ret = 0;
mutex_lock(&adsp->mutex); mutex_lock(&adsp->mutex);
if (adsp->init_done)
goto exit;
ret = nvadsp_os_load(); ret = nvadsp_os_load();
if (ret < 0) { if (ret < 0) {
dev_err(adsp->dev, "Failed to load OS."); dev_err(adsp->dev, "Failed to load OS.");
@@ -417,6 +423,7 @@ static int tegra210_adsp_init(struct tegra210_adsp *adsp)
} }
adsp->init_done = 1; adsp->init_done = 1;
complete(&adsp->init_complete);
exit: exit:
mutex_unlock(&adsp->mutex); mutex_unlock(&adsp->mutex);
@@ -430,6 +437,7 @@ static void tegra210_adsp_deinit(struct tegra210_adsp *adsp)
nvadsp_os_stop(); nvadsp_os_stop();
adsp->init_done = 0; adsp->init_done = 0;
} }
reinit_completion(&adsp->init_complete);
mutex_unlock(&adsp->mutex); mutex_unlock(&adsp->mutex);
} }
@@ -1390,25 +1398,31 @@ static int tegra210_adsp_compr_open(struct snd_soc_component *component,
struct tegra210_adsp *adsp = snd_soc_component_get_drvdata(component); struct tegra210_adsp *adsp = snd_soc_component_get_drvdata(component);
struct tegra210_adsp_compr_rtd *prtd; struct tegra210_adsp_compr_rtd *prtd;
uint32_t fe_reg = rtd->dais[rtd->num_cpus]->id + 1; uint32_t fe_reg = rtd->dais[rtd->num_cpus]->id + 1;
int ret; int ret = 0;
int i; int i;
dev_vdbg(adsp->dev, "%s : DAI ID %d", __func__, rtd->dais[rtd->num_cpus]->id); dev_vdbg(adsp->dev, "%s : DAI ID %d", __func__, rtd->dais[rtd->num_cpus]->id);
if (!adsp->init_done) mutex_lock(&adsp->mutex);
return -ENODEV; if (!adsp->init_done) {
ret = -ENODEV;
goto exit;
}
if (!adsp->pcm_path[fe_reg][cstream->direction].fe_reg || if (!adsp->pcm_path[fe_reg][cstream->direction].fe_reg ||
!adsp->pcm_path[fe_reg][cstream->direction].be_reg) { !adsp->pcm_path[fe_reg][cstream->direction].be_reg) {
dev_err(adsp->dev, "Broken Path%d - FE not linked to BE", dev_err(adsp->dev, "Broken Path%d - FE not linked to BE",
fe_reg); fe_reg);
return -EPIPE; ret = -EPIPE;
goto exit;
} }
prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_compr_rtd), prtd = devm_kzalloc(adsp->dev, sizeof(struct tegra210_adsp_compr_rtd),
GFP_KERNEL); GFP_KERNEL);
if (!prtd) if (!prtd) {
return -ENOMEM; ret = -ENOMEM;
goto exit;
}
/* Find out the APM connected with ADSP-FE DAI */ /* Find out the APM connected with ADSP-FE DAI */
for (i = APM_IN_START; i <= APM_IN_END; i++) { for (i = APM_IN_START; i <= APM_IN_END; i++) {
@@ -1427,7 +1441,8 @@ static int tegra210_adsp_compr_open(struct snd_soc_component *component,
if (!prtd->fe_apm) { if (!prtd->fe_apm) {
dev_err(adsp->dev, "No FE APM found\n"); dev_err(adsp->dev, "No FE APM found\n");
devm_kfree(adsp->dev, prtd); devm_kfree(adsp->dev, prtd);
return -ENODEV; ret = -ENODEV;
goto exit;
} }
prtd->cstream = cstream; prtd->cstream = cstream;
@@ -1438,6 +1453,8 @@ static int tegra210_adsp_compr_open(struct snd_soc_component *component,
dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n", dev_err(adsp->dev, "%s pm_runtime_get_sync error 0x%x\n",
__func__, ret); __func__, ret);
} }
exit:
mutex_unlock(&adsp->mutex);
return ret; return ret;
} }
@@ -2569,7 +2586,10 @@ static int tegra210_adsp_init_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct tegra210_adsp *adsp = snd_soc_component_get_drvdata(cmpnt); struct tegra210_adsp *adsp = snd_soc_component_get_drvdata(cmpnt);
mutex_lock(&adsp->mutex);
ucontrol->value.enumerated.item[0] = adsp->init_done; ucontrol->value.enumerated.item[0] = adsp->init_done;
mutex_unlock(&adsp->mutex);
return 0; return 0;
} }
@@ -2581,9 +2601,6 @@ static int tegra210_adsp_init_put(struct snd_kcontrol *kcontrol,
int init = ucontrol->value.enumerated.item[0]; int init = ucontrol->value.enumerated.item[0];
int ret = 0; int ret = 0;
if (init == adsp->init_done)
return 0;
if (init) { if (init) {
ret = tegra210_adsp_init(adsp); ret = tegra210_adsp_init(adsp);
if (ret < 0) { if (ret < 0) {
@@ -4508,6 +4525,8 @@ static int tegra210_adsp_audio_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
mutex_init(&adsp->mutex);
init_completion(&adsp->init_complete);
dev_set_drvdata(&pdev->dev, adsp); dev_set_drvdata(&pdev->dev, adsp);
adsp->dev = &pdev->dev; adsp->dev = &pdev->dev;
adsp->soc_data = (struct adsp_soc_data *)match->data; adsp->soc_data = (struct adsp_soc_data *)match->data;
@@ -4540,7 +4559,6 @@ static int tegra210_adsp_audio_probe(struct platform_device *pdev)
/* TODO: Add mixer control to set I2S playback rate */ /* TODO: Add mixer control to set I2S playback rate */
adsp->i2s_rate = 48000; adsp->i2s_rate = 48000;
INIT_WORK(&adsp->override_freq_work, tegra_adsp_override_freq_worker); INIT_WORK(&adsp->override_freq_work, tegra_adsp_override_freq_worker);
mutex_init(&adsp->mutex);
pdev->dev.dma_mask = &tegra_dma_mask; pdev->dev.dma_mask = &tegra_dma_mask;
pdev->dev.coherent_dma_mask = tegra_dma_mask; pdev->dev.coherent_dma_mask = tegra_dma_mask;
@@ -4763,6 +4781,20 @@ static int tegra210_adsp_audio_remove(struct platform_device *pdev)
return 0; return 0;
} }
static void tegra210_adsp_audio_platform_shutdown(
struct platform_device *pdev)
{
struct tegra210_adsp *adsp = dev_get_drvdata(&pdev->dev);
if (!wait_for_completion_timeout(&adsp->init_complete,
msecs_to_jiffies(ADSP_SHUTDOWN_TIMEOUT))) {
dev_err(&pdev->dev, "Wait on init complete timed out");
return;
}
tegra210_adsp_deinit(adsp);
}
static const struct dev_pm_ops tegra210_adsp_pm_ops = { static const struct dev_pm_ops tegra210_adsp_pm_ops = {
SET_RUNTIME_PM_OPS(tegra210_adsp_runtime_suspend, SET_RUNTIME_PM_OPS(tegra210_adsp_runtime_suspend,
tegra210_adsp_runtime_resume, NULL) tegra210_adsp_runtime_resume, NULL)
@@ -4781,6 +4813,7 @@ static struct platform_driver tegra210_adsp_audio_driver = {
}, },
.probe = tegra210_adsp_audio_probe, .probe = tegra210_adsp_audio_probe,
.remove = tegra210_adsp_audio_remove, .remove = tegra210_adsp_audio_remove,
.shutdown = tegra210_adsp_audio_platform_shutdown,
}; };
module_platform_driver(tegra210_adsp_audio_driver); module_platform_driver(tegra210_adsp_audio_driver);