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

dmaengine: Extend NXP QDMA driver to check transmission errors

Extend NXP QDMA driver to check transmission errors

The NXP QDMA driver (fsl-qdma.c) does not check the status bits
that indicate if a DMA transfer has been completed successfully.
This patch extends the driver to do exactly this.

Signed-off-by: Mathias Koehrer <mathias.koehrer@etas.com>
Link: https://lore.kernel.org/r/744443c0462aac2df4754f99500a911527c0b235.camel@bosch.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Koehrer Mathias (ETAS/EES-SL) and committed by
Vinod Koul
ab6041e4 c3846c4c

+57 -6
+57 -6
drivers/dma/fsl-qdma.c
··· 56 56 57 57 /* Registers for bit and genmask */ 58 58 #define FSL_QDMA_CQIDR_SQT BIT(15) 59 - #define QDMA_CCDF_FOTMAT BIT(29) 59 + #define QDMA_CCDF_FORMAT BIT(29) 60 60 #define QDMA_CCDF_SER BIT(30) 61 61 #define QDMA_SG_FIN BIT(30) 62 62 #define QDMA_SG_LEN_MASK GENMASK(29, 0) ··· 110 110 #define FSL_QDMA_CMD_DSEN_OFFSET 19 111 111 #define FSL_QDMA_CMD_LWC_OFFSET 16 112 112 113 + /* Field definition for Descriptor status */ 114 + #define QDMA_CCDF_STATUS_RTE BIT(5) 115 + #define QDMA_CCDF_STATUS_WTE BIT(4) 116 + #define QDMA_CCDF_STATUS_CDE BIT(2) 117 + #define QDMA_CCDF_STATUS_SDE BIT(1) 118 + #define QDMA_CCDF_STATUS_DDE BIT(0) 119 + #define QDMA_CCDF_STATUS_MASK (QDMA_CCDF_STATUS_RTE | \ 120 + QDMA_CCDF_STATUS_WTE | \ 121 + QDMA_CCDF_STATUS_CDE | \ 122 + QDMA_CCDF_STATUS_SDE | \ 123 + QDMA_CCDF_STATUS_DDE) 124 + 113 125 /* Field definition for Descriptor offset */ 114 - #define QDMA_CCDF_STATUS 20 115 126 #define QDMA_CCDF_OFFSET 20 116 127 #define QDMA_SDDF_CMD(x) (((u64)(x)) << 32) 117 128 ··· 254 243 static inline void 255 244 qdma_ccdf_set_format(struct fsl_qdma_format *ccdf, int offset) 256 245 { 257 - ccdf->cfg = cpu_to_le32(QDMA_CCDF_FOTMAT | offset); 246 + ccdf->cfg = cpu_to_le32(QDMA_CCDF_FORMAT | 247 + (offset << QDMA_CCDF_OFFSET)); 258 248 } 259 249 260 250 static inline int 261 251 qdma_ccdf_get_status(const struct fsl_qdma_format *ccdf) 262 252 { 263 - return (le32_to_cpu(ccdf->status) & QDMA_CCDF_MASK) >> QDMA_CCDF_STATUS; 253 + return (le32_to_cpu(ccdf->status) & QDMA_CCDF_STATUS_MASK); 264 254 } 265 255 266 256 static inline void ··· 630 618 { 631 619 bool duplicate; 632 620 u32 reg, i, count; 621 + u8 completion_status; 633 622 struct fsl_qdma_queue *temp_queue; 634 623 struct fsl_qdma_format *status_addr; 635 624 struct fsl_qdma_comp *fsl_comp = NULL; ··· 690 677 } 691 678 list_del(&fsl_comp->list); 692 679 680 + completion_status = qdma_ccdf_get_status(status_addr); 681 + 693 682 reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR); 694 683 reg |= FSL_QDMA_BSQMR_DI; 695 684 qdma_desc_addr_set64(status_addr, 0x0); ··· 700 685 fsl_status->virt_head = fsl_status->cq; 701 686 qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); 702 687 spin_unlock(&temp_queue->queue_lock); 688 + 689 + /* The completion_status is evaluated here 690 + * (outside of spin lock) 691 + */ 692 + if (completion_status) { 693 + /* A completion error occurred! */ 694 + if (completion_status & QDMA_CCDF_STATUS_WTE) { 695 + /* Write transaction error */ 696 + fsl_comp->vdesc.tx_result.result = 697 + DMA_TRANS_WRITE_FAILED; 698 + } else if (completion_status & QDMA_CCDF_STATUS_RTE) { 699 + /* Read transaction error */ 700 + fsl_comp->vdesc.tx_result.result = 701 + DMA_TRANS_READ_FAILED; 702 + } else { 703 + /* Command/source/destination 704 + * description error 705 + */ 706 + fsl_comp->vdesc.tx_result.result = 707 + DMA_TRANS_ABORTED; 708 + dev_err(fsl_qdma->dma_dev.dev, 709 + "DMA status descriptor error %x\n", 710 + completion_status); 711 + } 712 + } 703 713 704 714 spin_lock(&fsl_comp->qchan->vchan.lock); 705 715 vchan_cookie_complete(&fsl_comp->vdesc); ··· 740 700 unsigned int intr; 741 701 struct fsl_qdma_engine *fsl_qdma = dev_id; 742 702 void __iomem *status = fsl_qdma->status_base; 703 + unsigned int decfdw0r; 704 + unsigned int decfdw1r; 705 + unsigned int decfdw2r; 706 + unsigned int decfdw3r; 743 707 744 708 intr = qdma_readl(fsl_qdma, status + FSL_QDMA_DEDR); 745 709 746 - if (intr) 747 - dev_err(fsl_qdma->dma_dev.dev, "DMA transaction error!\n"); 710 + if (intr) { 711 + decfdw0r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW0R); 712 + decfdw1r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW1R); 713 + decfdw2r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW2R); 714 + decfdw3r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW3R); 715 + dev_err(fsl_qdma->dma_dev.dev, 716 + "DMA transaction error! (%x: %x-%x-%x-%x)\n", 717 + intr, decfdw0r, decfdw1r, decfdw2r, decfdw3r); 718 + } 748 719 749 720 qdma_writel(fsl_qdma, FSL_QDMA_DEDR_CLEAR, status + FSL_QDMA_DEDR); 750 721 return IRQ_HANDLED;