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
This commit is contained in:
Bjorn Helgaas 2026-06-23 17:32:16 -05:00
commit a5c8e1ffe9

View 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);
@ -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;
}