PCI: Make current and maximum bus speeds part of the PCI core
[safe/jmp/linux-2.6] / drivers / pci / probe.c
index 54b9f15..51cf898 100644 (file)
@@ -10,9 +10,7 @@
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/pci-aspm.h>
-#include <linux/iommu.h>
 #include <acpi/acpi_hest.h>
-#include <xen/xen.h>
 #include "pci.h"
 
 #define CARDBUS_LATENCY_TIMER  176     /* secondary latency timer */
@@ -389,10 +387,37 @@ static struct pci_bus * pci_alloc_bus(void)
                INIT_LIST_HEAD(&b->children);
                INIT_LIST_HEAD(&b->devices);
                INIT_LIST_HEAD(&b->slots);
+               b->max_bus_speed = PCI_SPEED_UNKNOWN;
+               b->cur_bus_speed = PCI_SPEED_UNKNOWN;
        }
        return b;
 }
 
+static unsigned char pcie_link_speed[] = {
+       PCI_SPEED_UNKNOWN,              /* 0 */
+       PCIE_SPEED_2_5GT,               /* 1 */
+       PCIE_SPEED_5_0GT,               /* 2 */
+       PCI_SPEED_UNKNOWN,              /* 3 */
+       PCI_SPEED_UNKNOWN,              /* 4 */
+       PCI_SPEED_UNKNOWN,              /* 5 */
+       PCI_SPEED_UNKNOWN,              /* 6 */
+       PCI_SPEED_UNKNOWN,              /* 7 */
+       PCI_SPEED_UNKNOWN,              /* 8 */
+       PCI_SPEED_UNKNOWN,              /* 9 */
+       PCI_SPEED_UNKNOWN,              /* A */
+       PCI_SPEED_UNKNOWN,              /* B */
+       PCI_SPEED_UNKNOWN,              /* C */
+       PCI_SPEED_UNKNOWN,              /* D */
+       PCI_SPEED_UNKNOWN,              /* E */
+       PCI_SPEED_UNKNOWN               /* F */
+};
+
+void pcie_update_link_speed(struct pci_bus *bus, u16 linksta)
+{
+       bus->cur_bus_speed = pcie_link_speed[linksta & 0xf];
+}
+EXPORT_SYMBOL_GPL(pcie_update_link_speed);
+
 static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
                                           struct pci_dev *bridge, int busnr)
 {
@@ -683,7 +708,7 @@ static void pci_read_irq(struct pci_dev *dev)
        dev->irq = irq;
 }
 
-static void set_pcie_port_type(struct pci_dev *pdev)
+void set_pcie_port_type(struct pci_dev *pdev)
 {
        int pos;
        u16 reg16;
@@ -697,13 +722,13 @@ static void set_pcie_port_type(struct pci_dev *pdev)
        pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
 }
 
-static void set_pcie_hotplug_bridge(struct pci_dev *pdev)
+void set_pcie_hotplug_bridge(struct pci_dev *pdev)
 {
        int pos;
        u16 reg16;
        u32 reg32;
 
-       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       pos = pci_pcie_cap(pdev);
        if (!pos)
                return;
        pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
@@ -920,7 +945,7 @@ int pci_cfg_space_size(struct pci_dev *dev)
        if (class == PCI_CLASS_BRIDGE_HOST)
                return pci_cfg_space_size_ext(dev);
 
-       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+       pos = pci_pcie_cap(dev);
        if (!pos) {
                pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
                if (!pos)
@@ -1029,8 +1054,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
        pci_iov_init(dev);
 
        /* Enable ACS P2P upstream forwarding */
-       if (iommu_found() || xen_initial_domain())
-               pci_enable_acs(dev);
+       pci_enable_acs(dev);
 }
 
 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
@@ -1084,6 +1108,37 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
 }
 EXPORT_SYMBOL(pci_scan_single_device);
 
+static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn)
+{
+       u16 cap;
+       unsigned pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
+       if (!pos)
+               return 0;
+       pci_read_config_word(dev, pos + 4, &cap);
+       return cap >> 8;
+}
+
+static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
+{
+       return (fn + 1) % 8;
+}
+
+static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
+{
+       return 0;
+}
+
+static int only_one_child(struct pci_bus *bus)
+{
+       struct pci_dev *parent = bus->self;
+       if (!parent || !pci_is_pcie(parent))
+               return 0;
+       if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
+           parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
+               return 1;
+       return 0;
+}
+
 /**
  * pci_scan_slot - scan a PCI slot on a bus for devices.
  * @bus: PCI bus to scan
@@ -1097,21 +1152,28 @@ EXPORT_SYMBOL(pci_scan_single_device);
  */
 int pci_scan_slot(struct pci_bus *bus, int devfn)
 {
-       int fn, nr = 0;
+       unsigned fn, nr = 0;
        struct pci_dev *dev;
+       unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;
+
+       if (only_one_child(bus) && (devfn > 0))
+               return 0; /* Already scanned the entire slot */
 
        dev = pci_scan_single_device(bus, devfn);
        if (dev && !dev->is_added)      /* new device? */
                nr++;
 
-       if (dev && dev->multifunction) {
-               for (fn = 1; fn < 8; fn++) {
-                       dev = pci_scan_single_device(bus, devfn + fn);
-                       if (dev) {
-                               if (!dev->is_added)
-                                       nr++;
-                               dev->multifunction = 1;
-                       }
+       if (pci_ari_enabled(bus))
+               next_fn = next_ari_fn;
+       else if (dev && dev->multifunction)
+               next_fn = next_trad_fn;
+
+       for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
+               dev = pci_scan_single_device(bus, devfn + fn);
+               if (dev) {
+                       if (!dev->is_added)
+                               nr++;
+                       dev->multifunction = 1;
                }
        }