generic: use new set_cpus_allowed_ptr function
[safe/jmp/linux-2.6] / drivers / pci / search.c
index d529462..8541034 100644 (file)
 #include "pci.h"
 
 DECLARE_RWSEM(pci_bus_sem);
+/*
+ * find the upstream PCIE-to-PCI bridge of a PCI device
+ * if the device is PCIE, return NULL
+ * if the device isn't connected to a PCIE bridge (that is its parent is a
+ * 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 *tmp = NULL;
+
+       if (pdev->is_pcie)
+               return NULL;
+       while (1) {
+               if (!pdev->bus->self)
+                       break;
+               pdev = pdev->bus->self;
+               /* a p2p bridge */
+               if (!pdev->is_pcie) {
+                       tmp = pdev;
+                       continue;
+               }
+               /* PCI device should connect to a PCIE bridge */
+               if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
+                       /* Busted hardware? */
+                       WARN_ON_ONCE(1);
+                       return NULL;
+               }
+               return pdev;
+       }
+
+       return tmp;
+}
 
-static struct pci_bus * __devinit
-pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
+static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
 {
        struct pci_bus* child;
        struct list_head *tmp;
@@ -80,6 +113,8 @@ pci_find_next_bus(const struct pci_bus *from)
        return b;
 }
 
+#ifdef CONFIG_PCI_LEGACY
+
 /**
  * pci_find_slot - locate PCI device from a given PCI slot
  * @bus: number of PCI bus on which desired PCI device resides
@@ -104,6 +139,8 @@ pci_find_slot(unsigned int bus, unsigned int devfn)
        return NULL;
 }
 
+#endif /* CONFIG_PCI_LEGACY */
+
 /**
  * pci_get_slot - locate PCI device for a given PCI slot
  * @bus: PCI bus on which desired PCI device resides
@@ -140,6 +177,35 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
 }
 
 /**
+ * pci_get_bus_and_slot - locate PCI device from a given PCI bus & slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI
+ * device resides and the logical device number within that slot
+ * in case of multi-function devices.
+ *
+ * Note: the bus/slot search is limited to PCI domain (segment) 0.
+ *
+ * Given a PCI bus and slot/function number, the desired PCI device
+ * is located in system global list of PCI devices.  If the device
+ * is found, a pointer to its data structure is returned.  If no
+ * device is found, %NULL is returned. The returned device has its
+ * reference count bumped by one.
+ */
+
+struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
+{
+       struct pci_dev *dev = NULL;
+
+       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+               if (pci_domain_nr(dev->bus) == 0 &&
+                  (dev->bus->number == bus && dev->devfn == devfn))
+                       return dev;
+       }
+       return NULL;
+}
+
+#ifdef CONFIG_PCI_LEGACY
+/**
  * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
@@ -168,6 +234,15 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
        struct pci_dev *dev;
 
        WARN_ON(in_interrupt());
+
+       /*
+        * pci_find_subsys() can be called on the ide_setup() path, super-early
+        * in boot.  But the down_read() will enable local interrupts, which
+        * can cause some machines to crash.  So here we detect and flag that
+        * situation and bail out early.
+        */
+       if (unlikely(no_pci_devices()))
+               return NULL;
        down_read(&pci_bus_sem);
        n = from ? from->global_list.next : pci_devices.next;
 
@@ -208,6 +283,7 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *
 {
        return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
 }
+#endif /* CONFIG_PCI_LEGACY */
 
 /**
  * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
@@ -234,6 +310,15 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
        struct pci_dev *dev;
 
        WARN_ON(in_interrupt());
+
+       /*
+        * pci_get_subsys() can potentially be called by drivers super-early
+        * in boot.  But the down_read() will enable local interrupts, which
+        * can cause some machines to crash.  So here we detect and flag that
+        * situation and bail out early.
+        */
+       if (unlikely(no_pci_devices()))
+               return NULL;
        down_read(&pci_bus_sem);
        n = from ? from->global_list.next : pci_devices.next;
 
@@ -274,23 +359,23 @@ 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);
 }
 
-
 /**
- * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
+ * pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id
  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
  * @from: Previous PCI device found in search, or %NULL for new search.
  *
  * Iterates through the list of known PCI devices in the reverse order of
- * pci_find_device().
- * If a PCI device is found with a matching @vendor and @device, a pointer to
- * its device structure is returned.  Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL as the @from argument.
- * Otherwise if @from is not %NULL, searches continue from previous device
- * on the global list.
+ * pci_get_device.
+ * If a PCI device is found with a matching @vendor and @device, the reference
+ * count to the  device is incremented and a pointer to its device structure
+ * is returned Otherwise, %NULL is returned.  A new search is initiated by
+ * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
+ * searches continue from next device on the global list.  The reference
+ * count for @from is always decremented if it is not %NULL.
  */
 struct pci_dev *
-pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
+pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from)
 {
        struct list_head *n;
        struct pci_dev *dev;
@@ -308,7 +393,9 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p
        }
        dev = NULL;
 exit:
+       dev = pci_dev_get(dev);
        up_read(&pci_bus_sem);
+       pci_dev_put(from);
        return dev;
 }
 
@@ -349,30 +436,17 @@ exit:
        return dev;
 }
 
-/**
- * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
- * @ids: A pointer to a null terminated list of struct pci_device_id structures
- * that describe the type of PCI device the caller is trying to find.
- *
- * Obvious fact: You do not have a reference to any device that might be found
- * by this function, so if that device is removed from the system right after
- * this function is finished, the value will be stale.  Use this function to
- * find devices that are usually built into a system, or for a general hint as
- * to if another device happens to be present at this specific moment in time.
- */
-int pci_dev_present(const struct pci_device_id *ids)
+const struct pci_device_id *pci_find_present(const struct pci_device_id *ids)
 {
        struct pci_dev *dev;
-       int found = 0;
+       const struct pci_device_id *found = NULL;
 
        WARN_ON(in_interrupt());
        down_read(&pci_bus_sem);
        while (ids->vendor || ids->subvendor || ids->class_mask) {
                list_for_each_entry(dev, &pci_devices, global_list) {
-                       if (pci_match_one_device(ids, dev)) {
-                               found = 1;
+                       if ((found = pci_match_one_device(ids, dev)) != NULL)
                                goto exit;
-                       }
                }
                ids++;
        }
@@ -380,14 +454,38 @@ exit:
        up_read(&pci_bus_sem);
        return found;
 }
+
+/**
+ * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
+ * @ids: A pointer to a null terminated list of struct pci_device_id structures
+ * that describe the type of PCI device the caller is trying to find.
+ *
+ * Obvious fact: You do not have a reference to any device that might be found
+ * by this function, so if that device is removed from the system right after
+ * this function is finished, the value will be stale.  Use this function to
+ * find devices that are usually built into a system, or for a general hint as
+ * to if another device happens to be present at this specific moment in time.
+ */
+int pci_dev_present(const struct pci_device_id *ids)
+{
+       return pci_find_present(ids) == NULL ? 0 : 1;
+}
+
 EXPORT_SYMBOL(pci_dev_present);
+EXPORT_SYMBOL(pci_find_present);
 
-EXPORT_SYMBOL(pci_find_bus);
-EXPORT_SYMBOL(pci_find_next_bus);
+#ifdef CONFIG_PCI_LEGACY
 EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_device_reverse);
 EXPORT_SYMBOL(pci_find_slot);
+#endif /* CONFIG_PCI_LEGACY */
+
+/* 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_device_reverse);
 EXPORT_SYMBOL(pci_get_subsys);
 EXPORT_SYMBOL(pci_get_slot);
+EXPORT_SYMBOL(pci_get_bus_and_slot);
 EXPORT_SYMBOL(pci_get_class);