From: Keith Busch Date: Mon, 24 Aug 2015 13:48:16 +0000 (-0500) Subject: PCI: Set MPS to match upstream bridge X-Git-Tag: v4.1.12-92~162^2~6 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=3e2dc7ef5bf7c5722ba462ce43dc94ab0f427212;p=users%2Fjedix%2Flinux-maple.git PCI: Set MPS to match upstream bridge Firmware typically configures the PCIe fabric with a consistent Max Payload Size setting based on the devices present at boot. A hot-added device typically has the power-on default MPS setting (128 bytes), which may not match the fabric. The previous Linux default, in the absence of any "pci=pcie_bus_*" options, was PCIE_BUS_TUNE_OFF, in which we never touch MPS, even for hot-added devices. Add a new default setting, PCIE_BUS_DEFAULT, in which we make sure every device's MPS setting matches the upstream bridge. This makes it more likely that a hot-added device will work in a system with optimized MPS configuration. Note that if we hot-add a device that only supports 128-byte MPS, it still likely won't work because we don't reconfigure the rest of the fabric. Booting with "pci=pcie_bus_peer2peer" is a workaround for this because it sets MPS to 128 for everything. [bhelgaas: changelog, new default, rework for pci_configure_device() path] Tested-by: Keith Busch Tested-by: Jordan Hargrave Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Acked-by: Yinghai Lu (cherry picked from commit 27d868b5e6cfaee4fec66b388e4085ff94050fa7) Orabug: 23237033 Signed-off-by: Ethan Zhao --- diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index acc4b6ef78c43..f1ae534afa78a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -81,7 +81,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; +enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT; /* * The default CLS is used if arch didn't set CLS explicitly and not diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 22467a793e3e8..8ac2975249363 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1242,7 +1242,7 @@ int pci_setup_device(struct pci_dev *dev) static void pci_configure_mps(struct pci_dev *dev) { struct pci_dev *bridge = pci_upstream_bridge(dev); - int mps, p_mps; + int mps, p_mps, rc; if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge)) return; @@ -1258,6 +1258,23 @@ static void pci_configure_mps(struct pci_dev *dev) mps, pci_name(bridge), p_mps); return; } + + /* + * Fancier MPS configuration is done later by + * pcie_bus_configure_settings() + */ + if (pcie_bus_config != PCIE_BUS_DEFAULT) + return; + + rc = pcie_set_mps(dev, p_mps); + if (rc) { + dev_warn(&dev->dev, "can't set Max Payload Size to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n", + p_mps); + return; + } + + dev_info(&dev->dev, "Max Payload Size set to %d (was %d, max %d)\n", + p_mps, mps, 128 << dev->pcie_mpss); } static struct hpp_type0 pci_default_type0 = { @@ -1785,7 +1802,8 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) if (!pci_is_pcie(dev)) return 0; - if (pcie_bus_config == PCIE_BUS_TUNE_OFF) + if (pcie_bus_config == PCIE_BUS_TUNE_OFF || + pcie_bus_config == PCIE_BUS_DEFAULT) return 0; mps = 128 << *(u8 *)data; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c6dc1dfd25d55..40284e15e8db8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2871,7 +2871,8 @@ static void quirk_intel_mc_errata(struct pci_dev *dev) int err; u16 rcc; - if (pcie_bus_config == PCIE_BUS_TUNE_OFF) + if (pcie_bus_config == PCIE_BUS_TUNE_OFF || + pcie_bus_config == PCIE_BUS_DEFAULT) return; /* Intel errata specifies bits to change but does not say what they are. diff --git a/include/linux/pci.h b/include/linux/pci.h index 353db8dc4c6e0..e1fa6e516dce2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -731,10 +731,11 @@ struct pci_driver { void pcie_bus_configure_settings(struct pci_bus *bus); enum pcie_bus_config_types { - PCIE_BUS_TUNE_OFF, - PCIE_BUS_SAFE, - PCIE_BUS_PERFORMANCE, - PCIE_BUS_PEER2PEER, + PCIE_BUS_TUNE_OFF, /* don't touch MPS at all */ + PCIE_BUS_DEFAULT, /* ensure MPS matches upstream bridge */ + PCIE_BUS_SAFE, /* use largest MPS boot-time devices support */ + PCIE_BUS_PERFORMANCE, /* use MPS and MRRS for best performance */ + PCIE_BUS_PEER2PEER, /* set MPS = 128 for all devices */ }; extern enum pcie_bus_config_types pcie_bus_config;