|
@@ -340,53 +340,56 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
|
|
|
static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
|
|
|
{
|
|
|
struct pl08x_phy_chan *ch;
|
|
|
- struct pl08x_txd *txdi = NULL;
|
|
|
struct pl08x_txd *txd;
|
|
|
unsigned long flags;
|
|
|
size_t bytes = 0;
|
|
|
|
|
|
spin_lock_irqsave(&plchan->lock, flags);
|
|
|
-
|
|
|
ch = plchan->phychan;
|
|
|
txd = plchan->at;
|
|
|
|
|
|
/*
|
|
|
- * Next follow the LLIs to get the number of pending bytes in the
|
|
|
- * currently active transaction.
|
|
|
+ * Follow the LLIs to get the number of remaining
|
|
|
+ * bytes in the currently active transaction.
|
|
|
*/
|
|
|
if (ch && txd) {
|
|
|
- struct pl08x_lli *llis_va = txd->llis_va;
|
|
|
- struct pl08x_lli *llis_bus = (struct pl08x_lli *) txd->llis_bus;
|
|
|
u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
|
|
|
|
|
|
- /* First get the bytes in the current active LLI */
|
|
|
+ /* First get the remaining bytes in the active transfer */
|
|
|
bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
|
|
|
|
|
|
if (clli) {
|
|
|
- int i = 0;
|
|
|
+ struct pl08x_lli *llis_va = txd->llis_va;
|
|
|
+ dma_addr_t llis_bus = txd->llis_bus;
|
|
|
+ int index;
|
|
|
|
|
|
- /* Forward to the LLI pointed to by clli */
|
|
|
- while ((clli != (u32) &(llis_bus[i])) &&
|
|
|
- (i < MAX_NUM_TSFR_LLIS))
|
|
|
- i++;
|
|
|
+ BUG_ON(clli < llis_bus || clli >= llis_bus +
|
|
|
+ sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Locate the next LLI - as this is an array,
|
|
|
+ * it's simple maths to find.
|
|
|
+ */
|
|
|
+ index = (clli - llis_bus) / sizeof(struct pl08x_lli);
|
|
|
+
|
|
|
+ for (; index < MAX_NUM_TSFR_LLIS; index++) {
|
|
|
+ bytes += get_bytes_in_cctl(llis_va[index].cctl);
|
|
|
|
|
|
- while (clli) {
|
|
|
- bytes += get_bytes_in_cctl(llis_va[i].cctl);
|
|
|
/*
|
|
|
* A LLI pointer of 0 terminates the LLI list
|
|
|
*/
|
|
|
- clli = llis_va[i].lli;
|
|
|
- i++;
|
|
|
+ if (!llis_va[index].lli)
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Sum up all queued transactions */
|
|
|
if (!list_empty(&plchan->desc_list)) {
|
|
|
+ struct pl08x_txd *txdi;
|
|
|
list_for_each_entry(txdi, &plchan->desc_list, node) {
|
|
|
bytes += txdi->len;
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
spin_unlock_irqrestore(&plchan->lock, flags);
|