|
@@ -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;
|