]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
PCI: loongson: Do not ignore downstream devices on external bridges
authorRong Zhang <i@rong.moe>
Thu, 30 Apr 2026 18:45:23 +0000 (02:45 +0800)
committerManivannan Sadhasivam <mani@kernel.org>
Tue, 12 May 2026 08:45:58 +0000 (14:15 +0530)
Loongson PCI host controllers have a hardware quirk that requires
software to ignore downstream devices with device number > 0 on the
internal bridges. The current implementation applies the workaround to
all non-root buses, which breaks external bridges (e.g., PCIe switches)
with multiple downstream devices.

Fix it by only applying the workaround to internal bridges.

Tested on Loongson-LS3A4000-7A1000-NUC-SE, using AMD Promontory 21
chipset add-in card [1].

  $ lspci -tnnnvvv
  -[0000:00]-+-00.0  Loongson Technology LLC 7A1000 Chipset Hyper Transport Bridge Controller [0014:7a00]
             +-00.1  Loongson Technology LLC 7A2000 Chipset Hyper Transport Bridge Controller [0014:7a10]
             +-03.0  Loongson Technology LLC 2K1000/2000 / 7A1000 Chipset Gigabit Ethernet Controller [0014:7a03]
             +-04.0  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB OHCI Controller [0014:7a24]
             +-04.1  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB EHCI Controller [0014:7a14]
             +-05.0  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB OHCI Controller [0014:7a24]
             +-05.1  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB EHCI Controller [0014:7a14]
             +-06.0  Loongson Technology LLC 7A1000 Chipset Vivante GC1000 GPU [0014:7a15]
             +-06.1  Loongson Technology LLC 2K1000 / 7A1000 Chipset Display Controller [0014:7a06]
             +-07.0  Loongson Technology LLC 2K1000/2000/3000 / 3B6000M / 7A1000/2000 Chipset HD Audio Controller [0014:7a07]
             +-08.0  Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
             +-08.1  Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
             +-08.2  Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
             +-09.0-[01]----00.0  Qualcomm Technologies, Inc QCNFA765 Wireless Network Adapter [17cb:1103]
             +-0a.0-[02]----00.0  Etron Technology, Inc. EJ188/EJ198 USB 3.0 Host Controller [1b6f:7052]
             +-0f.0-[03-08]----00.0-[04-08]--+-00.0-[05]----00.0  Shenzhen Longsys Electronics Co., Ltd. FORESEE XP1000 / Lexar Professional CFexpress Type B Gold series, NM620 PCIe NVME SSD (DRAM-less) [1d97:5216]
             |                               +-08.0-[06]----00.0  MAXIO Technology (Hangzhou) Ltd. NVMe SSD Controller MAP1202 (DRAM-less) [1e4b:1202]
             |                               +-0c.0-[07]----00.0  Advanced Micro Devices, Inc. [AMD] 600 Series Chipset USB 3.2 Controller [1022:43f7]
             |                               \-0d.0-[08]----00.0  Advanced Micro Devices, Inc. [AMD] 600 Series Chipset SATA Controller [1022:43f6]
             \-16.0  Loongson Technology LLC 7A1000 Chipset SPI Controller [0014:7a0b]

Fixes: 2410e3301fcc ("PCI: loongson: Don't access non-existent devices")
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Co-developed-by: Lain "Fearyncess" Yang <i@lain.vg>
Signed-off-by: Lain "Fearyncess" Yang <i@lain.vg>
Signed-off-by: Rong Zhang <i@rong.moe>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://oshwhub.com/wesd/b650
Link: https://patch.msgid.link/20260501-ls7a-bridge-fixes-v2-1-69fa93683805@rong.moe
drivers/pci/controller/pci-loongson.c

index bc630ab8a283162189989cc161cfe87ba4527cb8..de5e809a537d2ccbe79f59dbcaec13904f4673d8 100644 (file)
@@ -80,6 +80,18 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
                        DEV_LS7A_LPC, system_bus_quirk);
 
+static const struct pci_device_id loongson_internal_bridge_devids[] = {
+       { PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
+       { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
+       { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
+       { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
+       { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
+       { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
+       { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
+       { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
+       { 0, },
+};
+
 /*
  * Some Loongson PCIe ports have hardware limitations on their Maximum Read
  * Request Size. They can't handle anything larger than this.  Sane
@@ -92,24 +104,13 @@ static void loongson_set_min_mrrs_quirk(struct pci_dev *pdev)
 {
        struct pci_bus *bus = pdev->bus;
        struct pci_dev *bridge;
-       static const struct pci_device_id bridge_devids[] = {
-               { PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
-               { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
-               { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
-               { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
-               { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
-               { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
-               { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
-               { PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
-               { 0, },
-       };
 
        /* look for the matching bridge */
        while (!pci_is_root_bus(bus)) {
                bridge = bus->self;
                bus = bus->parent;
 
-               if (pci_match_id(bridge_devids, bridge)) {
+               if (pci_match_id(loongson_internal_bridge_devids, bridge)) {
                        if (pcie_get_readrq(pdev) > 256) {
                                pci_info(pdev, "limiting MRRS to 256\n");
                                pcie_set_readrq(pdev, 256);
@@ -230,11 +231,11 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
        struct loongson_pci *priv = pci_bus_to_loongson_pci(bus);
 
        /*
-        * Do not read more than one device on the bus other than
-        * the host bus.
+        * Do not read more than one device on the internal bridges.
         */
        if ((priv->data->flags & FLAG_DEV_FIX) && bus->self) {
-               if (!pci_is_root_bus(bus) && (device > 0))
+               if (!pci_is_root_bus(bus) && (device > 0) &&
+                   pci_match_id(loongson_internal_bridge_devids, bus->self))
                        return NULL;
        }