| From 7166ee85b6c99e37cbaa98fbae08af0503899077 Mon Sep 17 00:00:00 2001 |
| From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Date: Sun, 5 Jul 2020 14:56:20 +0300 |
| Subject: [PATCH] dmaengine: dw: Initialize channel before each transfer |
| |
| commit 99ba8b9b0d9780e9937eb1d488d120e9e5c2533d upstream. |
| |
| In some cases DMA can be used only with a consumer which does runtime power |
| management and on the platforms, that have DMA auto power gating logic |
| (see comments in the drivers/acpi/acpi_lpss.c), may result in DMA losing |
| its context. Simple mitigation of this issue is to initialize channel |
| each time the consumer initiates a transfer. |
| |
| Fixes: cfdf5b6cc598 ("dw_dmac: add support for Lynxpoint DMA controllers") |
| Reported-by: Tsuchiya Yuto <kitakar@gmail.com> |
| Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Acked-by: Viresh Kumar <viresh.kumar@linaro.org> |
| BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206403 |
| Link: https://lore.kernel.org/r/20200705115620.51929-1-andriy.shevchenko@linux.intel.com |
| Signed-off-by: Vinod Koul <vkoul@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c |
| index 21cb2a58dbd2..a1b56f52db2f 100644 |
| --- a/drivers/dma/dw/core.c |
| +++ b/drivers/dma/dw/core.c |
| @@ -118,16 +118,11 @@ static void dwc_initialize(struct dw_dma_chan *dwc) |
| { |
| struct dw_dma *dw = to_dw_dma(dwc->chan.device); |
| |
| - if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags)) |
| - return; |
| - |
| dw->initialize_chan(dwc); |
| |
| /* Enable interrupts */ |
| channel_set_bit(dw, MASK.XFER, dwc->mask); |
| channel_set_bit(dw, MASK.ERROR, dwc->mask); |
| - |
| - set_bit(DW_DMA_IS_INITIALIZED, &dwc->flags); |
| } |
| |
| /*----------------------------------------------------------------------*/ |
| @@ -954,8 +949,6 @@ static void dwc_issue_pending(struct dma_chan *chan) |
| |
| void do_dw_dma_off(struct dw_dma *dw) |
| { |
| - unsigned int i; |
| - |
| dma_writel(dw, CFG, 0); |
| |
| channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); |
| @@ -966,9 +959,6 @@ void do_dw_dma_off(struct dw_dma *dw) |
| |
| while (dma_readl(dw, CFG) & DW_CFG_DMA_EN) |
| cpu_relax(); |
| - |
| - for (i = 0; i < dw->dma.chancnt; i++) |
| - clear_bit(DW_DMA_IS_INITIALIZED, &dw->chan[i].flags); |
| } |
| |
| void do_dw_dma_on(struct dw_dma *dw) |
| @@ -1032,8 +1022,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan) |
| /* Clear custom channel configuration */ |
| memset(&dwc->dws, 0, sizeof(struct dw_dma_slave)); |
| |
| - clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags); |
| - |
| /* Disable interrupts */ |
| channel_clear_bit(dw, MASK.XFER, dwc->mask); |
| channel_clear_bit(dw, MASK.BLOCK, dwc->mask); |
| -- |
| 2.27.0 |
| |