aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/search.c')
-rw-r--r--drivers/pci/search.c62
1 files changed, 45 insertions, 17 deletions
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 2f13eba5d5a..fab381ed853 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -193,6 +193,18 @@ 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(list_empty(&pci_devices))) {
+ printk(KERN_INFO "pci_find_subsys() called while pci_devices "
+ "is still empty\n");
+ return NULL;
+ }
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
@@ -259,6 +271,18 @@ 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(list_empty(&pci_devices))) {
+ printk(KERN_NOTICE "pci_get_subsys() called while pci_devices "
+ "is still empty\n");
+ return NULL;
+ }
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
@@ -413,6 +437,24 @@ exit:
return dev;
}
+const struct pci_device_id *pci_find_present(const struct pci_device_id *ids)
+{
+ struct pci_dev *dev;
+ 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 ((found = pci_match_one_device(ids, dev)) != NULL)
+ break;
+ }
+ ids++;
+ }
+ 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
@@ -426,25 +468,11 @@ exit:
*/
int pci_dev_present(const struct pci_device_id *ids)
{
- struct pci_dev *dev;
- int found = 0;
-
- 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;
- goto exit;
- }
- }
- ids++;
- }
-exit:
- up_read(&pci_bus_sem);
- return found;
+ return pci_find_present(ids) == NULL ? 0 : 1;
}
+
EXPORT_SYMBOL(pci_dev_present);
+EXPORT_SYMBOL(pci_find_present);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_device_reverse);