]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/pci/probe.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[karo-tx-linux.git] / drivers / pci / probe.c
index 496c5b082d4247082ef0450a9b379817ac1efaf9..4f9cc93c3b597df84d347a85906a1c2dcd76e549 100644 (file)
@@ -96,7 +96,7 @@ static void release_pcibus_dev(struct device *dev)
 static struct class pcibus_class = {
        .name           = "pci_bus",
        .dev_release    = &release_pcibus_dev,
-       .dev_attrs      = pcibus_dev_attrs,
+       .dev_groups     = pcibus_groups,
 };
 
 static int __init pcibus_class_init(void)
@@ -156,6 +156,8 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)
        return flags;
 }
 
+#define PCI_COMMAND_DECODE_ENABLE      (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
+
 /**
  * pci_read_base - read a PCI BAR
  * @dev: the PCI device
@@ -178,8 +180,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
        /* No printks while decoding is disabled! */
        if (!dev->mmio_always_on) {
                pci_read_config_word(dev, PCI_COMMAND, &orig_cmd);
-               pci_write_config_word(dev, PCI_COMMAND,
-                       orig_cmd & ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
+               if (orig_cmd & PCI_COMMAND_DECODE_ENABLE) {
+                       pci_write_config_word(dev, PCI_COMMAND,
+                               orig_cmd & ~PCI_COMMAND_DECODE_ENABLE);
+               }
        }
 
        res->name = pci_name(dev);
@@ -293,7 +297,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 fail:
        res->flags = 0;
 out:
-       if (!dev->mmio_always_on)
+       if (!dev->mmio_always_on &&
+           (orig_cmd & PCI_COMMAND_DECODE_ENABLE))
                pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
 
        if (bar_too_big)
@@ -1491,24 +1496,23 @@ static int pcie_find_smpss(struct pci_dev *dev, void *data)
        if (!pci_is_pcie(dev))
                return 0;
 
-       /* For PCIE hotplug enabled slots not connected directly to a
-        * PCI-E root port, there can be problems when hotplugging
-        * devices.  This is due to the possibility of hotplugging a
-        * device into the fabric with a smaller MPS that the devices
-        * currently running have configured.  Modifying the MPS on the
-        * running devices could cause a fatal bus error due to an
-        * incoming frame being larger than the newly configured MPS.
-        * To work around this, the MPS for the entire fabric must be
-        * set to the minimum size.  Any devices hotplugged into this
-        * fabric will have the minimum MPS set.  If the PCI hotplug
-        * slot is directly connected to the root port and there are not
-        * other devices on the fabric (which seems to be the most
-        * common case), then this is not an issue and MPS discovery
-        * will occur as normal.
+       /*
+        * We don't have a way to change MPS settings on devices that have
+        * drivers attached.  A hot-added device might support only the minimum
+        * MPS setting (MPS=128).  Therefore, if the fabric contains a bridge
+        * where devices may be hot-added, we limit the fabric MPS to 128 so
+        * hot-added devices will work correctly.
+        *
+        * However, if we hot-add a device to a slot directly below a Root
+        * Port, it's impossible for there to be other existing devices below
+        * the port.  We don't limit the MPS in this case because we can
+        * reconfigure MPS on both the Root Port and the hot-added device,
+        * and there are no other devices involved.
+        *
+        * Note that this PCIE_BUS_SAFE path assumes no peer-to-peer DMA.
         */
-       if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
-            (dev->bus->self &&
-             pci_pcie_type(dev->bus->self) != PCI_EXP_TYPE_ROOT_PORT)))
+       if (dev->is_hotplug_bridge &&
+           pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
                *smpss = 0;
 
        if (*smpss > dev->pcie_mpss)
@@ -1583,6 +1587,22 @@ static void pcie_write_mrrs(struct pci_dev *dev)
                        "with pci=pcie_bus_safe.\n");
 }
 
+static void pcie_bus_detect_mps(struct pci_dev *dev)
+{
+       struct pci_dev *bridge = dev->bus->self;
+       int mps, p_mps;
+
+       if (!bridge)
+               return;
+
+       mps = pcie_get_mps(dev);
+       p_mps = pcie_get_mps(bridge);
+
+       if (mps != p_mps)
+               dev_warn(&dev->dev, "Max Payload Size %d, but upstream %s set to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n",
+                        mps, pci_name(bridge), p_mps);
+}
+
 static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
 {
        int mps, orig_mps;
@@ -1590,13 +1610,18 @@ 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) {
+               pcie_bus_detect_mps(dev);
+               return 0;
+       }
+
        mps = 128 << *(u8 *)data;
        orig_mps = pcie_get_mps(dev);
 
        pcie_write_mps(dev, mps);
        pcie_write_mrrs(dev);
 
-       dev_info(&dev->dev, "PCI-E Max Payload Size set to %4d/%4d (was %4d), "
+       dev_info(&dev->dev, "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));
 
@@ -1607,25 +1632,25 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
  * parents then children fashion.  If this changes, then this code will not
  * work as designed.
  */
-void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
+void pcie_bus_configure_settings(struct pci_bus *bus)
 {
        u8 smpss;
 
-       if (!pci_is_pcie(bus->self))
+       if (!bus->self)
                return;
 
-       if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
+       if (!pci_is_pcie(bus->self))
                return;
 
        /* FIXME - Peer to peer DMA is possible, though the endpoint would need
-        * to be aware to the MPS of the destination.  To work around this,
+        * to be aware of the MPS of the destination.  To work around this,
         * simply force the MPS of the entire system to the smallest possible.
         */
        if (pcie_bus_config == PCIE_BUS_PEER2PEER)
                smpss = 0;
 
        if (pcie_bus_config == PCIE_BUS_SAFE) {
-               smpss = mpss;
+               smpss = bus->self->pcie_mpss;
 
                pcie_find_smpss(bus->self, &smpss);
                pci_walk_bus(bus, pcie_find_smpss, &smpss);
@@ -1979,7 +2004,6 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
 
        max = pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
-       pci_enable_bridges(bus);
        pci_bus_add_devices(bus);
 
        return max;