CHROMIUM: DMA: PL330: Report residue for dev to mem transfers.
authorDylan Reid <dgreid@chromium.org>
Mon, 24 Sep 2012 18:36:14 +0000 (11:36 -0700)
committerGerrit <chrome-bot@google.com>
Fri, 28 Sep 2012 19:02:41 +0000 (12:02 -0700)
When setting the residue, account for device to memory transfers.  Do
this by checking both the source and destination addresses against the
active descriptors.  For memory to device the source address will be
incrementing, for device to memory the destination will increment and
for memory to memory both will increment.

BUG=chrome-os-partner:12776
TEST=enter hangout, ask if other end can hear you clearly.
'arecord -B10000 -f data /tmp/asdf.wav' then playback.

Change-Id: I4debd2e8b6ea1c2c9842e692016e83d7c852de91
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/33922
Reviewed-by: Olof Johansson <olofj@chromium.org>
drivers/dma/pl330.c

index a8e38f9..80c942b 100644 (file)
@@ -2474,31 +2474,51 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
        spin_unlock_irqrestore(&pch->lock, flags);
 }
 
+static inline int
+pl330_src_addr_in_desc(struct dma_pl330_desc *desc, unsigned int sar)
+{
+       return ((desc->px.src_addr <= sar) &&
+               (sar <= (desc->px.src_addr + desc->px.bytes)));
+}
+
+static inline int
+pl330_dst_addr_in_desc(struct dma_pl330_desc *desc, unsigned int dar)
+{
+       return ((desc->px.dst_addr <= dar) &&
+               (dar <= (desc->px.dst_addr + desc->px.bytes)));
+}
+
 static unsigned int pl330_tx_residue(struct dma_chan *chan)
 {
        struct dma_pl330_chan *pch = to_pchan(chan);
        void __iomem *regs = pch->dmac->pif.base;
        struct pl330_thread *thrd = pch->pl330_chid;
        struct dma_pl330_desc *desc;
-       unsigned int sar;
+       unsigned int sar, dar;
+       unsigned int residue = 0;
        unsigned long flags;
 
        sar = readl(regs + SA(thrd->id));
+       dar = readl(regs + DA(thrd->id));
 
        spin_lock_irqsave(&pch->lock, flags);
 
        /* Find the desc related to the current buffer. */
-       list_for_each_entry(desc, &pch->work_list, node)
-               if (desc->px.src_addr <= sar &&
-                   sar < (desc->px.src_addr + desc->px.bytes))
-                       break;
+       list_for_each_entry(desc, &pch->work_list, node) {
+               if (desc->rqcfg.src_inc && pl330_src_addr_in_desc(desc, sar)) {
+                       residue = desc->px.bytes - (sar - desc->px.src_addr);
+                       goto found_unlock;
+               }
+               if (desc->rqcfg.dst_inc && pl330_dst_addr_in_desc(desc, dar)) {
+                       residue = desc->px.bytes - (dar - desc->px.dst_addr);
+                       goto found_unlock;
+               }
+       }
 
+found_unlock:
        spin_unlock_irqrestore(&pch->lock, flags);
 
-       if (!desc)
-               return 0;
-
-       return desc->px.bytes - (sar - desc->px.src_addr);
+       return residue;
 }
 
 static enum dma_status