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 <nkristam@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-t264/+/3175952
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Nagarjuna Kristam
2024-07-16 15:43:27 +05:30
committed by Jon Hunter
parent 8774bd321b
commit 49f357d6e1

View File

@@ -258,19 +258,23 @@ static irqreturn_t xdma_irq_handler(int irq, void *cookie)
continue; continue;
for (bit = 0; bit < mode_cnt[i]; bit++) { 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; ch = chan[i] + bit;
/* Process only if DMA channel status set in INTR status */ /* Ignore if no error or xfer valid set for the channel. */
if (!(val & (1 << (16 + bit + (i * mode_cnt[0]))))) if (!xfer_valid && !err_status)
continue; continue;
if (val & XDMA_MSI_CHANNEL_PRIMARY_INTR_STATUS_FUNC_ERR_VALID) { if (err_status) {
{
u32 temp; u32 temp;
temp = xdma_channel_rd(prv->xdma_base, prv->is_remote_dma, temp = xdma_channel_rd(prv->xdma_base, bit + (i * mode_cnt[0]),
XDMA_CHANNEL_FUNC_ERROR_STATUS); 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; ch->st = TEGRA_PCIE_DMA_ABORT;
xdma_hw_deinit(prv, bit + (i * mode_cnt[0])); 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]), xdma_ll_ch_init(prv->xdma_base, bit + (i * mode_cnt[0]),
ch->dma_iova, (i == 0), prv->is_remote_dma); 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 { } else {
process_ch_irq(prv, bit + (i * mode_cnt[0]), ch, i); process_ch_irq(prv, bit + (i * mode_cnt[0]), ch, i);
} }