From 816abce5a93dc4ee93d277f40311a1b2147b9d99 Mon Sep 17 00:00:00 2001 From: Ajay Nandakumar Date: Wed, 10 May 2017 11:42:40 +0530 Subject: [PATCH] platform: nvadsp: move request/free irqs calls The request irqs are moved just before starting ADSP and freed when adsp is suspended/stopped. This is since the new agic driver is based on a device-driver model and requires all interrupts to be freed before it could suspend. Bug 200270956 Change-Id: I8ecd05ebe52020f11be79b9a1da37a85fed432ac Signed-off-by: Ajay Nandakumar Reviewed-on: http://git-master/r/1478838 Signed-off-by: Nitin Kumbhar Reviewed-on: https://git-master.nvidia.com/r/1537326 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: svccoveritychecker GVS: Gerrit_Virtual_Submit --- drivers/platform/tegra/nvadsp/amc.c | 30 ++++-- drivers/platform/tegra/nvadsp/dev.c | 5 - drivers/platform/tegra/nvadsp/dev.h | 6 +- drivers/platform/tegra/nvadsp/hwmailbox.c | 71 ++++++++------ drivers/platform/tegra/nvadsp/hwmailbox.h | 3 + drivers/platform/tegra/nvadsp/os.c | 108 ++++++++++++++++++---- 6 files changed, 157 insertions(+), 66 deletions(-) diff --git a/drivers/platform/tegra/nvadsp/amc.c b/drivers/platform/tegra/nvadsp/amc.c index 92803620..1d37d4f2 100644 --- a/drivers/platform/tegra/nvadsp/amc.c +++ b/drivers/platform/tegra/nvadsp/amc.c @@ -3,7 +3,7 @@ * * AMC and ARAM handling * - * Copyright (C) 2014-2016, NVIDIA Corporation. All rights reserved. + * Copyright (C) 2014-2017, NVIDIA Corporation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -162,23 +162,33 @@ static irqreturn_t nvadsp_amc_error_int_handler(int irq, void *devid) return IRQ_HANDLED; } -status_t __init nvadsp_amc_init(struct platform_device *pdev) +void nvadsp_free_amc_interrupts(struct platform_device *pdev) { struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; + struct device_node *node; + + node = dev->of_node; + + if (!of_device_is_compatible(node, "nvidia,tegra18x-adsp-hv")) + devm_free_irq(dev, drv->agic_irqs[AMC_ERR_VIRQ], pdev); +} + +int nvadsp_setup_amc_interrupts(struct platform_device *pdev) +{ + struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct device_node *node; int ret = 0; + node = dev->of_node; nvadsp_pdev = pdev; nvadsp_drv_data = drv; - if (!of_device_is_compatible(node, "nvidia,tegra18x-adsp-hv")) { - dev_info(&pdev->dev, "Registering AMC Error Interrupt\n"); - ret = request_irq(drv->agic_irqs[AMC_ERR_VIRQ], - nvadsp_amc_error_int_handler, 0, "AMC error int", pdev); - } - - dev_info(&pdev->dev, "AMC/ARAM initialized.\n"); + if (!of_device_is_compatible(node, "nvidia,tegra18x-adsp-hv")) + ret = devm_request_irq(dev, drv->agic_irqs[AMC_ERR_VIRQ], + nvadsp_amc_error_int_handler, 0, + "AMC error int", pdev); return ret; } diff --git a/drivers/platform/tegra/nvadsp/dev.c b/drivers/platform/tegra/nvadsp/dev.c index feef42b4..0738f56c 100644 --- a/drivers/platform/tegra/nvadsp/dev.c +++ b/drivers/platform/tegra/nvadsp/dev.c @@ -322,11 +322,6 @@ static int __init nvadsp_probe(struct platform_device *pdev) if (ret < 0) goto out; #endif - - ret = nvadsp_amc_init(pdev); - if (ret) - goto err; - ret = nvadsp_hwmbox_init(pdev); if (ret) goto err; diff --git a/drivers/platform/tegra/nvadsp/dev.h b/drivers/platform/tegra/nvadsp/dev.h index c31ef749..653c93d9 100644 --- a/drivers/platform/tegra/nvadsp/dev.h +++ b/drivers/platform/tegra/nvadsp/dev.h @@ -146,8 +146,6 @@ struct nvadsp_drv_data { struct platform_device *pdev; struct resource *dram_region[ADSP_MAX_DRAM_MAP]; struct hwmbox_queue hwmbox_send_queue; - int hwmbox_send_virq; - int hwmbox_recv_virq; struct nvadsp_mbox **mboxes; unsigned long *mbox_ids; @@ -216,7 +214,9 @@ struct nvadsp_drv_data { #define UART_BAUD_RATE 9600 status_t nvadsp_mbox_init(struct platform_device *pdev); -status_t nvadsp_amc_init(struct platform_device *pdev); + +int nvadsp_setup_amc_interrupts(struct platform_device *pdev); +void nvadsp_free_amc_interrupts(struct platform_device *pdev); #ifdef CONFIG_TEGRA_ADSP_DFS void adsp_cpu_set_rate(unsigned long freq); diff --git a/drivers/platform/tegra/nvadsp/hwmailbox.c b/drivers/platform/tegra/nvadsp/hwmailbox.c index ebb70b8c..2b3b1240 100644 --- a/drivers/platform/tegra/nvadsp/hwmailbox.c +++ b/drivers/platform/tegra/nvadsp/hwmailbox.c @@ -266,43 +266,58 @@ static irqreturn_t hwmbox_recv_full_int_handler(int irq, void *devid) return IRQ_HANDLED; } +void nvadsp_free_hwmbox_interrupts(struct platform_device *pdev) +{ + + struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int recv_virq, send_virq; + + recv_virq = drv->agic_irqs[MBOX_RECV_VIRQ]; + send_virq = drv->agic_irqs[MBOX_SEND_VIRQ]; + + devm_free_irq(dev, recv_virq, pdev); + devm_free_irq(dev, send_virq, pdev); +} + +int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev) +{ + struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int recv_virq, send_virq; + int ret; + + recv_virq = drv->agic_irqs[MBOX_RECV_VIRQ]; + send_virq = drv->agic_irqs[MBOX_SEND_VIRQ]; + + ret = devm_request_irq(dev, recv_virq, hwmbox_recv_full_int_handler, + IRQF_TRIGGER_RISING, "hwmbox0_recv_full", pdev); + if (ret) + goto err; + + ret = devm_request_irq(dev, send_virq, hwmbox_send_empty_int_handler, + IRQF_TRIGGER_RISING, + "hwmbox1_send_empty", pdev); + if (ret) + goto free_interrupts; + + return ret; + + free_interrupts: + nvadsp_free_hwmbox_interrupts(pdev); + err: + return ret; +} + int __init nvadsp_hwmbox_init(struct platform_device *pdev) { struct nvadsp_drv_data *drv = platform_get_drvdata(pdev); - int recv_virq, send_virq; int ret = 0; nvadsp_pdev = pdev; nvadsp_drv_data = drv; - recv_virq = drv->agic_irqs[MBOX_RECV_VIRQ]; - drv->hwmbox_recv_virq = recv_virq; - - send_virq = drv->agic_irqs[MBOX_SEND_VIRQ]; - drv->hwmbox_send_virq = send_virq; - - ret = request_irq(recv_virq, hwmbox_recv_full_int_handler, - IRQF_TRIGGER_RISING, "hwmbox0_recv_full", pdev); - if (ret) - goto req_recv_virq; - - ret = request_irq(send_virq, hwmbox_send_empty_int_handler, - IRQF_TRIGGER_RISING, - "hwmbox1_send_empty", pdev); - if (ret) - goto req_send_virq; - hwmboxq_init(&drv->hwmbox_send_queue); return ret; - - req_send_virq: - free_irq(recv_virq, pdev); - - req_recv_virq: - irq_dispose_mapping(send_virq); - irq_dispose_mapping(recv_virq); - nvadsp_drv_data = NULL; - nvadsp_pdev = NULL; - return ret; } diff --git a/drivers/platform/tegra/nvadsp/hwmailbox.h b/drivers/platform/tegra/nvadsp/hwmailbox.h index 2071a83e..b0792961 100644 --- a/drivers/platform/tegra/nvadsp/hwmailbox.h +++ b/drivers/platform/tegra/nvadsp/hwmailbox.h @@ -110,4 +110,7 @@ int nvadsp_hwmbox_init(struct platform_device *); status_t nvadsp_hwmbox_send_data(uint16_t, uint32_t, uint32_t); void dump_mailbox_regs(void); +int nvadsp_setup_hwmbox_interrupts(struct platform_device *pdev); +void nvadsp_free_hwmbox_interrupts(struct platform_device *pdev); + #endif /* __HWMAILBOX_H */ diff --git a/drivers/platform/tegra/nvadsp/os.c b/drivers/platform/tegra/nvadsp/os.c index 7fbf7b15..8093878d 100644 --- a/drivers/platform/tegra/nvadsp/os.c +++ b/drivers/platform/tegra/nvadsp/os.c @@ -133,6 +133,8 @@ static struct nvadsp_mbox adsp_com_mbox; static DECLARE_COMPLETION(entered_wfi); static void __nvadsp_os_stop(bool); +static irqreturn_t adsp_wdt_handler(int irq, void *arg); +static irqreturn_t adsp_wfi_handler(int irq, void *arg); #ifdef CONFIG_DEBUG_FS static int adsp_logger_open(struct inode *inode, struct file *file) @@ -1166,6 +1168,83 @@ void dump_adsp_sys(void) } EXPORT_SYMBOL(dump_adsp_sys); +static void nvadsp_free_os_interrupts(struct nvadsp_os_data *priv) +{ + struct nvadsp_drv_data *drv_data = platform_get_drvdata(priv->pdev); + int wdt_virq = drv_data->agic_irqs[WDT_VIRQ]; + int wfi_virq = drv_data->agic_irqs[WFI_VIRQ]; + struct device *dev = &priv->pdev->dev; + + devm_free_irq(dev, wdt_virq, priv); + devm_free_irq(dev, wfi_virq, priv); +} + +static int nvadsp_setup_os_interrupts(struct nvadsp_os_data *priv) +{ + struct nvadsp_drv_data *drv_data = platform_get_drvdata(priv->pdev); + int wdt_virq = drv_data->agic_irqs[WDT_VIRQ]; + int wfi_virq = drv_data->agic_irqs[WFI_VIRQ]; + struct device *dev = &priv->pdev->dev; + int ret; + + ret = devm_request_irq(dev, wdt_virq, adsp_wdt_handler, + IRQF_TRIGGER_RISING, "adsp watchdog", priv); + if (ret) { + dev_err(dev, "failed to get adsp watchdog interrupt\n"); + 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; + } + + writel(DISABLE_MBOX2_FULL_INT, + priv->hwmailbox_base + drv_data->chip_data->hwmb.hwmbox2_reg); + + end: + + return ret; + + free_interrupts: + nvadsp_free_os_interrupts(priv); + return ret; +} + +static void free_interrupts(struct nvadsp_os_data *priv) +{ + nvadsp_free_os_interrupts(priv); + nvadsp_free_hwmbox_interrupts(priv->pdev); + nvadsp_free_amc_interrupts(priv->pdev); +} + +static int setup_interrupts(struct nvadsp_os_data *priv) +{ + int ret; + + ret = nvadsp_setup_os_interrupts(priv); + if (ret) + goto err; + + ret = nvadsp_setup_hwmbox_interrupts(priv->pdev); + if (ret) + goto free_os_interrupts; + ret = nvadsp_setup_amc_interrupts(priv->pdev); + if (ret) + goto free_hwmbox_interrupts; + + return ret; + + free_hwmbox_interrupts: + nvadsp_free_hwmbox_interrupts(priv->pdev); + free_os_interrupts: + nvadsp_free_os_interrupts(priv); + err: + return ret; +} + int nvadsp_os_start(void) { struct nvadsp_drv_data *drv_data; @@ -1198,12 +1277,17 @@ int nvadsp_os_start(void) if (ret < 0) goto unlock; #endif + ret = setup_interrupts(&priv); + if (ret < 0) + goto unlock; + ret = __nvadsp_os_start(); if (ret) { priv.os_running = drv_data->adsp_os_running = false; /* if start fails call pm suspend of adsp driver */ dev_err(dev, "adsp failed to boot with ret = %d\n", ret); dump_adsp_sys(); + free_interrupts(&priv); #ifdef CONFIG_PM pm_runtime_put_sync(&priv.pdev->dev); #endif @@ -1372,6 +1456,7 @@ void nvadsp_os_stop(void) priv.os_running = drv_data->adsp_os_running = false; + free_interrupts(&priv); #ifdef CONFIG_PM if (pm_runtime_put_sync(dev) < 0) dev_err(dev, "failed in pm_runtime_put_sync\n"); @@ -1410,6 +1495,8 @@ int nvadsp_os_suspend(void) if (!ret) { #ifdef CONFIG_PM struct device *dev = &priv.pdev->dev; + + free_interrupts(&priv); ret = pm_runtime_put_sync(&priv.pdev->dev); if (ret < 0) dev_err(dev, "failed in pm_runtime_put_sync\n"); @@ -1465,7 +1552,7 @@ static void nvadsp_os_restart(struct work_struct *work) dev_crit(dev, "Unable to restart ADSP OS\n"); } -static irqreturn_t adsp_wfi_handler(int irq, void *arg) +static irqreturn_t adsp_wfi_handler(int irq, void *arg) { struct nvadsp_os_data *data = arg; struct device *dev = &data->pdev->dev; @@ -1564,8 +1651,6 @@ static ssize_t tegrafw_read_adsp(struct device *dev, int __init nvadsp_os_probe(struct platform_device *pdev) { struct nvadsp_drv_data *drv_data = platform_get_drvdata(pdev); - int wdt_virq = drv_data->agic_irqs[WDT_VIRQ]; - int wfi_virq = drv_data->agic_irqs[WFI_VIRQ]; uint16_t com_mid = ADSP_COM_MBOX_ID; struct device *dev = &pdev->dev; int ret = 0; @@ -1579,23 +1664,6 @@ int __init nvadsp_os_probe(struct platform_device *pdev) priv.app_alloc_addr = drv_data->adsp_mem[ADSP_APP_ADDR]; priv.app_size = drv_data->adsp_mem[ADSP_APP_SIZE]; - ret = devm_request_irq(dev, wdt_virq, adsp_wdt_handler, - IRQF_TRIGGER_RISING, "adsp watchdog", &priv); - if (ret) { - dev_err(dev, "failed to get adsp watchdog interrupt\n"); - 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 end; - } - - writel(DISABLE_MBOX2_FULL_INT, - priv.hwmailbox_base + drv_data->chip_data->hwmb.hwmbox2_reg); - if (of_device_is_compatible(dev->of_node, "nvidia,tegra210-adsp")) { drv_data->assert_adsp = __assert_adsp; drv_data->deassert_adsp = __deassert_adsp;