Merge branch 'pci/enumeration'

- Use PCI_HEADER_TYPE_* defines, not hard-coded values (Ilpo Järvinen)

- Clean up early_dump_pci_device() to avoid hard-coded values (Ilpo
  Järvinen)

- Clean up pci_scan_child_bus_extend() loop to avoid hard-coded values
  (Ilpo Järvinen)

- Add a Xeon 6 quirk to disable Extended Tags and limit Max Read Request
  Size to 128B to avoid a performance issue (Ilpo Järvinen)

* pci/enumeration:
  PCI: Add Extended Tag + MRRS quirk for Xeon 6
  PCI: Clean up pci_scan_child_bus_extend() loop
  PCI: Clean up early_dump_pci_device()
  PCI: Use header type defines in pci_setup_device()
This commit is contained in:
Bjorn Helgaas
2025-10-03 12:13:08 -05:00
3 changed files with 51 additions and 9 deletions

View File

@@ -294,6 +294,46 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_r
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk);
/*
* PCIe devices underneath Xeon 6 PCIe Root Port bifurcated to x2 have lower
* performance with Extended Tags and MRRS > 128B. Work around the performance
* problems by disabling Extended Tags and limiting MRRS to 128B.
*
* https://cdrdv2.intel.com/v1/dl/getContent/837176
*/
static int limit_mrrs_to_128(struct pci_host_bridge *b, struct pci_dev *pdev)
{
int readrq = pcie_get_readrq(pdev);
if (readrq > 128)
pcie_set_readrq(pdev, 128);
return 0;
}
static void pci_xeon_x2_bifurc_quirk(struct pci_dev *pdev)
{
struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
u32 linkcap;
pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &linkcap);
if (FIELD_GET(PCI_EXP_LNKCAP_MLW, linkcap) != 0x2)
return;
bridge->no_ext_tags = 1;
bridge->enable_device = limit_mrrs_to_128;
pci_info(pdev, "Disabling Extended Tags and limiting MRRS to 128B (performance reasons due to x2 PCIe link)\n");
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db0, pci_xeon_x2_bifurc_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db1, pci_xeon_x2_bifurc_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db2, pci_xeon_x2_bifurc_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db3, pci_xeon_x2_bifurc_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db6, pci_xeon_x2_bifurc_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db7, pci_xeon_x2_bifurc_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db8, pci_xeon_x2_bifurc_quirk);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0db9, pci_xeon_x2_bifurc_quirk);
/*
* Fixup to mark boot BIOS video selected by BIOS before it changes
*

View File

@@ -8,6 +8,7 @@ struct pcie_tlp_log;
/* Number of possible devfns: 0.0 to 1f.7 inclusive */
#define MAX_NR_DEVFNS 256
#define PCI_MAX_NR_DEVS 32
#define MAX_NR_LANES 16

View File

@@ -3,6 +3,7 @@
* PCI detection and setup code
*/
#include <linux/array_size.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -1912,16 +1913,16 @@ static int pci_intx_mask_broken(struct pci_dev *dev)
static void early_dump_pci_device(struct pci_dev *pdev)
{
u32 value[256 / 4];
u32 value[PCI_CFG_SPACE_SIZE / sizeof(u32)];
int i;
pci_info(pdev, "config space:\n");
for (i = 0; i < 256; i += 4)
pci_read_config_dword(pdev, i, &value[i / 4]);
for (i = 0; i < ARRAY_SIZE(value); i++)
pci_read_config_dword(pdev, i * sizeof(u32), &value[i]);
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
value, 256, false);
value, ARRAY_SIZE(value) * sizeof(u32), false);
}
static const char *pci_type_str(struct pci_dev *dev)
@@ -1985,8 +1986,8 @@ int pci_setup_device(struct pci_dev *dev)
dev->sysdata = dev->bus->sysdata;
dev->dev.parent = dev->bus->bridge;
dev->dev.bus = &pci_bus_type;
dev->hdr_type = hdr_type & 0x7f;
dev->multifunction = !!(hdr_type & 0x80);
dev->hdr_type = FIELD_GET(PCI_HEADER_TYPE_MASK, hdr_type);
dev->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr_type);
dev->error_state = pci_channel_io_normal;
set_pcie_port_type(dev);
@@ -3045,14 +3046,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
{
unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0;
unsigned int start = bus->busn_res.start;
unsigned int devfn, cmax, max = start;
unsigned int devnr, cmax, max = start;
struct pci_dev *dev;
dev_dbg(&bus->dev, "scanning bus\n");
/* Go find them, Rover! */
for (devfn = 0; devfn < 256; devfn += 8)
pci_scan_slot(bus, devfn);
for (devnr = 0; devnr < PCI_MAX_NR_DEVS; devnr++)
pci_scan_slot(bus, PCI_DEVFN(devnr, 0));
/* Reserve buses for SR-IOV capability */
used_buses = pci_iov_bus_range(bus);