aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
authorBjorn Helgaas <bhelgaas@google.com>2026-06-23 17:32:16 -0500
committerBjorn Helgaas <bhelgaas@google.com>2026-06-23 17:32:16 -0500
commita5c8e1ffe9d92f76b62c515506121c7870ec7fcf (patch)
tree6016b73af892497b32ef6553a394a92804e46a57 /drivers
parentd04ef0d3b44e6ea15a13fa02268e60e8fde97ec4 (diff)
parente373c789bac0ad73b472d8b44714df3bd18a4edf (diff)
downloadath-a5c8e1ffe9d92f76b62c515506121c7870ec7fcf.tar.gz
Merge branch 'pci/controller/loongson'
- Ignore downstream devices only on internal bridges to avoid Loongson hardware issue (Rong Zhang) - Quirk old Loongson-3C6000 bridges that advertise incorrect supported link speeds (Ziyao Li) * pci/controller/loongson: PCI: loongson: Override PCIe bridge supported speeds for Loongson-3C6000 series PCI: loongson: Do not ignore downstream devices on external bridges
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/controller/pci-loongson.c67
1 files changed, 52 insertions, 15 deletions
diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c
index bc630ab8a2831..d0c643996476f 100644
--- a/drivers/pci/controller/pci-loongson.c
+++ b/drivers/pci/controller/pci-loongson.c
@@ -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);
@@ -176,6 +177,42 @@ static void loongson_pci_msi_quirk(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, DEV_LS7A_PCIE_PORT5, loongson_pci_msi_quirk);
+/*
+ * Older steppings of the Loongson-3C6000 series incorrectly report the
+ * supported link speeds on their PCIe bridges (device IDs 0x3c19,
+ * 0x3c29) as only 2.5 GT/s, despite the upstream bus supporting speeds
+ * from 2.5 GT/s up to 16 GT/s.
+ */
+static void loongson_pci_bridge_speed_quirk(struct pci_dev *pdev)
+{
+ u8 old_supported_speeds = pdev->supported_speeds;
+
+ switch (pdev->bus->max_bus_speed) {
+ case PCIE_SPEED_16_0GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_16_0GB;
+ fallthrough;
+ case PCIE_SPEED_8_0GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_8_0GB;
+ fallthrough;
+ case PCIE_SPEED_5_0GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_5_0GB;
+ fallthrough;
+ case PCIE_SPEED_2_5GT:
+ pdev->supported_speeds |= PCI_EXP_LNKCAP2_SLS_2_5GB;
+ break;
+ default:
+ pci_warn(pdev, "unexpected max bus speed");
+
+ return;
+ }
+
+ if (pdev->supported_speeds != old_supported_speeds)
+ pci_info(pdev, "fixed up supported link speeds: 0x%x => 0x%x",
+ old_supported_speeds, pdev->supported_speeds);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LOONGSON, 0x3c19, loongson_pci_bridge_speed_quirk);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_LOONGSON, 0x3c29, loongson_pci_bridge_speed_quirk);
+
static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus)
{
struct pci_config_window *cfg;
@@ -230,11 +267,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;
}