Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 017794739702 ("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>

authored by

Jai Luthra and committed by
Vinod Koul
d35f4064 6e9c5c8e

+47 -15
+47 -15
drivers/dma/ti/k3-udma.c
··· 3185 3186 d->static_tr.elcnt = elcnt; 3187 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 - */ 3194 if (uc->config.pkt_mode || !uc->cyclic) { 3195 unsigned int div = dev_width * elcnt; 3196 3197 if (uc->cyclic) 3198 d->static_tr.bstcnt = d->residue / d->sglen / div; 3199 else 3200 d->static_tr.bstcnt = d->residue / div; 3201 3202 - if (uc->config.dir == DMA_DEV_TO_MEM && 3203 - d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask) 3204 - return -EINVAL; 3205 } else { 3206 d->static_tr.bstcnt = 0; 3207 } 3208 3209 return 0; 3210 } ··· 3463 /* static TR for remote PDMA */ 3464 if (udma_configure_statictr(uc, d, dev_width, burst)) { 3465 dev_err(uc->ud->dev, 3466 - "%s: StaticTR Z is limited to maximum 4095 (%u)\n", 3467 - __func__, d->static_tr.bstcnt); 3468 3469 udma_free_hwdesc(uc, d); 3470 kfree(d); ··· 3490 u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; 3491 unsigned int i; 3492 int num_tr; 3493 3494 num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0, 3495 &tr0_cnt1, &tr1_cnt0); ··· 3512 else 3513 period_addr = buf_addr | 3514 ((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT); 3515 3516 for (i = 0; i < periods; i++) { 3517 int tr_idx = i * num_tr; ··· 3554 } 3555 3556 if (!(flags & DMA_PREP_INTERRUPT)) 3557 - cppi5_tr_csf_set(&tr_req[tr_idx].flags, 3558 - CPPI5_TR_CSF_SUPR_EVT); 3559 3560 period_addr += period_len; 3561 } ··· 3686 /* static TR for remote PDMA */ 3687 if (udma_configure_statictr(uc, d, dev_width, burst)) { 3688 dev_err(uc->ud->dev, 3689 - "%s: StaticTR Z is limited to maximum 4095 (%u)\n", 3690 - __func__, d->static_tr.bstcnt); 3691 3692 udma_free_hwdesc(uc, d); 3693 kfree(d);
··· 3185 3186 d->static_tr.elcnt = elcnt; 3187 3188 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 + */ 3195 unsigned int div = dev_width * elcnt; 3196 3197 if (uc->cyclic) 3198 d->static_tr.bstcnt = d->residue / d->sglen / div; 3199 else 3200 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; 3211 3212 + d->static_tr.bstcnt = 3213 + (tr_req->icnt0 * tr_req->icnt1) / dev_width; 3214 } else { 3215 d->static_tr.bstcnt = 0; 3216 } 3217 + 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 3222 return 0; 3223 } ··· 3450 /* static TR for remote PDMA */ 3451 if (udma_configure_statictr(uc, d, dev_width, burst)) { 3452 dev_err(uc->ud->dev, 3453 + "%s: StaticTR Z is limited to maximum %u (%u)\n", 3454 + __func__, uc->ud->match_data->statictr_z_mask, 3455 + d->static_tr.bstcnt); 3456 3457 udma_free_hwdesc(uc, d); 3458 kfree(d); ··· 3476 u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; 3477 unsigned int i; 3478 int num_tr; 3479 + u32 period_csf = 0; 3480 3481 num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0, 3482 &tr0_cnt1, &tr1_cnt0); ··· 3497 else 3498 period_addr = buf_addr | 3499 ((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT); 3500 + 3501 + /* 3502 + * For BCDMA <-> PDMA transfers, the EOP flag needs to be set on the 3503 + * last TR of a descriptor, to mark the packet as complete. 3504 + * This is required for getting the teardown completion message in case 3505 + * of TX, and to avoid short-packet error in case of RX. 3506 + * 3507 + * As we are in cyclic mode, we do not know which period might be the 3508 + * last one, so set the flag for each period. 3509 + */ 3510 + if (uc->config.ep_type == PSIL_EP_PDMA_XY && 3511 + uc->ud->match_data->type == DMA_TYPE_BCDMA) { 3512 + period_csf = CPPI5_TR_CSF_EOP; 3513 + } 3514 3515 for (i = 0; i < periods; i++) { 3516 int tr_idx = i * num_tr; ··· 3525 } 3526 3527 if (!(flags & DMA_PREP_INTERRUPT)) 3528 + period_csf |= CPPI5_TR_CSF_SUPR_EVT; 3529 + 3530 + if (period_csf) 3531 + cppi5_tr_csf_set(&tr_req[tr_idx].flags, period_csf); 3532 3533 period_addr += period_len; 3534 } ··· 3655 /* static TR for remote PDMA */ 3656 if (udma_configure_statictr(uc, d, dev_width, burst)) { 3657 dev_err(uc->ud->dev, 3658 + "%s: StaticTR Z is limited to maximum %u (%u)\n", 3659 + __func__, uc->ud->match_data->statictr_z_mask, 3660 + d->static_tr.bstcnt); 3661 3662 udma_free_hwdesc(uc, d); 3663 kfree(d);