]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
PCI: enable MPS "performance" setting to properly handle bridge MPS
authorJon Mason <mason@myri.com>
Fri, 14 Oct 2011 19:56:14 +0000 (14:56 -0500)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Thu, 27 Oct 2011 19:45:43 +0000 (12:45 -0700)
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>
drivers/pci/probe.c

index 6ab6bd3df4b25582f8fec61fbda9779333273a95..4829424398521a659755ae7135075645fe87afd3 100644 (file)
@@ -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));