dmaengine-fix-4.10-rc7
Few late fixes for this cycle - pl330 double lock fix - more fixes for runtime pm handling on cppi -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJYkgb+AAoJEHwUBw8lI4NH1LIP/2vG1GjnkbVP4lKlgFQkHU3f VaG60A3/70j247NLa3Fu5HzctRsfYSI8ES/fhZOXrVYRrPUkH+6itYDAECEwRhhJ bez1gcU3BDRhkmVc4hTUVfcBMDVnyliHwRaNsyWIS5FB95qmrODQLYuXHSvij56j Cxb6INU5fJuoGu3K0y+/1ABURwPWjx8RQR9+Yv3RAbZMn079MFu4JXKPDS0r0Bm6 nYZrpaky9zQLQQytTfUU3SYhe/K5/IFJro/EPdf/5kHYg/20Ub/zEqlBfKY1jL6u 2XgqhPABgkE4GwU8fr4nuOT9+xU7DEFPwuWiCphO4SQHVw6O/BC8R6Pd4x7gVX4E wK9NpOWZWQQHom0pezn6wF3GrYyaHUULg1SI805HVogEvLAufKYTGIP8WJC8ORZi 5nStEyU4k2GS9SVaoH8dh/VQdb7X0G9tkRqcuCj+I7Yuq9LpCNYar2cZ7P+bqeII zZ0HNAoBvQdVKn8PeHQUbdhblZ13pK0k2Lf0RT88aG0mYEl0dt6CknYEUURbYwqQ KRN3tRB0+C99Hdi8DCsUGitFyLnIfMeJ++JJfR4rw2uGskvk/VEPStj7zbuFo1qg MD8ydwZvYr9lOQBOC55K4BCsNbXHWb216OH5sOdzMsInJrLpjgeD0Ya7Il11KEer v/OmLjYybzFPWq3pp4/3 =4hDL -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
35609502ac
2 changed files with 52 additions and 36 deletions
|
@ -153,6 +153,8 @@ struct cppi41_dd {
|
|||
|
||||
/* context for suspend/resume */
|
||||
unsigned int dma_tdfdq;
|
||||
|
||||
bool is_suspended;
|
||||
};
|
||||
|
||||
#define FIST_COMPLETION_QUEUE 93
|
||||
|
@ -257,6 +259,10 @@ static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
|
|||
BUG_ON(desc_num >= ALLOC_DECS_NUM);
|
||||
c = cdd->chan_busy[desc_num];
|
||||
cdd->chan_busy[desc_num] = NULL;
|
||||
|
||||
/* Usecount for chan_busy[], paired with push_desc_queue() */
|
||||
pm_runtime_put(cdd->ddev.dev);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -317,12 +323,12 @@ static irqreturn_t cppi41_irq(int irq, void *data)
|
|||
|
||||
while (val) {
|
||||
u32 desc, len;
|
||||
int error;
|
||||
|
||||
error = pm_runtime_get(cdd->ddev.dev);
|
||||
if (error < 0)
|
||||
dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n",
|
||||
__func__, error);
|
||||
/*
|
||||
* This should never trigger, see the comments in
|
||||
* push_desc_queue()
|
||||
*/
|
||||
WARN_ON(cdd->is_suspended);
|
||||
|
||||
q_num = __fls(val);
|
||||
val &= ~(1 << q_num);
|
||||
|
@ -343,9 +349,6 @@ static irqreturn_t cppi41_irq(int irq, void *data)
|
|||
c->residue = pd_trans_len(c->desc->pd6) - len;
|
||||
dma_cookie_complete(&c->txd);
|
||||
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;
|
||||
|
@ -447,6 +450,15 @@ static void push_desc_queue(struct cppi41_channel *c)
|
|||
*/
|
||||
__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_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
|
||||
WARN_ON(cdd->chan_busy[desc_num]);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned long flags;
|
||||
struct cppi41_channel *c, *_c;
|
||||
|
||||
spin_lock_irqsave(&cdd->lock, flags);
|
||||
list_add_tail(&c->node, &cdd->pending);
|
||||
spin_unlock_irqrestore(&cdd->lock, flags);
|
||||
list_for_each_entry_safe(c, _c, &cdd->pending, node) {
|
||||
push_desc_queue(c);
|
||||
list_del(&c->node);
|
||||
}
|
||||
}
|
||||
|
||||
static void cppi41_dma_issue_pending(struct dma_chan *chan)
|
||||
{
|
||||
struct cppi41_channel *c = to_cpp41_chan(chan);
|
||||
struct cppi41_dd *cdd = c->cdd;
|
||||
unsigned long flags;
|
||||
int error;
|
||||
|
||||
error = pm_runtime_get(cdd->ddev.dev);
|
||||
|
@ -482,10 +500,11 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan)
|
|||
return;
|
||||
}
|
||||
|
||||
if (likely(pm_runtime_active(cdd->ddev.dev)))
|
||||
push_desc_queue(c);
|
||||
else
|
||||
pending_desc(c);
|
||||
spin_lock_irqsave(&cdd->lock, flags);
|
||||
list_add_tail(&c->node, &cdd->pending);
|
||||
if (!cdd->is_suspended)
|
||||
cppi41_run_queue(cdd);
|
||||
spin_unlock_irqrestore(&cdd->lock, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(cdd->ddev.dev);
|
||||
pm_runtime_put_autosuspend(cdd->ddev.dev);
|
||||
|
@ -705,6 +724,9 @@ static int cppi41_stop_chan(struct dma_chan *chan)
|
|||
WARN_ON(!cdd->chan_busy[desc_num]);
|
||||
cdd->chan_busy[desc_num] = NULL;
|
||||
|
||||
/* Usecount for chan_busy[], paired with push_desc_queue() */
|
||||
pm_runtime_put(cdd->ddev.dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1150,8 +1172,12 @@ static int __maybe_unused cppi41_resume(struct device *dev)
|
|||
static int __maybe_unused cppi41_runtime_suspend(struct device *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));
|
||||
spin_unlock_irqrestore(&cdd->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1159,14 +1185,11 @@ static int __maybe_unused cppi41_runtime_suspend(struct device *dev)
|
|||
static int __maybe_unused cppi41_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct cppi41_dd *cdd = dev_get_drvdata(dev);
|
||||
struct cppi41_channel *c, *_c;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cdd->lock, flags);
|
||||
list_for_each_entry_safe(c, _c, &cdd->pending, node) {
|
||||
push_desc_queue(c);
|
||||
list_del(&c->node);
|
||||
}
|
||||
cdd->is_suspended = false;
|
||||
cppi41_run_queue(cdd);
|
||||
spin_unlock_irqrestore(&cdd->lock, flags);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
struct pl330_thread *thrd = NULL;
|
||||
unsigned long flags;
|
||||
int chans, i;
|
||||
|
||||
if (pl330->state == DYING)
|
||||
|
@ -1707,8 +1706,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
|
|||
|
||||
chans = pl330->pcfg.num_chan;
|
||||
|
||||
spin_lock_irqsave(&pl330->lock, flags);
|
||||
|
||||
for (i = 0; i < chans; i++) {
|
||||
thrd = &pl330->channels[i];
|
||||
if ((thrd->free) && (!_manager_ns(thrd) ||
|
||||
|
@ -1726,8 +1723,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
|
|||
thrd = NULL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&pl330->lock, flags);
|
||||
|
||||
return thrd;
|
||||
}
|
||||
|
||||
|
@ -1745,7 +1740,6 @@ static inline void _free_event(struct pl330_thread *thrd, int ev)
|
|||
static void pl330_release_channel(struct pl330_thread *thrd)
|
||||
{
|
||||
struct pl330_dmac *pl330;
|
||||
unsigned long flags;
|
||||
|
||||
if (!thrd || thrd->free)
|
||||
return;
|
||||
|
@ -1757,10 +1751,8 @@ static void pl330_release_channel(struct pl330_thread *thrd)
|
|||
|
||||
pl330 = thrd->dmac;
|
||||
|
||||
spin_lock_irqsave(&pl330->lock, flags);
|
||||
_free_event(thrd, thrd->ev);
|
||||
thrd->free = true;
|
||||
spin_unlock_irqrestore(&pl330->lock, flags);
|
||||
}
|
||||
|
||||
/* Initialize the structure for PL330 configuration, that can be used
|
||||
|
@ -2122,20 +2114,20 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
|
|||
struct pl330_dmac *pl330 = pch->dmac;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pch->lock, flags);
|
||||
spin_lock_irqsave(&pl330->lock, flags);
|
||||
|
||||
dma_cookie_init(chan);
|
||||
pch->cyclic = false;
|
||||
|
||||
pch->thread = pl330_request_channel(pl330);
|
||||
if (!pch->thread) {
|
||||
spin_unlock_irqrestore(&pch->lock, flags);
|
||||
spin_unlock_irqrestore(&pl330->lock, flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
|
||||
|
||||
spin_unlock_irqrestore(&pch->lock, flags);
|
||||
spin_unlock_irqrestore(&pl330->lock, flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -2238,12 +2230,13 @@ static int pl330_pause(struct dma_chan *chan)
|
|||
static void pl330_free_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct dma_pl330_chan *pch = to_pchan(chan);
|
||||
struct pl330_dmac *pl330 = pch->dmac;
|
||||
unsigned long flags;
|
||||
|
||||
tasklet_kill(&pch->task);
|
||||
|
||||
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);
|
||||
pch->thread = NULL;
|
||||
|
@ -2251,7 +2244,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
|
|||
if (pch->cyclic)
|
||||
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_put_autosuspend(pch->dmac->ddma.dev);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue