From c9f68ec529111993dd044164060bd2f6bc0eadea Mon Sep 17 00:00:00 2001 From: Viswanath L Date: Thu, 16 May 2024 19:12:25 +0000 Subject: [PATCH] nvadsp: Rely on WFI status if no interrupt Check WFI status by regsiter query in case WFI interrupt is not available. Bug 3916054 Change-Id: Ideb0ac396623ad46e5d5ecf38738b99fd3366091 Signed-off-by: Viswanath L Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3139589 Reviewed-by: Asha T Reviewed-by: svcacv Reviewed-by: Dara Ramesh GVS: buildbot_gerritrpt --- drivers/platform/tegra/nvadsp/dev.c | 3 ++ drivers/platform/tegra/nvadsp/dev.h | 1 + drivers/platform/tegra/nvadsp/os.c | 63 +++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/drivers/platform/tegra/nvadsp/dev.c b/drivers/platform/tegra/nvadsp/dev.c index 3e4d42ab..10eda029 100644 --- a/drivers/platform/tegra/nvadsp/dev.c +++ b/drivers/platform/tegra/nvadsp/dev.c @@ -505,6 +505,9 @@ static int __init nvadsp_probe(struct platform_device *pdev) drv_data->base_regs_saved = drv_data->base_regs; for (irq_iter = 0; irq_iter < drv_data->chip_data->num_irqs; irq_iter++) { + if ((iter == WFI_VIRQ) && drv_data->chip_data->no_wfi_irq) + continue; + irq_num = platform_get_irq(pdev, irq_iter); if (irq_num < 0) { dev_err(dev, "Failed to get irq number for index %d\n", diff --git a/drivers/platform/tegra/nvadsp/dev.h b/drivers/platform/tegra/nvadsp/dev.h index c248bd4b..91503ec0 100644 --- a/drivers/platform/tegra/nvadsp/dev.h +++ b/drivers/platform/tegra/nvadsp/dev.h @@ -153,6 +153,7 @@ struct nvadsp_chipdata { int end_irq; bool amc_not_avlbl; + bool no_wfi_irq; bool amc_err_war; u32 chipid_ext; diff --git a/drivers/platform/tegra/nvadsp/os.c b/drivers/platform/tegra/nvadsp/os.c index 832b0d40..79e37e33 100644 --- a/drivers/platform/tegra/nvadsp/os.c +++ b/drivers/platform/tegra/nvadsp/os.c @@ -1611,7 +1611,9 @@ static void nvadsp_free_os_interrupts(struct nvadsp_os_data *priv) struct device *dev = &priv->pdev->dev; devm_free_irq(dev, wdt_virq, priv); - devm_free_irq(dev, wfi_virq, priv); + + if (!(drv_data->chip_data->no_wfi_irq)) + devm_free_irq(dev, wfi_virq, priv); } static int nvadsp_setup_os_interrupts(struct nvadsp_os_data *priv) @@ -1629,11 +1631,13 @@ static int nvadsp_setup_os_interrupts(struct nvadsp_os_data *priv) goto end; } - ret = devm_request_irq(dev, wfi_virq, adsp_wfi_handler, - IRQF_TRIGGER_RISING, "adsp wfi", priv); - if (ret) { - dev_err(dev, "cannot request for wfi interrupt\n"); - goto free_interrupts; + if (!(drv_data->chip_data->no_wfi_irq)) { + ret = devm_request_irq(dev, wfi_virq, adsp_wfi_handler, + IRQF_TRIGGER_RISING, "adsp wfi", priv); + if (ret) { + dev_err(dev, "cannot request for wfi interrupt\n"); + goto free_interrupts; + } } end: @@ -1858,6 +1862,7 @@ static int __nvadsp_os_suspend(struct nvadsp_os_data *priv) struct device *dev = &priv->pdev->dev; struct nvadsp_drv_data *drv_data = platform_get_drvdata(priv->pdev); struct nvadsp_handle *nvadsp_handle = &drv_data->nvadsp_handle; + unsigned long wfi_timeout; int ret; bool status = false; @@ -1882,16 +1887,25 @@ static int __nvadsp_os_suspend(struct nvadsp_os_data *priv) } dev_dbg(dev, "Waiting for ADSP OS suspend...\n"); - ret = wait_for_completion_timeout(&priv->entered_wfi, - msecs_to_jiffies(ADSP_WFI_TIMEOUT)); - if (WARN_ON(ret <= 0)) { - dev_err(dev, "Unable to suspend ADSP OS err = %d\n", ret); - ret = (ret < 0) ? ret : -ETIMEDOUT; - goto out; + + if (!(drv_data->chip_data->no_wfi_irq)) { + ret = wait_for_completion_timeout(&priv->entered_wfi, + msecs_to_jiffies(ADSP_WFI_TIMEOUT)); + if (WARN_ON(ret <= 0)) { + dev_err(dev, "Unable to suspend ADSP OS err = %d\n", ret); + ret = (ret < 0) ? ret : -ETIMEDOUT; + goto out; + } } - status = nvadsp_check_wfi_status(drv_data); + wfi_timeout = jiffies + msecs_to_jiffies(ADSP_WFI_TIMEOUT); + do { + status = nvadsp_check_wfi_status(drv_data); + mdelay(2); + } while (time_before(jiffies, wfi_timeout) && !status); + if (!status) { + dev_err(dev, "Core WFI failed\n"); ret = -EDEADLK; goto out; } @@ -1942,8 +1956,25 @@ static void __nvadsp_os_stop(struct nvadsp_os_data *priv, bool reload) NVADSP_MBOX_SMSG, true, UINT_MAX); if (err) dev_err(dev, "failed to send stop msg to adsp\n"); - err = wait_for_completion_timeout(&priv->entered_wfi, - msecs_to_jiffies(ADSP_WFI_TIMEOUT)); + + if (!(drv_data->chip_data->no_wfi_irq)) { + err = wait_for_completion_timeout(&priv->entered_wfi, + msecs_to_jiffies(ADSP_WFI_TIMEOUT)); + if (err <= 0) + err = (err < 0) ? err : -ETIMEDOUT; + } else { + unsigned long wfi_timeout; + bool status = false; + + wfi_timeout = jiffies + msecs_to_jiffies(ADSP_WFI_TIMEOUT); + do { + status = nvadsp_check_wfi_status(drv_data); + mdelay(2); + } while (time_before(jiffies, wfi_timeout) && !status); + + if (!status) + err = -EDEADLK; + } /* * ADSP needs to be in WFI/WFE state to properly reset it. @@ -1955,7 +1986,7 @@ static void __nvadsp_os_stop(struct nvadsp_os_data *priv, bool reload) nvadsp_assert_adsp(drv_data); /* Don't reload ADSPOS if ADSP state is not WFI/WFE */ - if (WARN_ON(err <= 0)) { + if (WARN_ON(err < 0)) { dev_err(dev, "%s: unable to enter wfi state err = %d\n", __func__, err); goto end;