Skip to content

Commit d35f406

Browse files
jailuthravinodkoul
authored andcommitted
dmaengine: ti: k3-udma: Set EOP for all TRs in cyclic BCDMA transfer
When receiving data in cyclic mode from PDMA peripherals, where reload count is set to infinite, any TR in the set can potentially be the last one of the overall transfer. In such cases, the EOP flag needs to be set in each TR and PDMA's Static TR "Z" parameter should be set, matching the size of the TR. This is required for the teardown to function properly and cleanup the internal state memory. This only affects platforms using BCDMA and not those using UDMA-P, which could set EOP flag in the teardown TR automatically. Similarly when transmitting data in cyclic mode to PDMA peripherals, the EOP flag needs to be set to get the teardown completion signal correctly. Fixes: 0177947 ("dmaengine: ti: k3-udma: Initial support for K3 BCDMA") Tested-by: Francesco Dolcini <francesco.dolcini@toradex.com> # Toradex Verdin AM62 Signed-off-by: Jai Luthra <j-luthra@ti.com> Signed-off-by: Jai Luthra <jai.luthra@linux.dev> Acked-by: Peter Ujfalusi <peter.ujfalusi@gmail.com> Link: https://lore.kernel.org/r/20240930-z_cnt-v2-1-9d38aba149a2@linux.dev Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 6e9c5c8 commit d35f406

File tree

1 file changed

+47
-15
lines changed

1 file changed

+47
-15
lines changed

drivers/dma/ti/k3-udma.c

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3185,27 +3185,40 @@ static int udma_configure_statictr(struct udma_chan *uc, struct udma_desc *d,
31853185

31863186
d->static_tr.elcnt = elcnt;
31873187

3188-
/*
3189-
* PDMA must to close the packet when the channel is in packet mode.
3190-
* For TR mode when the channel is not cyclic we also need PDMA to close
3191-
* the packet otherwise the transfer will stall because PDMA holds on
3192-
* the data it has received from the peripheral.
3193-
*/
31943188
if (uc->config.pkt_mode || !uc->cyclic) {
3189+
/*
3190+
* PDMA must close the packet when the channel is in packet mode.
3191+
* For TR mode when the channel is not cyclic we also need PDMA
3192+
* to close the packet otherwise the transfer will stall because
3193+
* PDMA holds on the data it has received from the peripheral.
3194+
*/
31953195
unsigned int div = dev_width * elcnt;
31963196

31973197
if (uc->cyclic)
31983198
d->static_tr.bstcnt = d->residue / d->sglen / div;
31993199
else
32003200
d->static_tr.bstcnt = d->residue / div;
3201+
} else if (uc->ud->match_data->type == DMA_TYPE_BCDMA &&
3202+
uc->config.dir == DMA_DEV_TO_MEM &&
3203+
uc->cyclic) {
3204+
/*
3205+
* For cyclic mode with BCDMA we have to set EOP in each TR to
3206+
* prevent short packet errors seen on channel teardown. So the
3207+
* PDMA must close the packet after every TR transfer by setting
3208+
* burst count equal to the number of bytes transferred.
3209+
*/
3210+
struct cppi5_tr_type1_t *tr_req = d->hwdesc[0].tr_req_base;
32013211

3202-
if (uc->config.dir == DMA_DEV_TO_MEM &&
3203-
d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask)
3204-
return -EINVAL;
3212+
d->static_tr.bstcnt =
3213+
(tr_req->icnt0 * tr_req->icnt1) / dev_width;
32053214
} else {
32063215
d->static_tr.bstcnt = 0;
32073216
}
32083217

3218+
if (uc->config.dir == DMA_DEV_TO_MEM &&
3219+
d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask)
3220+
return -EINVAL;
3221+
32093222
return 0;
32103223
}
32113224

@@ -3450,8 +3463,9 @@ udma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
34503463
/* static TR for remote PDMA */
34513464
if (udma_configure_statictr(uc, d, dev_width, burst)) {
34523465
dev_err(uc->ud->dev,
3453-
"%s: StaticTR Z is limited to maximum 4095 (%u)\n",
3454-
__func__, d->static_tr.bstcnt);
3466+
"%s: StaticTR Z is limited to maximum %u (%u)\n",
3467+
__func__, uc->ud->match_data->statictr_z_mask,
3468+
d->static_tr.bstcnt);
34553469

34563470
udma_free_hwdesc(uc, d);
34573471
kfree(d);
@@ -3476,6 +3490,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
34763490
u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
34773491
unsigned int i;
34783492
int num_tr;
3493+
u32 period_csf = 0;
34793494

34803495
num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0,
34813496
&tr0_cnt1, &tr1_cnt0);
@@ -3498,6 +3513,20 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
34983513
period_addr = buf_addr |
34993514
((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT);
35003515

3516+
/*
3517+
* For BCDMA <-> PDMA transfers, the EOP flag needs to be set on the
3518+
* last TR of a descriptor, to mark the packet as complete.
3519+
* This is required for getting the teardown completion message in case
3520+
* of TX, and to avoid short-packet error in case of RX.
3521+
*
3522+
* As we are in cyclic mode, we do not know which period might be the
3523+
* last one, so set the flag for each period.
3524+
*/
3525+
if (uc->config.ep_type == PSIL_EP_PDMA_XY &&
3526+
uc->ud->match_data->type == DMA_TYPE_BCDMA) {
3527+
period_csf = CPPI5_TR_CSF_EOP;
3528+
}
3529+
35013530
for (i = 0; i < periods; i++) {
35023531
int tr_idx = i * num_tr;
35033532

@@ -3525,8 +3554,10 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
35253554
}
35263555

35273556
if (!(flags & DMA_PREP_INTERRUPT))
3528-
cppi5_tr_csf_set(&tr_req[tr_idx].flags,
3529-
CPPI5_TR_CSF_SUPR_EVT);
3557+
period_csf |= CPPI5_TR_CSF_SUPR_EVT;
3558+
3559+
if (period_csf)
3560+
cppi5_tr_csf_set(&tr_req[tr_idx].flags, period_csf);
35303561

35313562
period_addr += period_len;
35323563
}
@@ -3655,8 +3686,9 @@ udma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
36553686
/* static TR for remote PDMA */
36563687
if (udma_configure_statictr(uc, d, dev_width, burst)) {
36573688
dev_err(uc->ud->dev,
3658-
"%s: StaticTR Z is limited to maximum 4095 (%u)\n",
3659-
__func__, d->static_tr.bstcnt);
3689+
"%s: StaticTR Z is limited to maximum %u (%u)\n",
3690+
__func__, uc->ud->match_data->statictr_z_mask,
3691+
d->static_tr.bstcnt);
36603692

36613693
udma_free_hwdesc(uc, d);
36623694
kfree(d);

0 commit comments

Comments
 (0)