| From bacdcb6675e170bb2e8d3824da220e10274f42a7 Mon Sep 17 00:00:00 2001 |
| From: Tony Lindgren <tony@atomide.com> |
| Date: Wed, 23 Oct 2019 08:31:38 -0700 |
| Subject: dmaengine: cppi41: Fix cppi41_dma_prep_slave_sg() when idle |
| |
| From: Tony Lindgren <tony@atomide.com> |
| |
| 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> |
| |
| --- |
| drivers/dma/ti/cppi41.c | 21 ++++++++++++++++++++- |
| 1 file changed, 20 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/dma/ti/cppi41.c |
| +++ b/drivers/dma/ti/cppi41.c |
| @@ -586,9 +586,22 @@ static struct dma_async_tx_descriptor *c |
| 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) { |
| @@ -611,7 +624,13 @@ static struct dma_async_tx_descriptor *c |
| 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) |