From 5daea9d6a8c8601754b0ce7dbb00c522003e6a85 Mon Sep 17 00:00:00 2001 From: wuqianhai Date: Tue, 3 Feb 2026 09:43:51 +0800 Subject: [PATCH] anolis: pci/quirks: Fix 2k2000/2k3000 gpu dma hangs ANBZ: #34027 pci/quirks: Fix 2k2000/2k3000 GPU DMA hangs by disabling DC/GPU/VPU output around BAR1 setup; add early and final quirks and log fixup status. Signed-off-by: wuqianhai Signed-off-by: Juxin Gao --- arch/loongarch/pci/pci.c | 95 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/arch/loongarch/pci/pci.c b/arch/loongarch/pci/pci.c index 2726639150bc..2a3bbca4a53f 100644 --- a/arch/loongarch/pci/pci.c +++ b/arch/loongarch/pci/pci.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -98,3 +99,97 @@ static void pci_fixup_vgadev(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev); + +#define DEV_LS2K3000_DC 0x7a46 +#define DEV_LS2K2000_DC 0x7a36 +#define DEV_LS2K2000_GPU 0x7a25 +#define DEV_LS2K3000_GPU 0x7a35 +#define LS2K2000_DC_OFFSET 0x1240 +#define LS2K3000_DC_OFFSET 0 +#define LS2K2000_DC_CRTC_OFFSET 0x10 +#define LS2K3000_DC_CRTC_OFFSET 0x400 +#define LS2K_DC_OUTPUT_ENABLE 0x100 +#define LS2K_DC_BAR_SIZE 0x10000 +#define LS2K_DC_NUM_MAX 2 + +static u32 save_status[LS2K_DC_NUM_MAX] = { 0 }; +static void loongson_dma_hangs_fixup(struct pci_dev *pdev, bool open) +{ + void __iomem *dc_reg, *base, *regbase; + u32 val, count, i, crtc_offset, device; + + base = pdev->bus->ops->map_bus(pdev->bus, pdev->devfn + 1, 0); + device = readw(base + PCI_DEVICE_ID); + + crtc_offset = (device == DEV_LS2K3000_DC) ? LS2K3000_DC_CRTC_OFFSET : + (device == DEV_LS2K2000_DC) ? LS2K2000_DC_CRTC_OFFSET : + 0; + regbase = ioremap(readq(base + PCI_BASE_ADDRESS_0) & ~0xffull, + LS2K_DC_BAR_SIZE); + if (!regbase) { + pci_err(pdev, "Failed to ioremap\n"); + return; + } + + dc_reg = regbase + ((device == DEV_LS2K2000_DC) ? LS2K2000_DC_OFFSET : + LS2K3000_DC_OFFSET); + + for (i = 0; i < LS2K_DC_NUM_MAX; i++, dc_reg += crtc_offset) { + count = 0; + + val = readl(dc_reg); + + if (!open) + save_status[i] = val; + + /* If the status is turned off at startup, + * there is no need to fixup. + */ + if (!(save_status[i] & LS2K_DC_OUTPUT_ENABLE)) { + pci_info(pdev, + "dma hangs no fixup at reg[0x%llx] : 0x%x\n", + (u64)dc_reg & 0xffff, save_status[i]); + continue; + } + + if (open) + val |= LS2K_DC_OUTPUT_ENABLE; + else + val &= ~LS2K_DC_OUTPUT_ENABLE; + + /* ensure value active */ + mb(); + writel(val, dc_reg); + + while (open ? (!(readl(dc_reg) & LS2K_DC_OUTPUT_ENABLE)) : + (readl(dc_reg) & LS2K_DC_OUTPUT_ENABLE)) { + if (count++ > 50) + break; + udelay(1000); + } + + pci_info(pdev, "dma hangs fixup at reg[0x%llx] : 0x%x\n", + (u64)dc_reg & 0xffff, val); + } + + iounmap(regbase); +} + +static void loongson_dma_hangs_early_quirk(struct pci_dev *pdev) +{ + loongson_dma_hangs_fixup(pdev, false); +} + +static void loongson_dma_hangs_final_quirk(struct pci_dev *pdev) +{ + loongson_dma_hangs_fixup(pdev, true); +} + +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, DEV_LS2K2000_GPU, + loongson_dma_hangs_early_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, DEV_LS2K3000_GPU, + loongson_dma_hangs_early_quirk); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, DEV_LS2K2000_GPU, + loongson_dma_hangs_final_quirk); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, DEV_LS2K3000_GPU, + loongson_dma_hangs_final_quirk); \ No newline at end of file -- Gitee