Commit 1c83767c authored by Vignesh Raghavendra's avatar Vignesh Raghavendra Committed by Vinod Koul

dmaengine: ti: k3-udma: Use ktime/usleep_range based TX completion check

In some cases (McSPI for example) the jiffie and delayed_work based
workaround can cause big throughput drop.

Switch to use ktime/usleep_range based implementation to be able
to sustain speed for PDMA based peripherals.
Signed-off-by: default avatarVignesh Raghavendra <vigneshr@ti.com>
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Link: https://lore.kernel.org/r/20200214091441.27535-2-peter.ujfalusi@ti.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 2227ab42
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmapool.h> #include <linux/dmapool.h>
...@@ -169,7 +170,7 @@ enum udma_chan_state { ...@@ -169,7 +170,7 @@ enum udma_chan_state {
struct udma_tx_drain { struct udma_tx_drain {
struct delayed_work work; struct delayed_work work;
unsigned long jiffie; ktime_t tstamp;
u32 residue; u32 residue;
}; };
...@@ -946,9 +947,10 @@ static bool udma_is_desc_really_done(struct udma_chan *uc, struct udma_desc *d) ...@@ -946,9 +947,10 @@ static bool udma_is_desc_really_done(struct udma_chan *uc, struct udma_desc *d)
peer_bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_PEER_BCNT_REG); peer_bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_PEER_BCNT_REG);
bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_BCNT_REG); bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_BCNT_REG);
/* Transfer is incomplete, store current residue and time stamp */
if (peer_bcnt < bcnt) { if (peer_bcnt < bcnt) {
uc->tx_drain.residue = bcnt - peer_bcnt; uc->tx_drain.residue = bcnt - peer_bcnt;
uc->tx_drain.jiffie = jiffies; uc->tx_drain.tstamp = ktime_get();
return false; return false;
} }
...@@ -961,35 +963,59 @@ static void udma_check_tx_completion(struct work_struct *work) ...@@ -961,35 +963,59 @@ static void udma_check_tx_completion(struct work_struct *work)
tx_drain.work.work); tx_drain.work.work);
bool desc_done = true; bool desc_done = true;
u32 residue_diff; u32 residue_diff;
unsigned long jiffie_diff, delay; ktime_t time_diff;
unsigned long delay;
while (1) {
if (uc->desc) {
/* Get previous residue and time stamp */
residue_diff = uc->tx_drain.residue;
time_diff = uc->tx_drain.tstamp;
/*
* Get current residue and time stamp or see if
* transfer is complete
*/
desc_done = udma_is_desc_really_done(uc, uc->desc);
}
if (uc->desc) { if (!desc_done) {
residue_diff = uc->tx_drain.residue; /*
jiffie_diff = uc->tx_drain.jiffie; * Find the time delta and residue delta w.r.t
desc_done = udma_is_desc_really_done(uc, uc->desc); * previous poll
} */
time_diff = ktime_sub(uc->tx_drain.tstamp,
if (!desc_done) { time_diff) + 1;
jiffie_diff = uc->tx_drain.jiffie - jiffie_diff; residue_diff -= uc->tx_drain.residue;
residue_diff -= uc->tx_drain.residue; if (residue_diff) {
if (residue_diff) { /*
/* Try to guess when we should check next time */ * Try to guess when we should check
residue_diff /= jiffie_diff; * next time by calculating rate at
delay = uc->tx_drain.residue / residue_diff / 3; * which data is being drained at the
if (jiffies_to_msecs(delay) < 5) * peer device
delay = 0; */
} else { delay = (time_diff / residue_diff) *
/* No progress, check again in 1 second */ uc->tx_drain.residue;
delay = HZ; } else {
/* No progress, check again in 1 second */
schedule_delayed_work(&uc->tx_drain.work, HZ);
break;
}
usleep_range(ktime_to_us(delay),
ktime_to_us(delay) + 10);
continue;
} }
schedule_delayed_work(&uc->tx_drain.work, delay); if (uc->desc) {
} else if (uc->desc) { struct udma_desc *d = uc->desc;
struct udma_desc *d = uc->desc;
uc->bcnt += d->residue;
udma_start(uc);
vchan_cookie_complete(&d->vd);
break;
}
uc->bcnt += d->residue; break;
udma_start(uc);
vchan_cookie_complete(&d->vd);
} }
} }
......
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