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>
This commit is contained in:
Keith Busch 2015-08-24 08:48:16 -05:00 committed by Bjorn Helgaas
parent 9dae3a9729
commit 27d868b5e6
4 changed files with 28 additions and 8 deletions

View 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_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_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 * The default CLS is used if arch didn't set CLS explicitly and not

View File

@ -1278,7 +1278,7 @@ int pci_setup_device(struct pci_dev *dev)
static void pci_configure_mps(struct pci_dev *dev) static void pci_configure_mps(struct pci_dev *dev)
{ {
struct pci_dev *bridge = pci_upstream_bridge(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)) if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge))
return; return;
@ -1294,6 +1294,23 @@ static void pci_configure_mps(struct pci_dev *dev)
mps, pci_name(bridge), p_mps); mps, pci_name(bridge), p_mps);
return; 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 = { 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)) if (!pci_is_pcie(dev))
return 0; 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; return 0;
mps = 128 << *(u8 *)data; mps = 128 << *(u8 *)data;

View File

@ -2862,7 +2862,8 @@ static void quirk_intel_mc_errata(struct pci_dev *dev)
int err; int err;
u16 rcc; 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; return;
/* Intel errata specifies bits to change but does not say what they are. /* Intel errata specifies bits to change but does not say what they are.

View File

@ -738,10 +738,11 @@ struct pci_driver {
void pcie_bus_configure_settings(struct pci_bus *bus); void pcie_bus_configure_settings(struct pci_bus *bus);
enum pcie_bus_config_types { enum pcie_bus_config_types {
PCIE_BUS_TUNE_OFF, PCIE_BUS_TUNE_OFF, /* don't touch MPS at all */
PCIE_BUS_SAFE, PCIE_BUS_DEFAULT, /* ensure MPS matches upstream bridge */
PCIE_BUS_PERFORMANCE, PCIE_BUS_SAFE, /* use largest MPS boot-time devices support */
PCIE_BUS_PEER2PEER, 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; extern enum pcie_bus_config_types pcie_bus_config;