summaryrefslogtreecommitdiffstats
path: root/drivers/pci/probe.c
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2015-08-24 08:48:16 -0500
committerBjorn Helgaas <bhelgaas@google.com>2015-08-24 08:48:16 -0500
commit27d868b5e6cfaee4fec66b388e4085ff94050fa7 (patch)
tree9df429169a5671c49c70b0ac34c8ba95fb1e21b7 /drivers/pci/probe.c
parent9dae3a97297f71e884ed8e7664955bcacb86f010 (diff)
downloadtalos-obmc-linux-27d868b5e6cfaee4fec66b388e4085ff94050fa7.tar.gz
talos-obmc-linux-27d868b5e6cfaee4fec66b388e4085ff94050fa7.zip
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 <keith.busch@intel.com> Tested-by: Jordan Hargrave <jharg93@gmail.com> Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Yinghai Lu <yinghai@kernel.org>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r--drivers/pci/probe.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index eb32395d5897..eebabe3a814e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1278,7 +1278,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;
@@ -1294,6 +1294,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 = {
@@ -1821,7 +1838,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;
OpenPOWER on IntegriCloud