]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/pci/search.c
Merge branch 'fixes' of git://ftp.arm.linux.org.uk/~rmk/linux-arm
[karo-tx-linux.git] / drivers / pci / search.c
index 8e495bda678f2e0e9a927ac993c27da8f585e37a..827ad831f1dd67335cf3918ed960f81579fc8405 100644 (file)
 DECLARE_RWSEM(pci_bus_sem);
 EXPORT_SYMBOL_GPL(pci_bus_sem);
 
+/*
+ * pci_for_each_dma_alias - Iterate over DMA aliases for a device
+ * @pdev: starting downstream device
+ * @fn: function to call for each alias
+ * @data: opaque data to pass to @fn
+ *
+ * Starting @pdev, walk up the bus calling @fn for each possible alias
+ * of @pdev at the root bus.
+ */
+int pci_for_each_dma_alias(struct pci_dev *pdev,
+                          int (*fn)(struct pci_dev *pdev,
+                                    u16 alias, void *data), void *data)
+{
+       struct pci_bus *bus;
+       int ret;
+
+       ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data);
+       if (ret)
+               return ret;
+
+       /*
+        * If the device is broken and uses an alias requester ID for
+        * DMA, iterate over that too.
+        */
+       if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) {
+               ret = fn(pdev, PCI_DEVID(pdev->bus->number,
+                                        pdev->dma_alias_devfn), data);
+               if (ret)
+                       return ret;
+       }
+
+       for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
+               struct pci_dev *tmp;
+
+               /* Skip virtual buses */
+               if (!bus->self)
+                       continue;
+
+               tmp = bus->self;
+
+               /*
+                * PCIe-to-PCI/X bridges alias transactions from downstream
+                * devices using the subordinate bus number (PCI Express to
+                * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3).  For all cases
+                * where the upstream bus is PCI/X we alias to the bridge
+                * (there are various conditions in the previous reference
+                * where the bridge may take ownership of transactions, even
+                * when the secondary interface is PCI-X).
+                */
+               if (pci_is_pcie(tmp)) {
+                       switch (pci_pcie_type(tmp)) {
+                       case PCI_EXP_TYPE_ROOT_PORT:
+                       case PCI_EXP_TYPE_UPSTREAM:
+                       case PCI_EXP_TYPE_DOWNSTREAM:
+                               continue;
+                       case PCI_EXP_TYPE_PCI_BRIDGE:
+                               ret = fn(tmp,
+                                        PCI_DEVID(tmp->subordinate->number,
+                                                  PCI_DEVFN(0, 0)), data);
+                               if (ret)
+                                       return ret;
+                               continue;
+                       case PCI_EXP_TYPE_PCIE_BRIDGE:
+                               ret = fn(tmp,
+                                        PCI_DEVID(tmp->bus->number,
+                                                  tmp->devfn), data);
+                               if (ret)
+                                       return ret;
+                               continue;
+                       }
+               } else {
+                       if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS)
+                               ret = fn(tmp,
+                                        PCI_DEVID(tmp->subordinate->number,
+                                                  PCI_DEVFN(0, 0)), data);
+                       else
+                               ret = fn(tmp,
+                                        PCI_DEVID(tmp->bus->number,
+                                                  tmp->devfn), data);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return ret;
+}
+
 /*
  * find the upstream PCIe-to-PCI bridge of a PCI device
  * if the device is PCIE, return NULL
@@ -23,8 +110,7 @@ EXPORT_SYMBOL_GPL(pci_bus_sem);
  * legacy PCI bridge and the bridge is directly connected to bus 0), return its
  * parent
  */
-struct pci_dev *
-pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
+struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
 {
        struct pci_dev *tmp = NULL;
 
@@ -56,12 +142,12 @@ static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
        struct pci_bus *child;
        struct pci_bus *tmp;
 
-       if(bus->number == busnr)
+       if (bus->number == busnr)
                return bus;
 
        list_for_each_entry(tmp, &bus->children, node) {
                child = pci_do_find_bus(tmp, busnr);
-               if(child)
+               if (child)
                        return child;
        }
        return NULL;
@@ -76,7 +162,7 @@ static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
  * in the global list of PCI buses.  If the bus is found, a pointer to its
  * data structure is returned.  If no bus is found, %NULL is returned.
  */
-struct pci_bus * pci_find_bus(int domain, int busnr)
+struct pci_bus *pci_find_bus(int domain, int busnr)
 {
        struct pci_bus *bus = NULL;
        struct pci_bus *tmp_bus;
@@ -90,6 +176,7 @@ struct pci_bus * pci_find_bus(int domain, int busnr)
        }
        return NULL;
 }
+EXPORT_SYMBOL(pci_find_bus);
 
 /**
  * pci_find_next_bus - begin or continue searching for a PCI bus
@@ -100,8 +187,7 @@ struct pci_bus * pci_find_bus(int domain, int busnr)
  * @from is not %NULL, searches continue from next device on the
  * global list.
  */
-struct pci_bus *
-pci_find_next_bus(const struct pci_bus *from)
+struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
 {
        struct list_head *n;
        struct pci_bus *b = NULL;
@@ -114,6 +200,7 @@ pci_find_next_bus(const struct pci_bus *from)
        up_read(&pci_bus_sem);
        return b;
 }
+EXPORT_SYMBOL(pci_find_next_bus);
 
 /**
  * pci_get_slot - locate PCI device for a given PCI slot
@@ -147,6 +234,7 @@ struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn)
        up_read(&pci_bus_sem);
        return dev;
 }
+EXPORT_SYMBOL(pci_get_slot);
 
 /**
  * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot
@@ -251,6 +339,7 @@ struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
 
        return pci_get_dev_by_id(&id, from);
 }
+EXPORT_SYMBOL(pci_get_subsys);
 
 /**
  * pci_get_device - begin or continue searching for a PCI device by vendor/device id
@@ -266,11 +355,12 @@ struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
  * from next device on the global list.  The reference count for @from is
  * always decremented if it is not %NULL.
  */
-struct pci_dev *
-pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
+struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
+                              struct pci_dev *from)
 {
        return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
 }
+EXPORT_SYMBOL(pci_get_device);
 
 /**
  * pci_get_class - begin or continue searching for a PCI device by class
@@ -299,6 +389,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
 
        return pci_get_dev_by_id(&id, from);
 }
+EXPORT_SYMBOL(pci_get_class);
 
 /**
  * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
@@ -328,12 +419,3 @@ int pci_dev_present(const struct pci_device_id *ids)
        return 0;
 }
 EXPORT_SYMBOL(pci_dev_present);
-
-/* For boot time work */
-EXPORT_SYMBOL(pci_find_bus);
-EXPORT_SYMBOL(pci_find_next_bus);
-/* For everyone */
-EXPORT_SYMBOL(pci_get_device);
-EXPORT_SYMBOL(pci_get_subsys);
-EXPORT_SYMBOL(pci_get_slot);
-EXPORT_SYMBOL(pci_get_class);