]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
PCI: Set MPS to match upstream bridge
authorKeith Busch <keith.busch@intel.com>
Mon, 24 Aug 2015 13:48:16 +0000 (08:48 -0500)
committerChuck Anderson <chuck.anderson@oracle.com>
Sun, 22 May 2016 18:07:59 +0000 (11:07 -0700)
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>
(cherry picked from commit 27d868b5e6cfaee4fec66b388e4085ff94050fa7)

Orabug: 23237033

Signed-off-by: Ethan Zhao <ethan.zhao@oracle.com>
drivers/pci/pci.c
drivers/pci/probe.c
drivers/pci/quirks.c
include/linux/pci.h

index acc4b6ef78c4380273b1af144838582dde57f80a..f1ae534afa78a03a89afc2fce81a6817b6305208 100644 (file)
@@ -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
index 22467a793e3e89b0d8d05dc365351d530e46b96e..8ac2975249363be95d6b17e049a363a47120707f 100644 (file)
@@ -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;
index c6dc1dfd25d55ea9ac536634143eafcf196ce2c2..40284e15e8db89a0cb36d6b0ae498de88d37481e 100644 (file)
@@ -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.
index 353db8dc4c6e0eca74751d4aabc8b0cb28fc4c7a..e1fa6e516dce2e641e8da12e74259b3141868089 100644 (file)
@@ -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;