[1/1] dmaengine: fsl-dma: fix DMA error when enabling sg if 'DONE' bit is set
Commit Message
In eDMAv3, clearing 'DONE' bit (bit 30) of CHn_CSR is required when
enabling scatter-gather (SG). eDMAv4 does not require this change.
Cc: <stable@vger.kernel.org>
Fixes: 72f5801a4e2b ("dmaengine: fsl-edma: integrate v3 support")
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
drivers/dma/fsl-edma-common.c | 12 ++++++++++++
drivers/dma/fsl-edma-common.h | 14 +++++++++++++-
drivers/dma/fsl-edma-main.c | 2 +-
3 files changed, 26 insertions(+), 2 deletions(-)
Comments
Hi Frank,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.6-rc2 next-20230921]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Frank-Li/dmaengine-fsl-dma-fix-DMA-error-when-enabling-sg-if-DONE-bit-is-set/20230921-043838
base: linus/master
patch link: https://lore.kernel.org/r/20230920203741.3184727-1-Frank.Li%40nxp.com
patch subject: [PATCH 1/1] dmaengine: fsl-dma: fix DMA error when enabling sg if 'DONE' bit is set
config: i386-randconfig-062-20230921 (https://download.01.org/0day-ci/archive/20230921/202309211717.aYksVles-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230921/202309211717.aYksVles-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202309211717.aYksVles-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
drivers/dma/fsl-edma-common.c:76:15: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:93:9: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:96:17: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:98:15: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:100:9: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:125:19: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:131:17: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:134:9: sparse: sparse: cast removes address space '__iomem' of expression
>> drivers/dma/fsl-edma-common.c:463:21: sparse: sparse: restricted __le16 degrades to integer
drivers/dma/fsl-edma-common.c:465:21: sparse: sparse: restricted __le16 degrades to integer
drivers/dma/fsl-edma-common.c:466:17: sparse: sparse: cast removes address space '__iomem' of expression
drivers/dma/fsl-edma-common.c:466:17: sparse: sparse: cast removes address space '__iomem' of expression
vim +463 drivers/dma/fsl-edma-common.c
422
423 static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
424 struct fsl_edma_hw_tcd *tcd)
425 {
426 u16 csr = 0;
427
428 /*
429 * TCD parameters are stored in struct fsl_edma_hw_tcd in little
430 * endian format. However, we need to load the TCD registers in
431 * big- or little-endian obeying the eDMA engine model endian,
432 * and this is performed from specific edma_write functions
433 */
434 edma_write_tcdreg(fsl_chan, 0, csr);
435
436 edma_write_tcdreg(fsl_chan, tcd->saddr, saddr);
437 edma_write_tcdreg(fsl_chan, tcd->daddr, daddr);
438
439 edma_write_tcdreg(fsl_chan, tcd->attr, attr);
440 edma_write_tcdreg(fsl_chan, tcd->soff, soff);
441
442 edma_write_tcdreg(fsl_chan, tcd->nbytes, nbytes);
443 edma_write_tcdreg(fsl_chan, tcd->slast, slast);
444
445 edma_write_tcdreg(fsl_chan, tcd->citer, citer);
446 edma_write_tcdreg(fsl_chan, tcd->biter, biter);
447 edma_write_tcdreg(fsl_chan, tcd->doff, doff);
448
449 edma_write_tcdreg(fsl_chan, tcd->dlast_sga, dlast_sga);
450
451 if (fsl_chan->is_sw) {
452 csr = le16_to_cpu(tcd->csr);
453 csr |= EDMA_TCD_CSR_START;
454 tcd->csr = cpu_to_le16(csr);
455 }
456
457 /*
458 * Must clear CHn_CSR[DONE] bit before enable TCDn_CSR[ESG] at EDMAv3
459 * eDMAv4 have not such requirement.
460 * Change MLINK need clear CHn_CSR[DONE] for both eDMAv3 and eDMAv4.
461 */
462 if (((fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_CLEAR_DONE_E_SG) &&
> 463 (tcd->csr & EDMA_TCD_CSR_E_SG)) ||
464 ((fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_CLEAR_DONE_E_LINK) &&
465 (tcd->csr & EDMA_TCD_CSR_E_LINK)))
466 edma_writel_chreg(fsl_chan, edma_readl_chreg(fsl_chan, ch_csr), ch_csr);
467
468
469 edma_write_tcdreg(fsl_chan, tcd->csr, csr);
470 }
471
@@ -460,6 +460,18 @@ static void fsl_edma_set_tcd_regs(struct fsl_edma_chan *fsl_chan,
tcd->csr = cpu_to_le16(csr);
}
+ /*
+ * Must clear CHn_CSR[DONE] bit before enable TCDn_CSR[ESG] at EDMAv3
+ * eDMAv4 have not such requirement.
+ * Change MLINK need clear CHn_CSR[DONE] for both eDMAv3 and eDMAv4.
+ */
+ if (((fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_CLEAR_DONE_E_SG) &&
+ (tcd->csr & EDMA_TCD_CSR_E_SG)) ||
+ ((fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_CLEAR_DONE_E_LINK) &&
+ (tcd->csr & EDMA_TCD_CSR_E_LINK)))
+ edma_writel_chreg(fsl_chan, edma_readl_chreg(fsl_chan, ch_csr), ch_csr);
+
+
edma_write_tcdreg(fsl_chan, tcd->csr, csr);
}
@@ -183,11 +183,23 @@ struct fsl_edma_desc {
#define FSL_EDMA_DRV_BUS_8BYTE BIT(10)
#define FSL_EDMA_DRV_DEV_TO_DEV BIT(11)
#define FSL_EDMA_DRV_ALIGN_64BYTE BIT(12)
+/* Need clean CHn_CSR DONE before enable TCD's ESG */
+#define FSL_EDMA_DRV_CLEAR_DONE_E_SG BIT(13)
+/* Need clean CHn_CSR DONE before enable TCD's MAJORELINK */
+#define FSL_EDMA_DRV_CLEAR_DONE_E_LINK BIT(14)
#define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \
FSL_EDMA_DRV_BUS_8BYTE | \
FSL_EDMA_DRV_DEV_TO_DEV | \
- FSL_EDMA_DRV_ALIGN_64BYTE)
+ FSL_EDMA_DRV_ALIGN_64BYTE | \
+ FSL_EDMA_DRV_CLEAR_DONE_E_SG | \
+ FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
+
+#define FSL_EDMA_DRV_EDMA4 (FSL_EDMA_DRV_SPLIT_REG | \
+ FSL_EDMA_DRV_BUS_8BYTE | \
+ FSL_EDMA_DRV_DEV_TO_DEV | \
+ FSL_EDMA_DRV_ALIGN_64BYTE | \
+ FSL_EDMA_DRV_CLEAR_DONE_E_LINK)
struct fsl_edma_drvdata {
u32 dmamuxs; /* only used before v3 */
@@ -357,7 +357,7 @@ static struct fsl_edma_drvdata imx93_data3 = {
};
static struct fsl_edma_drvdata imx93_data4 = {
- .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA3,
+ .flags = FSL_EDMA_DRV_HAS_CHMUX | FSL_EDMA_DRV_HAS_DMACLK | FSL_EDMA_DRV_EDMA4,
.chreg_space_sz = 0x8000,
.chreg_off = 0x10000,
.setup_irq = fsl_edma3_irq_init,