From c3a4528788cf09d709217f21be4b0fc38ada17d0 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 25 Mar 2017 19:04:02 -0400 Subject: dmaengine: qcom_hidma: disable/enable IRQs on pause/resume Once the channels are stopped, disable interrupts to make sure no new HW interaction can happen. Similarly, re-enable the interrupts only if we know that channel is operational again. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_ll.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/dma') diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 6645bdf0d151..1530a661518d 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -499,6 +499,9 @@ int hidma_ll_enable(struct hidma_lldev *lldev) lldev->trch_state = HIDMA_CH_ENABLED; lldev->evch_state = HIDMA_CH_ENABLED; + /* enable irqs */ + writel(ENABLE_IRQS, lldev->evca + HIDMA_EVCA_IRQ_EN_REG); + return 0; } @@ -596,6 +599,9 @@ int hidma_ll_disable(struct hidma_lldev *lldev) lldev->trch_state = HIDMA_CH_SUSPENDED; lldev->evch_state = HIDMA_CH_SUSPENDED; + + /* disable interrupts */ + writel(0, lldev->evca + HIDMA_EVCA_IRQ_EN_REG); return 0; } -- cgit v1.2.3 From dc7c733acb04307563da357af6118b12948c3f50 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 25 Mar 2017 19:04:03 -0400 Subject: dmaengine: qcom_hidma: pause the channel on shutdown We need to ensure that all DMAs and interrupts are cleared during shutdown operation in order for kexec to start the next kernel clearly. Otherwise, HW could be performing a DMA into random addresses in the middle of second kernel start. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/dma') diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 3c982c96b4b7..5072a7d306d4 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -865,6 +865,20 @@ bailout: return rc; } +static void hidma_shutdown(struct platform_device *pdev) +{ + struct hidma_dev *dmadev = platform_get_drvdata(pdev); + + dev_info(dmadev->ddev.dev, "HI-DMA engine shutdown\n"); + + pm_runtime_get_sync(dmadev->ddev.dev); + if (hidma_ll_disable(dmadev->lldev)) + dev_warn(dmadev->ddev.dev, "channel did not stop\n"); + pm_runtime_mark_last_busy(dmadev->ddev.dev); + pm_runtime_put_autosuspend(dmadev->ddev.dev); + +} + static int hidma_remove(struct platform_device *pdev) { struct hidma_dev *dmadev = platform_get_drvdata(pdev); @@ -908,6 +922,7 @@ MODULE_DEVICE_TABLE(of, hidma_match); static struct platform_driver hidma_driver = { .probe = hidma_probe, .remove = hidma_remove, + .shutdown = hidma_shutdown, .driver = { .name = "hidma", .of_match_table = hidma_match, -- cgit v1.2.3