summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorJon Mason <mason@myri.com>2011-10-14 21:56:14 +0200
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-10-27 21:45:43 +0200
commit62f392ea5b5f87b641e16e61a4cedda21ef7341f (patch)
tree3392e1c0b10f851df98b18797c0637608887d624 /drivers/pci
parentPCI: Workaround for Intel MPS errata (diff)
downloadlinux-62f392ea5b5f87b641e16e61a4cedda21ef7341f.tar.xz
linux-62f392ea5b5f87b641e16e61a4cedda21ef7341f.zip
PCI: enable MPS "performance" setting to properly handle bridge MPS
Rework the "performance" MPS option to configure the device MPS with the smaller of the device MPSS or the bridge MPS (which is assumed to be properly configured at this point to the largest allowable MPS based on its parent bus). Also, rework the MRRS setting to report an inability to set the MRRS to a valid setting. Signed-off-by: Jon Mason <mason@myri.com> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/probe.c55
1 files changed, 24 insertions, 31 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6ab6bd3df4b2..482942439852 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1363,31 +1363,25 @@ static int pcie_find_smpss(struct pci_dev *dev, void *data)
static void pcie_write_mps(struct pci_dev *dev, int mps)
{
- int rc, dev_mpss;
-
- dev_mpss = 128 << dev->pcie_mpss;
+ int rc;
if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
- if (dev->bus->self) {
- dev_dbg(&dev->bus->dev, "Bus MPSS %d\n",
- 128 << dev->bus->self->pcie_mpss);
+ mps = 128 << dev->pcie_mpss;
- /* For "MPS Force Max", the assumption is made that
+ if (dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && dev->bus->self)
+ /* For "Performance", the assumption is made that
* downstream communication will never be larger than
* the MRRS. So, the MPS only needs to be configured
* for the upstream communication. This being the case,
* walk from the top down and set the MPS of the child
* to that of the parent bus.
+ *
+ * Configure the device MPS with the smaller of the
+ * device MPSS or the bridge MPS (which is assumed to be
+ * properly configured at this point to the largest
+ * allowable MPS based on its parent bus).
*/
- mps = 128 << dev->bus->self->pcie_mpss;
- if (mps > dev_mpss)
- dev_warn(&dev->dev, "MPS configured higher than"
- " maximum supported by the device. If"
- " a bus issue occurs, try running with"
- " pci=pcie_bus_safe.\n");
- }
-
- dev->pcie_mpss = ffs(mps) - 8;
+ mps = min(mps, pcie_get_mps(dev->bus->self));
}
rc = pcie_set_mps(dev, mps);
@@ -1395,25 +1389,22 @@ static void pcie_write_mps(struct pci_dev *dev, int mps)
dev_err(&dev->dev, "Failed attempting to set the MPS\n");
}
-static void pcie_write_mrrs(struct pci_dev *dev, int mps)
+static void pcie_write_mrrs(struct pci_dev *dev)
{
- int rc, mrrs, dev_mpss;
+ int rc, mrrs;
/* In the "safe" case, do not configure the MRRS. There appear to be
* issues with setting MRRS to 0 on a number of devices.
*/
-
if (pcie_bus_config != PCIE_BUS_PERFORMANCE)
return;
- dev_mpss = 128 << dev->pcie_mpss;
-
/* For Max performance, the MRRS must be set to the largest supported
* value. However, it cannot be configured larger than the MPS the
- * device or the bus can support. This assumes that the largest MRRS
- * available on the device cannot be smaller than the device MPSS.
+ * device or the bus can support. This should already be properly
+ * configured by a prior call to pcie_write_mps.
*/
- mrrs = min(mps, dev_mpss);
+ mrrs = pcie_get_mps(dev);
/* MRRS is a R/W register. Invalid values can be written, but a
* subsequent read will verify if the value is acceptable or not.
@@ -1421,16 +1412,18 @@ static void pcie_write_mrrs(struct pci_dev *dev, int mps)
* shrink the value until it is acceptable to the HW.
*/
while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) {
- dev_warn(&dev->dev, "Attempting to modify the PCI-E MRRS value"
- " to %d. If any issues are encountered, please try "
- "running with pci=pcie_bus_safe\n", mrrs);
rc = pcie_set_readrq(dev, mrrs);
- if (rc)
- dev_err(&dev->dev,
- "Failed attempting to set the MRRS\n");
+ if (!rc)
+ break;
+ dev_warn(&dev->dev, "Failed attempting to set the MRRS\n");
mrrs /= 2;
}
+
+ if (mrrs < 128)
+ dev_err(&dev->dev, "MRRS was unable to be configured with a "
+ "safe value. If problems are experienced, try running "
+ "with pci=pcie_bus_safe.\n");
}
static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
@@ -1444,7 +1437,7 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
pcie_write_mps(dev, mps);
- pcie_write_mrrs(dev, mps);
+ pcie_write_mrrs(dev);
dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));