PCI: Restore detection of read-only BARs
[pandora-kernel.git] / drivers / pci / probe.c
index 6ab6bd3..bc92c47 100644 (file)
@@ -175,14 +175,17 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                res->flags |= IORESOURCE_SIZEALIGN;
                if (res->flags & IORESOURCE_IO) {
                        l &= PCI_BASE_ADDRESS_IO_MASK;
+                       sz &= PCI_BASE_ADDRESS_IO_MASK;
                        mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT;
                } else {
                        l &= PCI_BASE_ADDRESS_MEM_MASK;
+                       sz &= PCI_BASE_ADDRESS_MEM_MASK;
                        mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
                }
        } else {
                res->flags |= (l & IORESOURCE_ROM_ENABLE);
                l &= PCI_ROM_ADDRESS_MASK;
+               sz &= PCI_ROM_ADDRESS_MASK;
                mask = (u32)PCI_ROM_ADDRESS_MASK;
        }
 
@@ -651,10 +654,17 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
        dev_dbg(&dev->dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n",
                secondary, subordinate, pass);
 
+       if (!primary && (primary != bus->number) && secondary && subordinate) {
+               dev_warn(&dev->dev, "Primary bus is hard wired to 0\n");
+               primary = bus->number;
+       }
+
        /* Check if setup is sensible at all */
        if (!pass &&
-           (primary != bus->number || secondary <= bus->number)) {
-               dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
+           (primary != bus->number || secondary <= bus->number ||
+            secondary > subordinate)) {
+               dev_info(&dev->dev, "bridge configuration invalid ([bus %02x-%02x]), reconfiguring\n",
+                        secondary, subordinate);
                broken = 1;
        }
 
@@ -1363,31 +1373,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 +1399,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,38 +1422,41 @@ 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)
 {
-       int mps = 128 << *(u8 *)data;
+       int mps, orig_mps;
 
        if (!pci_is_pcie(dev))
                return 0;
 
-       dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
-                pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
+       mps = 128 << *(u8 *)data;
+       orig_mps = pcie_get_mps(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));
+       dev_info(&dev->dev, "PCI-E Max Payload Size set to %4d/%4d (was %4d), "
+                "Max Read Rq %4d\n", pcie_get_mps(dev), 128 << dev->pcie_mpss,
+                orig_mps, pcie_get_readrq(dev));
 
        return 0;
 }
 
-/* pcie_bus_configure_mps requires that pci_walk_bus work in a top-down,
+/* pcie_bus_configure_settings requires that pci_walk_bus work in a top-down,
  * parents then children fashion.  If this changes, then this code will not
  * work as designed.
  */