Commit 35609502 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dmaengine-fix-4.10-rc7' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine fixes from Vinod Koul:
 "A couple of fixes showed up late in the cycle so sending them up and
  sending early in the week and not on Friday :).

  They fix a double lock in pl330 driver and runtime pm fixes for cppi
  driver"

* tag 'dmaengine-fix-4.10-rc7' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: pl330: fix double lock
  dmaengine: cppi41: Clean up pointless warnings
  dmaengine: cppi41: Fix oops in cppi41_runtime_resume
  dmaengine: cppi41: Fix runtime PM timeouts with USB mass storage
parents c325b353 91539eb1
...@@ -153,6 +153,8 @@ struct cppi41_dd { ...@@ -153,6 +153,8 @@ struct cppi41_dd {
/* context for suspend/resume */ /* context for suspend/resume */
unsigned int dma_tdfdq; unsigned int dma_tdfdq;
bool is_suspended;
}; };
#define FIST_COMPLETION_QUEUE 93 #define FIST_COMPLETION_QUEUE 93
...@@ -257,6 +259,10 @@ static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc) ...@@ -257,6 +259,10 @@ static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
BUG_ON(desc_num >= ALLOC_DECS_NUM); BUG_ON(desc_num >= ALLOC_DECS_NUM);
c = cdd->chan_busy[desc_num]; c = cdd->chan_busy[desc_num];
cdd->chan_busy[desc_num] = NULL; cdd->chan_busy[desc_num] = NULL;
/* Usecount for chan_busy[], paired with push_desc_queue() */
pm_runtime_put(cdd->ddev.dev);
return c; return c;
} }
...@@ -317,12 +323,12 @@ static irqreturn_t cppi41_irq(int irq, void *data) ...@@ -317,12 +323,12 @@ static irqreturn_t cppi41_irq(int irq, void *data)
while (val) { while (val) {
u32 desc, len; u32 desc, len;
int error;
error = pm_runtime_get(cdd->ddev.dev); /*
if (error < 0) * This should never trigger, see the comments in
dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n", * push_desc_queue()
__func__, error); */
WARN_ON(cdd->is_suspended);
q_num = __fls(val); q_num = __fls(val);
val &= ~(1 << q_num); val &= ~(1 << q_num);
...@@ -343,9 +349,6 @@ static irqreturn_t cppi41_irq(int irq, void *data) ...@@ -343,9 +349,6 @@ static irqreturn_t cppi41_irq(int irq, void *data)
c->residue = pd_trans_len(c->desc->pd6) - len; c->residue = pd_trans_len(c->desc->pd6) - len;
dma_cookie_complete(&c->txd); dma_cookie_complete(&c->txd);
dmaengine_desc_get_callback_invoke(&c->txd, NULL); dmaengine_desc_get_callback_invoke(&c->txd, NULL);
pm_runtime_mark_last_busy(cdd->ddev.dev);
pm_runtime_put_autosuspend(cdd->ddev.dev);
} }
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -447,6 +450,15 @@ static void push_desc_queue(struct cppi41_channel *c) ...@@ -447,6 +450,15 @@ static void push_desc_queue(struct cppi41_channel *c)
*/ */
__iowmb(); __iowmb();
/*
* DMA transfers can take at least 200ms to complete with USB mass
* storage connected. To prevent autosuspend timeouts, we must use
* pm_runtime_get/put() when chan_busy[] is modified. This will get
* cleared in desc_to_chan() or cppi41_stop_chan() depending on the
* outcome of the transfer.
*/
pm_runtime_get(cdd->ddev.dev);
desc_phys = lower_32_bits(c->desc_phys); desc_phys = lower_32_bits(c->desc_phys);
desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
WARN_ON(cdd->chan_busy[desc_num]); WARN_ON(cdd->chan_busy[desc_num]);
...@@ -457,20 +469,26 @@ static void push_desc_queue(struct cppi41_channel *c) ...@@ -457,20 +469,26 @@ static void push_desc_queue(struct cppi41_channel *c)
cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
} }
static void pending_desc(struct cppi41_channel *c) /*
* Caller must hold cdd->lock to prevent push_desc_queue()
* getting called out of order. We have both cppi41_dma_issue_pending()
* and cppi41_runtime_resume() call this function.
*/
static void cppi41_run_queue(struct cppi41_dd *cdd)
{ {
struct cppi41_dd *cdd = c->cdd; struct cppi41_channel *c, *_c;
unsigned long flags;
spin_lock_irqsave(&cdd->lock, flags); list_for_each_entry_safe(c, _c, &cdd->pending, node) {
list_add_tail(&c->node, &cdd->pending); push_desc_queue(c);
spin_unlock_irqrestore(&cdd->lock, flags); list_del(&c->node);
}
} }
static void cppi41_dma_issue_pending(struct dma_chan *chan) static void cppi41_dma_issue_pending(struct dma_chan *chan)
{ {
struct cppi41_channel *c = to_cpp41_chan(chan); struct cppi41_channel *c = to_cpp41_chan(chan);
struct cppi41_dd *cdd = c->cdd; struct cppi41_dd *cdd = c->cdd;
unsigned long flags;
int error; int error;
error = pm_runtime_get(cdd->ddev.dev); error = pm_runtime_get(cdd->ddev.dev);
...@@ -482,10 +500,11 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan) ...@@ -482,10 +500,11 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan)
return; return;
} }
if (likely(pm_runtime_active(cdd->ddev.dev))) spin_lock_irqsave(&cdd->lock, flags);
push_desc_queue(c); list_add_tail(&c->node, &cdd->pending);
else if (!cdd->is_suspended)
pending_desc(c); cppi41_run_queue(cdd);
spin_unlock_irqrestore(&cdd->lock, flags);
pm_runtime_mark_last_busy(cdd->ddev.dev); pm_runtime_mark_last_busy(cdd->ddev.dev);
pm_runtime_put_autosuspend(cdd->ddev.dev); pm_runtime_put_autosuspend(cdd->ddev.dev);
...@@ -705,6 +724,9 @@ static int cppi41_stop_chan(struct dma_chan *chan) ...@@ -705,6 +724,9 @@ static int cppi41_stop_chan(struct dma_chan *chan)
WARN_ON(!cdd->chan_busy[desc_num]); WARN_ON(!cdd->chan_busy[desc_num]);
cdd->chan_busy[desc_num] = NULL; cdd->chan_busy[desc_num] = NULL;
/* Usecount for chan_busy[], paired with push_desc_queue() */
pm_runtime_put(cdd->ddev.dev);
return 0; return 0;
} }
...@@ -1150,8 +1172,12 @@ static int __maybe_unused cppi41_resume(struct device *dev) ...@@ -1150,8 +1172,12 @@ static int __maybe_unused cppi41_resume(struct device *dev)
static int __maybe_unused cppi41_runtime_suspend(struct device *dev) static int __maybe_unused cppi41_runtime_suspend(struct device *dev)
{ {
struct cppi41_dd *cdd = dev_get_drvdata(dev); struct cppi41_dd *cdd = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&cdd->lock, flags);
cdd->is_suspended = true;
WARN_ON(!list_empty(&cdd->pending)); WARN_ON(!list_empty(&cdd->pending));
spin_unlock_irqrestore(&cdd->lock, flags);
return 0; return 0;
} }
...@@ -1159,14 +1185,11 @@ static int __maybe_unused cppi41_runtime_suspend(struct device *dev) ...@@ -1159,14 +1185,11 @@ static int __maybe_unused cppi41_runtime_suspend(struct device *dev)
static int __maybe_unused cppi41_runtime_resume(struct device *dev) static int __maybe_unused cppi41_runtime_resume(struct device *dev)
{ {
struct cppi41_dd *cdd = dev_get_drvdata(dev); struct cppi41_dd *cdd = dev_get_drvdata(dev);
struct cppi41_channel *c, *_c;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&cdd->lock, flags); spin_lock_irqsave(&cdd->lock, flags);
list_for_each_entry_safe(c, _c, &cdd->pending, node) { cdd->is_suspended = false;
push_desc_queue(c); cppi41_run_queue(cdd);
list_del(&c->node);
}
spin_unlock_irqrestore(&cdd->lock, flags); spin_unlock_irqrestore(&cdd->lock, flags);
return 0; return 0;
......
...@@ -1699,7 +1699,6 @@ static bool _chan_ns(const struct pl330_dmac *pl330, int i) ...@@ -1699,7 +1699,6 @@ static bool _chan_ns(const struct pl330_dmac *pl330, int i)
static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
{ {
struct pl330_thread *thrd = NULL; struct pl330_thread *thrd = NULL;
unsigned long flags;
int chans, i; int chans, i;
if (pl330->state == DYING) if (pl330->state == DYING)
...@@ -1707,8 +1706,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) ...@@ -1707,8 +1706,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
chans = pl330->pcfg.num_chan; chans = pl330->pcfg.num_chan;
spin_lock_irqsave(&pl330->lock, flags);
for (i = 0; i < chans; i++) { for (i = 0; i < chans; i++) {
thrd = &pl330->channels[i]; thrd = &pl330->channels[i];
if ((thrd->free) && (!_manager_ns(thrd) || if ((thrd->free) && (!_manager_ns(thrd) ||
...@@ -1726,8 +1723,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) ...@@ -1726,8 +1723,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
thrd = NULL; thrd = NULL;
} }
spin_unlock_irqrestore(&pl330->lock, flags);
return thrd; return thrd;
} }
...@@ -1745,7 +1740,6 @@ static inline void _free_event(struct pl330_thread *thrd, int ev) ...@@ -1745,7 +1740,6 @@ static inline void _free_event(struct pl330_thread *thrd, int ev)
static void pl330_release_channel(struct pl330_thread *thrd) static void pl330_release_channel(struct pl330_thread *thrd)
{ {
struct pl330_dmac *pl330; struct pl330_dmac *pl330;
unsigned long flags;
if (!thrd || thrd->free) if (!thrd || thrd->free)
return; return;
...@@ -1757,10 +1751,8 @@ static void pl330_release_channel(struct pl330_thread *thrd) ...@@ -1757,10 +1751,8 @@ static void pl330_release_channel(struct pl330_thread *thrd)
pl330 = thrd->dmac; pl330 = thrd->dmac;
spin_lock_irqsave(&pl330->lock, flags);
_free_event(thrd, thrd->ev); _free_event(thrd, thrd->ev);
thrd->free = true; thrd->free = true;
spin_unlock_irqrestore(&pl330->lock, flags);
} }
/* Initialize the structure for PL330 configuration, that can be used /* Initialize the structure for PL330 configuration, that can be used
...@@ -2122,20 +2114,20 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) ...@@ -2122,20 +2114,20 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
struct pl330_dmac *pl330 = pch->dmac; struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pch->lock, flags); spin_lock_irqsave(&pl330->lock, flags);
dma_cookie_init(chan); dma_cookie_init(chan);
pch->cyclic = false; pch->cyclic = false;
pch->thread = pl330_request_channel(pl330); pch->thread = pl330_request_channel(pl330);
if (!pch->thread) { if (!pch->thread) {
spin_unlock_irqrestore(&pch->lock, flags); spin_unlock_irqrestore(&pl330->lock, flags);
return -ENOMEM; return -ENOMEM;
} }
tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch); tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
spin_unlock_irqrestore(&pch->lock, flags); spin_unlock_irqrestore(&pl330->lock, flags);
return 1; return 1;
} }
...@@ -2238,12 +2230,13 @@ static int pl330_pause(struct dma_chan *chan) ...@@ -2238,12 +2230,13 @@ static int pl330_pause(struct dma_chan *chan)
static void pl330_free_chan_resources(struct dma_chan *chan) static void pl330_free_chan_resources(struct dma_chan *chan)
{ {
struct dma_pl330_chan *pch = to_pchan(chan); struct dma_pl330_chan *pch = to_pchan(chan);
struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags; unsigned long flags;
tasklet_kill(&pch->task); tasklet_kill(&pch->task);
pm_runtime_get_sync(pch->dmac->ddma.dev); pm_runtime_get_sync(pch->dmac->ddma.dev);
spin_lock_irqsave(&pch->lock, flags); spin_lock_irqsave(&pl330->lock, flags);
pl330_release_channel(pch->thread); pl330_release_channel(pch->thread);
pch->thread = NULL; pch->thread = NULL;
...@@ -2251,7 +2244,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan) ...@@ -2251,7 +2244,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
if (pch->cyclic) if (pch->cyclic)
list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
spin_unlock_irqrestore(&pch->lock, flags); spin_unlock_irqrestore(&pl330->lock, flags);
pm_runtime_mark_last_busy(pch->dmac->ddma.dev); pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
pm_runtime_put_autosuspend(pch->dmac->ddma.dev); pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment