mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
dmaengine: pl330: _loop_cyclic: fixup loopcnt is too large
This patch fixup dma transfer data lost if loop cnt is larger than 256. Change-Id: Id49302cdcc1ac871d03070ce07eaa7653e54408c Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
@@ -1341,19 +1341,14 @@ static inline int _loop(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[],
|
||||
return off;
|
||||
}
|
||||
|
||||
/* Returns bytes consumed */
|
||||
static inline int _loop_cyclic(struct pl330_dmac *pl330, unsigned dry_run,
|
||||
u8 buf[], unsigned long bursts, const struct _xfer_spec *pxs, int ev)
|
||||
static int _period(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[],
|
||||
unsigned long bursts, const struct _xfer_spec *pxs, int ev)
|
||||
{
|
||||
int cyc, off;
|
||||
unsigned lcnt0, lcnt1, ljmp0, ljmp1, ljmpfe;
|
||||
unsigned int lcnt1, ljmp1;
|
||||
int cyc, off = 0;
|
||||
struct _arg_LPEND lpend;
|
||||
struct pl330_xfer *x = &pxs->desc->px;
|
||||
|
||||
off = 0;
|
||||
ljmpfe = off;
|
||||
lcnt0 = pxs->desc->num_periods;
|
||||
|
||||
if (bursts > 256) {
|
||||
lcnt1 = 256;
|
||||
cyc = bursts / 256;
|
||||
@@ -1362,18 +1357,6 @@ static inline int _loop_cyclic(struct pl330_dmac *pl330, unsigned dry_run,
|
||||
cyc = 1;
|
||||
}
|
||||
|
||||
/* forever loop */
|
||||
off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr);
|
||||
off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
|
||||
off += _emit_FLUSHP(dry_run, &buf[off],
|
||||
pxs->desc->peri);
|
||||
#endif
|
||||
/* loop0 */
|
||||
off += _emit_LP(dry_run, &buf[off], 0, lcnt0);
|
||||
ljmp0 = off;
|
||||
|
||||
/* loop1 */
|
||||
off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
|
||||
ljmp1 = off;
|
||||
@@ -1424,12 +1407,54 @@ static inline int _loop_cyclic(struct pl330_dmac *pl330, unsigned dry_run,
|
||||
|
||||
off += _emit_SEV(dry_run, &buf[off], ev);
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/* Returns bytes consumed */
|
||||
static inline int _loop_cyclic(struct pl330_dmac *pl330, unsigned int dry_run,
|
||||
u8 buf[], unsigned long bursts, const struct _xfer_spec *pxs, int ev)
|
||||
{
|
||||
int off, periods, residue, i;
|
||||
unsigned int lcnt0, ljmp0, ljmpfe;
|
||||
struct _arg_LPEND lpend;
|
||||
struct pl330_xfer *x = &pxs->desc->px;
|
||||
|
||||
off = 0;
|
||||
ljmpfe = off;
|
||||
lcnt0 = pxs->desc->num_periods;
|
||||
periods = 1;
|
||||
|
||||
while (lcnt0 > 256) {
|
||||
periods++;
|
||||
lcnt0 = pxs->desc->num_periods / periods;
|
||||
}
|
||||
|
||||
residue = pxs->desc->num_periods % periods;
|
||||
|
||||
/* forever loop */
|
||||
off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr);
|
||||
off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
|
||||
#ifdef CONFIG_ARCH_ROCKCHIP
|
||||
if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
|
||||
off += _emit_FLUSHP(dry_run, &buf[off],
|
||||
pxs->desc->peri);
|
||||
#endif
|
||||
/* loop0 */
|
||||
off += _emit_LP(dry_run, &buf[off], 0, lcnt0);
|
||||
ljmp0 = off;
|
||||
|
||||
for (i = 0; i < periods; i++)
|
||||
off += _period(pl330, dry_run, &buf[off], bursts, pxs, ev);
|
||||
|
||||
lpend.cond = ALWAYS;
|
||||
lpend.forever = false;
|
||||
lpend.loop = 0;
|
||||
lpend.bjump = off - ljmp0;
|
||||
off += _emit_LPEND(dry_run, &buf[off], &lpend);
|
||||
|
||||
for (i = 0; i < residue; i++)
|
||||
off += _period(pl330, dry_run, &buf[off], bursts, pxs, ev);
|
||||
|
||||
lpend.cond = ALWAYS;
|
||||
lpend.forever = true;
|
||||
lpend.loop = 1;
|
||||
|
||||
Reference in New Issue
Block a user