From 49f357d6e162f9b63cc9c0b7cd9615a2c7ebef38 Mon Sep 17 00:00:00 2001 From: Nagarjuna Kristam Date: Tue, 16 Jul 2024 15:43:27 +0530 Subject: [PATCH] pci: t264-xdma: Fix MSI error handling Issue: When XDMA interrupt is received and only error is set, interrupt is not processed resulting in DMA HW halt and no further transfers working. Fix: Process XDMA irq, when either transfer complete or error status is set. Bug 4747322 Change-Id: Ic71f3bf93343e986a1f4be9b570bcc36f03afeeb Signed-off-by: Nagarjuna Kristam Reviewed-on: https://git-master.nvidia.com/r/c/linux-t264/+/3175952 Reviewed-by: Bitan Biswas GVS: buildbot_gerritrpt --- .../private-soc/tegra264-pcie-xdma.c | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/private-soc/tegra264-pcie-xdma.c b/drivers/pci/controller/private-soc/tegra264-pcie-xdma.c index 5d24558c..b34f33cd 100644 --- a/drivers/pci/controller/private-soc/tegra264-pcie-xdma.c +++ b/drivers/pci/controller/private-soc/tegra264-pcie-xdma.c @@ -258,19 +258,23 @@ static irqreturn_t xdma_irq_handler(int irq, void *cookie) continue; for (bit = 0; bit < mode_cnt[i]; bit++) { + u32 xfer_valid = val & (1 << (16 + bit + (i * mode_cnt[0]))); + u32 err_status = val & (1 << (8 + bit + (i * mode_cnt[0]))); + ch = chan[i] + bit; - /* Process only if DMA channel status set in INTR status */ - if (!(val & (1 << (16 + bit + (i * mode_cnt[0]))))) + /* Ignore if no error or xfer valid set for the channel. */ + if (!xfer_valid && !err_status) continue; - if (val & XDMA_MSI_CHANNEL_PRIMARY_INTR_STATUS_FUNC_ERR_VALID) { - { - u32 temp; + if (err_status) { + u32 temp; - temp = xdma_channel_rd(prv->xdma_base, prv->is_remote_dma, - XDMA_CHANNEL_FUNC_ERROR_STATUS); - } + temp = xdma_channel_rd(prv->xdma_base, bit + (i * mode_cnt[0]), + XDMA_CHANNEL_FUNC_ERROR_STATUS); + + dev_info(prv->dev, "MSI error %x seen for channel %d for mode %d\n", + temp, bit, i); ch->st = TEGRA_PCIE_DMA_ABORT; xdma_hw_deinit(prv, bit + (i * mode_cnt[0])); @@ -285,6 +289,11 @@ static irqreturn_t xdma_irq_handler(int irq, void *cookie) xdma_ll_ch_init(prv->xdma_base, bit + (i * mode_cnt[0]), ch->dma_iova, (i == 0), prv->is_remote_dma); + /* + * If both xfer_valid and err_status are set, error recovery process + * channel(process_ch_irq()), so we can skip else part when both xfer_valid + * and err_status are set. + */ } else { process_ch_irq(prv, bit + (i * mode_cnt[0]), ch, i); }