summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2019-10-23 08:31:38 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-11-06 12:43:36 +0100
commit7a7313ae7163cb2c206abf071a4e098a3ba7f140 (patch)
tree0c62db1b61ed423ac888f63d7012adafd9f15182 /drivers/dma
parent1b940dd55d42133791d7ba4841adfcf436fab98e (diff)
dmaengine: cppi41: Fix cppi41_dma_prep_slave_sg() when idle
commit bacdcb6675e170bb2e8d3824da220e10274f42a7 upstream. Yegor Yefremov <yegorslists@googlemail.com> reported that musb and ftdi uart can fail for the first open of the uart unless connected using a hub. This is because the first dma call done by musb_ep_program() must wait if cppi41 is PM runtime suspended. Otherwise musb_ep_program() continues with other non-dma packets before the DMA transfer is started causing at least ftdi uarts to fail to receive data. Let's fix the issue by waking up cppi41 with PM runtime calls added to cppi41_dma_prep_slave_sg() and return NULL if still idled. This way we have musb_ep_program() continue with PIO until cppi41 is awake. Fixes: fdea2d09b997 ("dmaengine: cppi41: Add basic PM runtime support") Reported-by: Yegor Yefremov <yegorslists@googlemail.com> Signed-off-by: Tony Lindgren <tony@atomide.com> Cc: stable@vger.kernel.org # v4.9+ Link: https://lore.kernel.org/r/20191023153138.23442-1-tony@atomide.com Signed-off-by: Vinod Koul <vkoul@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/cppi41.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index ddd4a3932127..cf119a8ccdd5 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -585,9 +585,22 @@ static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
enum dma_transfer_direction dir, unsigned long tx_flags, void *context)
{
struct cppi41_channel *c = to_cpp41_chan(chan);
+ struct dma_async_tx_descriptor *txd = NULL;
+ struct cppi41_dd *cdd = c->cdd;
struct cppi41_desc *d;
struct scatterlist *sg;
unsigned int i;
+ int error;
+
+ error = pm_runtime_get(cdd->ddev.dev);
+ if (error < 0) {
+ pm_runtime_put_noidle(cdd->ddev.dev);
+
+ return NULL;
+ }
+
+ if (cdd->is_suspended)
+ goto err_out_not_ready;
d = c->desc;
for_each_sg(sgl, sg, sg_len, i) {
@@ -610,7 +623,13 @@ static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
d++;
}
- return &c->txd;
+ txd = &c->txd;
+
+err_out_not_ready:
+ pm_runtime_mark_last_busy(cdd->ddev.dev);
+ pm_runtime_put_autosuspend(cdd->ddev.dev);
+
+ return txd;
}
static void cppi41_compute_td_desc(struct cppi41_desc *d)