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>
This commit is contained in:
parent
c3846c4cce
commit
ab6041e409
|
@ -56,7 +56,7 @@
|
||||||
|
|
||||||
/* Registers for bit and genmask */
|
/* Registers for bit and genmask */
|
||||||
#define FSL_QDMA_CQIDR_SQT BIT(15)
|
#define FSL_QDMA_CQIDR_SQT BIT(15)
|
||||||
#define QDMA_CCDF_FOTMAT BIT(29)
|
#define QDMA_CCDF_FORMAT BIT(29)
|
||||||
#define QDMA_CCDF_SER BIT(30)
|
#define QDMA_CCDF_SER BIT(30)
|
||||||
#define QDMA_SG_FIN BIT(30)
|
#define QDMA_SG_FIN BIT(30)
|
||||||
#define QDMA_SG_LEN_MASK GENMASK(29, 0)
|
#define QDMA_SG_LEN_MASK GENMASK(29, 0)
|
||||||
|
@ -110,8 +110,19 @@
|
||||||
#define FSL_QDMA_CMD_DSEN_OFFSET 19
|
#define FSL_QDMA_CMD_DSEN_OFFSET 19
|
||||||
#define FSL_QDMA_CMD_LWC_OFFSET 16
|
#define FSL_QDMA_CMD_LWC_OFFSET 16
|
||||||
|
|
||||||
|
/* Field definition for Descriptor status */
|
||||||
|
#define QDMA_CCDF_STATUS_RTE BIT(5)
|
||||||
|
#define QDMA_CCDF_STATUS_WTE BIT(4)
|
||||||
|
#define QDMA_CCDF_STATUS_CDE BIT(2)
|
||||||
|
#define QDMA_CCDF_STATUS_SDE BIT(1)
|
||||||
|
#define QDMA_CCDF_STATUS_DDE BIT(0)
|
||||||
|
#define QDMA_CCDF_STATUS_MASK (QDMA_CCDF_STATUS_RTE | \
|
||||||
|
QDMA_CCDF_STATUS_WTE | \
|
||||||
|
QDMA_CCDF_STATUS_CDE | \
|
||||||
|
QDMA_CCDF_STATUS_SDE | \
|
||||||
|
QDMA_CCDF_STATUS_DDE)
|
||||||
|
|
||||||
/* Field definition for Descriptor offset */
|
/* Field definition for Descriptor offset */
|
||||||
#define QDMA_CCDF_STATUS 20
|
|
||||||
#define QDMA_CCDF_OFFSET 20
|
#define QDMA_CCDF_OFFSET 20
|
||||||
#define QDMA_SDDF_CMD(x) (((u64)(x)) << 32)
|
#define QDMA_SDDF_CMD(x) (((u64)(x)) << 32)
|
||||||
|
|
||||||
|
@ -243,13 +254,14 @@ qdma_ccdf_get_offset(const struct fsl_qdma_format *ccdf)
|
||||||
static inline void
|
static inline void
|
||||||
qdma_ccdf_set_format(struct fsl_qdma_format *ccdf, int offset)
|
qdma_ccdf_set_format(struct fsl_qdma_format *ccdf, int offset)
|
||||||
{
|
{
|
||||||
ccdf->cfg = cpu_to_le32(QDMA_CCDF_FOTMAT | offset);
|
ccdf->cfg = cpu_to_le32(QDMA_CCDF_FORMAT |
|
||||||
|
(offset << QDMA_CCDF_OFFSET));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
qdma_ccdf_get_status(const struct fsl_qdma_format *ccdf)
|
qdma_ccdf_get_status(const struct fsl_qdma_format *ccdf)
|
||||||
{
|
{
|
||||||
return (le32_to_cpu(ccdf->status) & QDMA_CCDF_MASK) >> QDMA_CCDF_STATUS;
|
return (le32_to_cpu(ccdf->status) & QDMA_CCDF_STATUS_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -618,6 +630,7 @@ fsl_qdma_queue_transfer_complete(struct fsl_qdma_engine *fsl_qdma,
|
||||||
{
|
{
|
||||||
bool duplicate;
|
bool duplicate;
|
||||||
u32 reg, i, count;
|
u32 reg, i, count;
|
||||||
|
u8 completion_status;
|
||||||
struct fsl_qdma_queue *temp_queue;
|
struct fsl_qdma_queue *temp_queue;
|
||||||
struct fsl_qdma_format *status_addr;
|
struct fsl_qdma_format *status_addr;
|
||||||
struct fsl_qdma_comp *fsl_comp = NULL;
|
struct fsl_qdma_comp *fsl_comp = NULL;
|
||||||
|
@ -677,6 +690,8 @@ fsl_qdma_queue_transfer_complete(struct fsl_qdma_engine *fsl_qdma,
|
||||||
}
|
}
|
||||||
list_del(&fsl_comp->list);
|
list_del(&fsl_comp->list);
|
||||||
|
|
||||||
|
completion_status = qdma_ccdf_get_status(status_addr);
|
||||||
|
|
||||||
reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR);
|
reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR);
|
||||||
reg |= FSL_QDMA_BSQMR_DI;
|
reg |= FSL_QDMA_BSQMR_DI;
|
||||||
qdma_desc_addr_set64(status_addr, 0x0);
|
qdma_desc_addr_set64(status_addr, 0x0);
|
||||||
|
@ -686,6 +701,31 @@ fsl_qdma_queue_transfer_complete(struct fsl_qdma_engine *fsl_qdma,
|
||||||
qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR);
|
qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR);
|
||||||
spin_unlock(&temp_queue->queue_lock);
|
spin_unlock(&temp_queue->queue_lock);
|
||||||
|
|
||||||
|
/* The completion_status is evaluated here
|
||||||
|
* (outside of spin lock)
|
||||||
|
*/
|
||||||
|
if (completion_status) {
|
||||||
|
/* A completion error occurred! */
|
||||||
|
if (completion_status & QDMA_CCDF_STATUS_WTE) {
|
||||||
|
/* Write transaction error */
|
||||||
|
fsl_comp->vdesc.tx_result.result =
|
||||||
|
DMA_TRANS_WRITE_FAILED;
|
||||||
|
} else if (completion_status & QDMA_CCDF_STATUS_RTE) {
|
||||||
|
/* Read transaction error */
|
||||||
|
fsl_comp->vdesc.tx_result.result =
|
||||||
|
DMA_TRANS_READ_FAILED;
|
||||||
|
} else {
|
||||||
|
/* Command/source/destination
|
||||||
|
* description error
|
||||||
|
*/
|
||||||
|
fsl_comp->vdesc.tx_result.result =
|
||||||
|
DMA_TRANS_ABORTED;
|
||||||
|
dev_err(fsl_qdma->dma_dev.dev,
|
||||||
|
"DMA status descriptor error %x\n",
|
||||||
|
completion_status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock(&fsl_comp->qchan->vchan.lock);
|
spin_lock(&fsl_comp->qchan->vchan.lock);
|
||||||
vchan_cookie_complete(&fsl_comp->vdesc);
|
vchan_cookie_complete(&fsl_comp->vdesc);
|
||||||
fsl_comp->qchan->status = DMA_COMPLETE;
|
fsl_comp->qchan->status = DMA_COMPLETE;
|
||||||
|
@ -700,11 +740,22 @@ static irqreturn_t fsl_qdma_error_handler(int irq, void *dev_id)
|
||||||
unsigned int intr;
|
unsigned int intr;
|
||||||
struct fsl_qdma_engine *fsl_qdma = dev_id;
|
struct fsl_qdma_engine *fsl_qdma = dev_id;
|
||||||
void __iomem *status = fsl_qdma->status_base;
|
void __iomem *status = fsl_qdma->status_base;
|
||||||
|
unsigned int decfdw0r;
|
||||||
|
unsigned int decfdw1r;
|
||||||
|
unsigned int decfdw2r;
|
||||||
|
unsigned int decfdw3r;
|
||||||
|
|
||||||
intr = qdma_readl(fsl_qdma, status + FSL_QDMA_DEDR);
|
intr = qdma_readl(fsl_qdma, status + FSL_QDMA_DEDR);
|
||||||
|
|
||||||
if (intr)
|
if (intr) {
|
||||||
dev_err(fsl_qdma->dma_dev.dev, "DMA transaction error!\n");
|
decfdw0r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW0R);
|
||||||
|
decfdw1r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW1R);
|
||||||
|
decfdw2r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW2R);
|
||||||
|
decfdw3r = qdma_readl(fsl_qdma, status + FSL_QDMA_DECFDW3R);
|
||||||
|
dev_err(fsl_qdma->dma_dev.dev,
|
||||||
|
"DMA transaction error! (%x: %x-%x-%x-%x)\n",
|
||||||
|
intr, decfdw0r, decfdw1r, decfdw2r, decfdw3r);
|
||||||
|
}
|
||||||
|
|
||||||
qdma_writel(fsl_qdma, FSL_QDMA_DEDR_CLEAR, status + FSL_QDMA_DEDR);
|
qdma_writel(fsl_qdma, FSL_QDMA_DEDR_CLEAR, status + FSL_QDMA_DEDR);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
Loading…
Reference in New Issue