Message ID | 20211209180715.27998-1-vigneshr@ti.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Series | dma: ti: k3-udma: Workaround errata i2234 | expand |
Hi Vignesh, On 09/12/2021 20:07, Vignesh Raghavendra wrote: > Per [1], UDMA TR15 transactions may hang if ICNT0 is less than 64B > Work around is to set EOL flag is to 1 for ICNT0. > > Since, there is no performance penalty / side effects of setting EOL > flag event ICNTO > 64B, just set the flag for all UDMAP TR15 > descriptors. PDMAs and CSI does not send EOL? If you set it the EOL to one then when it arrives the remaining icnt0 is skipped... > > [1] https://www.ti.com/lit/er/sprz455a/sprz455a.pdf > Errata doc for J721E DRA829/TDA4VM Processors Silicon Revision 1.1/1.0 (Rev. A) > > Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> > --- > drivers/dma/ti/k3-udma.c | 48 +++++++++++++++++++----------------- > include/linux/dma/ti-cppi5.h | 1 + > 2 files changed, 27 insertions(+), 22 deletions(-) > > diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c > index 6e56d1cef5ee..d65c4cc5fbf7 100644 > --- a/drivers/dma/ti/k3-udma.c > +++ b/drivers/dma/ti/k3-udma.c > @@ -2863,6 +2863,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > struct udma_desc *d; > struct cppi5_tr_type1_t *tr_req = NULL; > u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > unsigned int i; > size_t tr_size; > int num_tr = 0; > @@ -2885,10 +2886,12 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > > d->sglen = sglen; > > - if (uc->ud->match_data->type == DMA_TYPE_UDMA) > + if (uc->ud->match_data->type == DMA_TYPE_UDMA) { > asel = 0; > - else > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > + } else { > asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; > + } > > tr_req = d->hwdesc[0].tr_req_base; > for_each_sg(sgl, sgent, sglen, i) { > @@ -2906,7 +2909,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false, > false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > > sg_addr |= asel; > tr_req[tr_idx].addr = sg_addr; > @@ -2919,8 +2922,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, > false, false, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > > tr_req[tr_idx].addr = sg_addr + tr0_cnt1 * tr0_cnt0; > tr_req[tr_idx].icnt0 = tr1_cnt0; > @@ -2932,8 +2934,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > d->residue += sg_dma_len(sgent); > } > > - cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, > - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); > + cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); > > return d; > } > @@ -2947,6 +2948,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > struct scatterlist *sgent; > struct cppi5_tr_type15_t *tr_req = NULL; > enum dma_slave_buswidth dev_width; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > u16 tr_cnt0, tr_cnt1; > dma_addr_t dev_addr; > struct udma_desc *d; > @@ -3017,6 +3019,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > > if (uc->ud->match_data->type == DMA_TYPE_UDMA) { > asel = 0; > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > } else { > asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; > dev_addr |= asel; > @@ -3040,7 +3043,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false, > true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > cppi5_tr_set_trigger(&tr_req[tr_idx].flags, > uc->config.tr_trigger_type, > CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 0, 0); > @@ -3086,8 +3089,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, > false, true, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > cppi5_tr_set_trigger(&tr_req[tr_idx].flags, > uc->config.tr_trigger_type, > CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, > @@ -3131,8 +3133,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > d->residue += sg_len; > } > > - cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, > - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); > + cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); > > return d; > } > @@ -3454,6 +3455,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > struct cppi5_tr_type1_t *tr_req; > unsigned int periods = buf_len / period_len; > u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > unsigned int i; > int num_tr; > > @@ -3472,11 +3474,13 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > return NULL; > > tr_req = d->hwdesc[0].tr_req_base; > - if (uc->ud->match_data->type == DMA_TYPE_UDMA) > + if (uc->ud->match_data->type == DMA_TYPE_UDMA) { > period_addr = buf_addr; > - else > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > + } else { > period_addr = buf_addr | > ((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT); > + } > > for (i = 0; i < periods; i++) { > int tr_idx = i * num_tr; > @@ -3490,8 +3494,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > tr_req[tr_idx].dim1 = tr0_cnt0; > > if (num_tr == 2) { > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > tr_idx++; > > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, > @@ -3505,8 +3508,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > } > > if (!(flags & DMA_PREP_INTERRUPT)) > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > > period_addr += period_len; > } > @@ -3659,6 +3661,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > int num_tr; > size_t tr_size = sizeof(struct cppi5_tr_type15_t); > u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > > if (uc->config.dir != DMA_MEM_TO_MEM) { > dev_err(chan->device->dev, > @@ -3689,13 +3692,15 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > if (uc->ud->match_data->type != DMA_TYPE_UDMA) { > src |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; > dest |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; > + } else { > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > } > > tr_req = d->hwdesc[0].tr_req_base; > > cppi5_tr_init(&tr_req[0].flags, CPPI5_TR_TYPE15, false, true, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[0].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[0].flags, csf); > > tr_req[0].addr = src; > tr_req[0].icnt0 = tr0_cnt0; > @@ -3714,7 +3719,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > if (num_tr == 2) { > cppi5_tr_init(&tr_req[1].flags, CPPI5_TR_TYPE15, false, true, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[1].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[1].flags, csf); > > tr_req[1].addr = src + tr0_cnt1 * tr0_cnt0; > tr_req[1].icnt0 = tr1_cnt0; > @@ -3729,8 +3734,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > tr_req[1].dicnt3 = 1; > } > > - cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, > - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); > + cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, csf | CPPI5_TR_CSF_EOP); > > if (uc->config.metadata_size) > d->vd.tx.metadata_ops = &metadata_ops; > diff --git a/include/linux/dma/ti-cppi5.h b/include/linux/dma/ti-cppi5.h > index efa2f0309f00..c53c0f6e3b1a 100644 > --- a/include/linux/dma/ti-cppi5.h > +++ b/include/linux/dma/ti-cppi5.h > @@ -616,6 +616,7 @@ static inline void *cppi5_hdesc_get_swdata(struct cppi5_host_desc_t *desc) > #define CPPI5_TR_CSF_SUPR_EVT BIT(2) > #define CPPI5_TR_CSF_EOL_ADV_SHIFT (4U) > #define CPPI5_TR_CSF_EOL_ADV_MASK GENMASK(6, 4) > +#define CPPI5_TR_CSF_EOL_ICNT0 BIT(4) the correct expression is: (1 << CPPI5_TR_CSF_EOL_ADV_SHIFT) as EOL = 1 is what you want to set. EOL = 2 will clear icnt0 and 1 on EOL. 3 will do the same for icnt 0, 1 and 2 4 will skip the remainin tr. > #define CPPI5_TR_CSF_EOP BIT(7) > > /** >
On 09-12-21, 23:37, Vignesh Raghavendra wrote: > Per [1], UDMA TR15 transactions may hang if ICNT0 is less than 64B > Work around is to set EOL flag is to 1 for ICNT0. > > Since, there is no performance penalty / side effects of setting EOL > flag event ICNTO > 64B, just set the flag for all UDMAP TR15 > descriptors. s/dma/dmaengine > > [1] https://www.ti.com/lit/er/sprz455a/sprz455a.pdf > Errata doc for J721E DRA829/TDA4VM Processors Silicon Revision 1.1/1.0 (Rev. A) > > Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> > --- > drivers/dma/ti/k3-udma.c | 48 +++++++++++++++++++----------------- > include/linux/dma/ti-cppi5.h | 1 + > 2 files changed, 27 insertions(+), 22 deletions(-) > > diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c > index 6e56d1cef5ee..d65c4cc5fbf7 100644 > --- a/drivers/dma/ti/k3-udma.c > +++ b/drivers/dma/ti/k3-udma.c > @@ -2863,6 +2863,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > struct udma_desc *d; > struct cppi5_tr_type1_t *tr_req = NULL; > u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > unsigned int i; > size_t tr_size; > int num_tr = 0; > @@ -2885,10 +2886,12 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > > d->sglen = sglen; > > - if (uc->ud->match_data->type == DMA_TYPE_UDMA) > + if (uc->ud->match_data->type == DMA_TYPE_UDMA) { > asel = 0; > - else > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > + } else { > asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; > + } > > tr_req = d->hwdesc[0].tr_req_base; > for_each_sg(sgl, sgent, sglen, i) { > @@ -2906,7 +2909,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false, > false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > > sg_addr |= asel; > tr_req[tr_idx].addr = sg_addr; > @@ -2919,8 +2922,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, > false, false, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > > tr_req[tr_idx].addr = sg_addr + tr0_cnt1 * tr0_cnt0; > tr_req[tr_idx].icnt0 = tr1_cnt0; > @@ -2932,8 +2934,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, > d->residue += sg_dma_len(sgent); > } > > - cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, > - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); > + cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); > > return d; > } > @@ -2947,6 +2948,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > struct scatterlist *sgent; > struct cppi5_tr_type15_t *tr_req = NULL; > enum dma_slave_buswidth dev_width; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > u16 tr_cnt0, tr_cnt1; > dma_addr_t dev_addr; > struct udma_desc *d; > @@ -3017,6 +3019,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > > if (uc->ud->match_data->type == DMA_TYPE_UDMA) { > asel = 0; > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > } else { > asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; > dev_addr |= asel; > @@ -3040,7 +3043,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false, > true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > cppi5_tr_set_trigger(&tr_req[tr_idx].flags, > uc->config.tr_trigger_type, > CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 0, 0); > @@ -3086,8 +3089,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, > false, true, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > cppi5_tr_set_trigger(&tr_req[tr_idx].flags, > uc->config.tr_trigger_type, > CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, > @@ -3131,8 +3133,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, > d->residue += sg_len; > } > > - cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, > - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); > + cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); > > return d; > } > @@ -3454,6 +3455,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > struct cppi5_tr_type1_t *tr_req; > unsigned int periods = buf_len / period_len; > u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > unsigned int i; > int num_tr; > > @@ -3472,11 +3474,13 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > return NULL; > > tr_req = d->hwdesc[0].tr_req_base; > - if (uc->ud->match_data->type == DMA_TYPE_UDMA) > + if (uc->ud->match_data->type == DMA_TYPE_UDMA) { > period_addr = buf_addr; > - else > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > + } else { > period_addr = buf_addr | > ((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT); > + } > > for (i = 0; i < periods; i++) { > int tr_idx = i * num_tr; > @@ -3490,8 +3494,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > tr_req[tr_idx].dim1 = tr0_cnt0; > > if (num_tr == 2) { > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > tr_idx++; > > cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, > @@ -3505,8 +3508,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, > } > > if (!(flags & DMA_PREP_INTERRUPT)) > - cppi5_tr_csf_set(&tr_req[tr_idx].flags, > - CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); > > period_addr += period_len; > } > @@ -3659,6 +3661,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > int num_tr; > size_t tr_size = sizeof(struct cppi5_tr_type15_t); > u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; > + u32 csf = CPPI5_TR_CSF_SUPR_EVT; > > if (uc->config.dir != DMA_MEM_TO_MEM) { > dev_err(chan->device->dev, > @@ -3689,13 +3692,15 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > if (uc->ud->match_data->type != DMA_TYPE_UDMA) { > src |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; > dest |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; > + } else { > + csf |= CPPI5_TR_CSF_EOL_ICNT0; > } > > tr_req = d->hwdesc[0].tr_req_base; > > cppi5_tr_init(&tr_req[0].flags, CPPI5_TR_TYPE15, false, true, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[0].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[0].flags, csf); > > tr_req[0].addr = src; > tr_req[0].icnt0 = tr0_cnt0; > @@ -3714,7 +3719,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > if (num_tr == 2) { > cppi5_tr_init(&tr_req[1].flags, CPPI5_TR_TYPE15, false, true, > CPPI5_TR_EVENT_SIZE_COMPLETION, 0); > - cppi5_tr_csf_set(&tr_req[1].flags, CPPI5_TR_CSF_SUPR_EVT); > + cppi5_tr_csf_set(&tr_req[1].flags, csf); > > tr_req[1].addr = src + tr0_cnt1 * tr0_cnt0; > tr_req[1].icnt0 = tr1_cnt0; > @@ -3729,8 +3734,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, > tr_req[1].dicnt3 = 1; > } > > - cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, > - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); > + cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, csf | CPPI5_TR_CSF_EOP); > > if (uc->config.metadata_size) > d->vd.tx.metadata_ops = &metadata_ops; > diff --git a/include/linux/dma/ti-cppi5.h b/include/linux/dma/ti-cppi5.h > index efa2f0309f00..c53c0f6e3b1a 100644 > --- a/include/linux/dma/ti-cppi5.h > +++ b/include/linux/dma/ti-cppi5.h > @@ -616,6 +616,7 @@ static inline void *cppi5_hdesc_get_swdata(struct cppi5_host_desc_t *desc) > #define CPPI5_TR_CSF_SUPR_EVT BIT(2) > #define CPPI5_TR_CSF_EOL_ADV_SHIFT (4U) > #define CPPI5_TR_CSF_EOL_ADV_MASK GENMASK(6, 4) > +#define CPPI5_TR_CSF_EOL_ICNT0 BIT(4) > #define CPPI5_TR_CSF_EOP BIT(7) > > /** > -- > 2.34.1
Hello Peter, On 10/12/21 20:52, Péter Ujfalusi wrote: > Hi Vignesh, > > On 09/12/2021 20:07, Vignesh Raghavendra wrote: >> Per [1], UDMA TR15 transactions may hang if ICNT0 is less than 64B >> Work around is to set EOL flag is to 1 for ICNT0. >> >> Since, there is no performance penalty / side effects of setting EOL >> flag event ICNTO > 64B, just set the flag for all UDMAP TR15 >> descriptors. > > PDMAs and CSI does not send EOL? If you set it the EOL to one then when > it arrives the remaining icnt0 is skipped... I am planning to respin v2 for this. Will fix this in v2. > >> >> [1] https://www.ti.com/lit/er/sprz455a/sprz455a.pdf >> Errata doc for J721E DRA829/TDA4VM Processors Silicon Revision 1.1/1.0 (Rev. A) >> >> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> >> --- >> drivers/dma/ti/k3-udma.c | 48 +++++++++++++++++++----------------- >> include/linux/dma/ti-cppi5.h | 1 + >> 2 files changed, 27 insertions(+), 22 deletions(-) >> [...] >> diff --git a/include/linux/dma/ti-cppi5.h b/include/linux/dma/ti-cppi5.h >> index efa2f0309f00..c53c0f6e3b1a 100644 >> --- a/include/linux/dma/ti-cppi5.h >> +++ b/include/linux/dma/ti-cppi5.h >> @@ -616,6 +616,7 @@ static inline void *cppi5_hdesc_get_swdata(struct cppi5_host_desc_t *desc) >> #define CPPI5_TR_CSF_SUPR_EVT BIT(2) >> #define CPPI5_TR_CSF_EOL_ADV_SHIFT (4U) >> #define CPPI5_TR_CSF_EOL_ADV_MASK GENMASK(6, 4) >> +#define CPPI5_TR_CSF_EOL_ICNT0 BIT(4) > > the correct expression is: (1 << CPPI5_TR_CSF_EOL_ADV_SHIFT) Both these expressions expands to the same value (CPPI5_TR_CSF_EOL_ADV_SHIFT = 4U) And according to the linux checkpatch, the usage of BIT macro is preferred so I will keep it the same. Warm regards, -Jayesh > as EOL = 1 is what you want to set. > EOL = 2 will clear icnt0 and 1 on EOL. > 3 will do the same for icnt 0, 1 and 2 > 4 will skip the remainin tr. > >> #define CPPI5_TR_CSF_EOP BIT(7) >> >> /** >> >
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 6e56d1cef5ee..d65c4cc5fbf7 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -2863,6 +2863,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, struct udma_desc *d; struct cppi5_tr_type1_t *tr_req = NULL; u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; + u32 csf = CPPI5_TR_CSF_SUPR_EVT; unsigned int i; size_t tr_size; int num_tr = 0; @@ -2885,10 +2886,12 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, d->sglen = sglen; - if (uc->ud->match_data->type == DMA_TYPE_UDMA) + if (uc->ud->match_data->type == DMA_TYPE_UDMA) { asel = 0; - else + csf |= CPPI5_TR_CSF_EOL_ICNT0; + } else { asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; + } tr_req = d->hwdesc[0].tr_req_base; for_each_sg(sgl, sgent, sglen, i) { @@ -2906,7 +2909,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false, false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); sg_addr |= asel; tr_req[tr_idx].addr = sg_addr; @@ -2919,8 +2922,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false, false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[tr_idx].flags, - CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); tr_req[tr_idx].addr = sg_addr + tr0_cnt1 * tr0_cnt0; tr_req[tr_idx].icnt0 = tr1_cnt0; @@ -2932,8 +2934,7 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, d->residue += sg_dma_len(sgent); } - cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); + cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); return d; } @@ -2947,6 +2948,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, struct scatterlist *sgent; struct cppi5_tr_type15_t *tr_req = NULL; enum dma_slave_buswidth dev_width; + u32 csf = CPPI5_TR_CSF_SUPR_EVT; u16 tr_cnt0, tr_cnt1; dma_addr_t dev_addr; struct udma_desc *d; @@ -3017,6 +3019,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, if (uc->ud->match_data->type == DMA_TYPE_UDMA) { asel = 0; + csf |= CPPI5_TR_CSF_EOL_ICNT0; } else { asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; dev_addr |= asel; @@ -3040,7 +3043,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); cppi5_tr_set_trigger(&tr_req[tr_idx].flags, uc->config.tr_trigger_type, CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 0, 0); @@ -3086,8 +3089,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[tr_idx].flags, - CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); cppi5_tr_set_trigger(&tr_req[tr_idx].flags, uc->config.tr_trigger_type, CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, @@ -3131,8 +3133,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, d->residue += sg_len; } - cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); + cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); return d; } @@ -3454,6 +3455,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, struct cppi5_tr_type1_t *tr_req; unsigned int periods = buf_len / period_len; u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; + u32 csf = CPPI5_TR_CSF_SUPR_EVT; unsigned int i; int num_tr; @@ -3472,11 +3474,13 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, return NULL; tr_req = d->hwdesc[0].tr_req_base; - if (uc->ud->match_data->type == DMA_TYPE_UDMA) + if (uc->ud->match_data->type == DMA_TYPE_UDMA) { period_addr = buf_addr; - else + csf |= CPPI5_TR_CSF_EOL_ICNT0; + } else { period_addr = buf_addr | ((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT); + } for (i = 0; i < periods; i++) { int tr_idx = i * num_tr; @@ -3490,8 +3494,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, tr_req[tr_idx].dim1 = tr0_cnt0; if (num_tr == 2) { - cppi5_tr_csf_set(&tr_req[tr_idx].flags, - CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); tr_idx++; cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, @@ -3505,8 +3508,7 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, } if (!(flags & DMA_PREP_INTERRUPT)) - cppi5_tr_csf_set(&tr_req[tr_idx].flags, - CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); period_addr += period_len; } @@ -3659,6 +3661,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, int num_tr; size_t tr_size = sizeof(struct cppi5_tr_type15_t); u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; + u32 csf = CPPI5_TR_CSF_SUPR_EVT; if (uc->config.dir != DMA_MEM_TO_MEM) { dev_err(chan->device->dev, @@ -3689,13 +3692,15 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, if (uc->ud->match_data->type != DMA_TYPE_UDMA) { src |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; dest |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; + } else { + csf |= CPPI5_TR_CSF_EOL_ICNT0; } tr_req = d->hwdesc[0].tr_req_base; cppi5_tr_init(&tr_req[0].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[0].flags, CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[0].flags, csf); tr_req[0].addr = src; tr_req[0].icnt0 = tr0_cnt0; @@ -3714,7 +3719,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, if (num_tr == 2) { cppi5_tr_init(&tr_req[1].flags, CPPI5_TR_TYPE15, false, true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); - cppi5_tr_csf_set(&tr_req[1].flags, CPPI5_TR_CSF_SUPR_EVT); + cppi5_tr_csf_set(&tr_req[1].flags, csf); tr_req[1].addr = src + tr0_cnt1 * tr0_cnt0; tr_req[1].icnt0 = tr1_cnt0; @@ -3729,8 +3734,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, tr_req[1].dicnt3 = 1; } - cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, - CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); + cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, csf | CPPI5_TR_CSF_EOP); if (uc->config.metadata_size) d->vd.tx.metadata_ops = &metadata_ops; diff --git a/include/linux/dma/ti-cppi5.h b/include/linux/dma/ti-cppi5.h index efa2f0309f00..c53c0f6e3b1a 100644 --- a/include/linux/dma/ti-cppi5.h +++ b/include/linux/dma/ti-cppi5.h @@ -616,6 +616,7 @@ static inline void *cppi5_hdesc_get_swdata(struct cppi5_host_desc_t *desc) #define CPPI5_TR_CSF_SUPR_EVT BIT(2) #define CPPI5_TR_CSF_EOL_ADV_SHIFT (4U) #define CPPI5_TR_CSF_EOL_ADV_MASK GENMASK(6, 4) +#define CPPI5_TR_CSF_EOL_ICNT0 BIT(4) #define CPPI5_TR_CSF_EOP BIT(7) /**
Per [1], UDMA TR15 transactions may hang if ICNT0 is less than 64B Work around is to set EOL flag is to 1 for ICNT0. Since, there is no performance penalty / side effects of setting EOL flag event ICNTO > 64B, just set the flag for all UDMAP TR15 descriptors. [1] https://www.ti.com/lit/er/sprz455a/sprz455a.pdf Errata doc for J721E DRA829/TDA4VM Processors Silicon Revision 1.1/1.0 (Rev. A) Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> --- drivers/dma/ti/k3-udma.c | 48 +++++++++++++++++++----------------- include/linux/dma/ti-cppi5.h | 1 + 2 files changed, 27 insertions(+), 22 deletions(-)