xref: /openbmc/linux/drivers/pci/search.c (revision 0db00e5d86dc793aab9722ad3728d99166eb7d96)
17328c8f4SBjorn Helgaas // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3df62ab5eSBjorn Helgaas  * PCI searching functions
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 1993 -- 1997 Drew Eckhardt, Frederic Potter,
61da177e4SLinus Torvalds  *					David Mosberger-Tang
71da177e4SLinus Torvalds  * Copyright (C) 1997 -- 2000 Martin Mares <mj@ucw.cz>
81da177e4SLinus Torvalds  * Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com>
91da177e4SLinus Torvalds  */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include <linux/pci.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/interrupt.h>
151da177e4SLinus Torvalds #include "pci.h"
161da177e4SLinus Torvalds 
17d71374daSZhang Yanmin DECLARE_RWSEM(pci_bus_sem);
18ce29ca3eSAmos Kong 
19994a65e2SKeshavamurthy, Anil S /*
20c25dc828SAlex Williamson  * pci_for_each_dma_alias - Iterate over DMA aliases for a device
21c25dc828SAlex Williamson  * @pdev: starting downstream device
22c25dc828SAlex Williamson  * @fn: function to call for each alias
23c25dc828SAlex Williamson  * @data: opaque data to pass to @fn
24c25dc828SAlex Williamson  *
25c25dc828SAlex Williamson  * Starting @pdev, walk up the bus calling @fn for each possible alias
26c25dc828SAlex Williamson  * of @pdev at the root bus.
27c25dc828SAlex Williamson  */
pci_for_each_dma_alias(struct pci_dev * pdev,int (* fn)(struct pci_dev * pdev,u16 alias,void * data),void * data)28c25dc828SAlex Williamson int pci_for_each_dma_alias(struct pci_dev *pdev,
29c25dc828SAlex Williamson 			   int (*fn)(struct pci_dev *pdev,
30c25dc828SAlex Williamson 				     u16 alias, void *data), void *data)
31c25dc828SAlex Williamson {
32c25dc828SAlex Williamson 	struct pci_bus *bus;
33c25dc828SAlex Williamson 	int ret;
34c25dc828SAlex Williamson 
352856ba60SJon Derrick 	/*
362856ba60SJon Derrick 	 * The device may have an explicit alias requester ID for DMA where the
372856ba60SJon Derrick 	 * requester is on another PCI bus.
382856ba60SJon Derrick 	 */
392856ba60SJon Derrick 	pdev = pci_real_dma_dev(pdev);
402856ba60SJon Derrick 
414e544bacSHeiner Kallweit 	ret = fn(pdev, pci_dev_id(pdev), data);
42c25dc828SAlex Williamson 	if (ret)
43c25dc828SAlex Williamson 		return ret;
44c25dc828SAlex Williamson 
4531c2b815SAlex Williamson 	/*
4631c2b815SAlex Williamson 	 * If the device is broken and uses an alias requester ID for
4731c2b815SAlex Williamson 	 * DMA, iterate over that too.
4831c2b815SAlex Williamson 	 */
49338c3149SJacek Lawrynowicz 	if (unlikely(pdev->dma_alias_mask)) {
50f8bf2aebSJames Sewart 		unsigned int devfn;
51338c3149SJacek Lawrynowicz 
52f8bf2aebSJames Sewart 		for_each_set_bit(devfn, pdev->dma_alias_mask, MAX_NR_DEVFNS) {
53338c3149SJacek Lawrynowicz 			ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn),
54338c3149SJacek Lawrynowicz 				 data);
5531c2b815SAlex Williamson 			if (ret)
5631c2b815SAlex Williamson 				return ret;
5731c2b815SAlex Williamson 		}
58338c3149SJacek Lawrynowicz 	}
5931c2b815SAlex Williamson 
60c25dc828SAlex Williamson 	for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
61c25dc828SAlex Williamson 		struct pci_dev *tmp;
62c25dc828SAlex Williamson 
63c25dc828SAlex Williamson 		/* Skip virtual buses */
64c25dc828SAlex Williamson 		if (!bus->self)
65c25dc828SAlex Williamson 			continue;
66c25dc828SAlex Williamson 
67c25dc828SAlex Williamson 		tmp = bus->self;
68c25dc828SAlex Williamson 
69ffff8858SJayachandran C 		/* stop at bridge where translation unit is associated */
70ffff8858SJayachandran C 		if (tmp->dev_flags & PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT)
71ffff8858SJayachandran C 			return ret;
72ffff8858SJayachandran C 
73c25dc828SAlex Williamson 		/*
74c25dc828SAlex Williamson 		 * PCIe-to-PCI/X bridges alias transactions from downstream
75c25dc828SAlex Williamson 		 * devices using the subordinate bus number (PCI Express to
76c25dc828SAlex Williamson 		 * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3).  For all cases
77c25dc828SAlex Williamson 		 * where the upstream bus is PCI/X we alias to the bridge
78c25dc828SAlex Williamson 		 * (there are various conditions in the previous reference
79c25dc828SAlex Williamson 		 * where the bridge may take ownership of transactions, even
80c25dc828SAlex Williamson 		 * when the secondary interface is PCI-X).
81c25dc828SAlex Williamson 		 */
82c25dc828SAlex Williamson 		if (pci_is_pcie(tmp)) {
83c25dc828SAlex Williamson 			switch (pci_pcie_type(tmp)) {
84c25dc828SAlex Williamson 			case PCI_EXP_TYPE_ROOT_PORT:
85c25dc828SAlex Williamson 			case PCI_EXP_TYPE_UPSTREAM:
86c25dc828SAlex Williamson 			case PCI_EXP_TYPE_DOWNSTREAM:
87c25dc828SAlex Williamson 				continue;
88c25dc828SAlex Williamson 			case PCI_EXP_TYPE_PCI_BRIDGE:
89c25dc828SAlex Williamson 				ret = fn(tmp,
90c25dc828SAlex Williamson 					 PCI_DEVID(tmp->subordinate->number,
91c25dc828SAlex Williamson 						   PCI_DEVFN(0, 0)), data);
92c25dc828SAlex Williamson 				if (ret)
93c25dc828SAlex Williamson 					return ret;
94c25dc828SAlex Williamson 				continue;
95c25dc828SAlex Williamson 			case PCI_EXP_TYPE_PCIE_BRIDGE:
964e544bacSHeiner Kallweit 				ret = fn(tmp, pci_dev_id(tmp), data);
97c25dc828SAlex Williamson 				if (ret)
98c25dc828SAlex Williamson 					return ret;
99c25dc828SAlex Williamson 				continue;
100c25dc828SAlex Williamson 			}
101c25dc828SAlex Williamson 		} else {
102c8fe16e3SAlex Williamson 			if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS)
103c8fe16e3SAlex Williamson 				ret = fn(tmp,
104c8fe16e3SAlex Williamson 					 PCI_DEVID(tmp->subordinate->number,
105c8fe16e3SAlex Williamson 						   PCI_DEVFN(0, 0)), data);
106c8fe16e3SAlex Williamson 			else
1074e544bacSHeiner Kallweit 				ret = fn(tmp, pci_dev_id(tmp), data);
108c25dc828SAlex Williamson 			if (ret)
109c25dc828SAlex Williamson 				return ret;
110c25dc828SAlex Williamson 		}
111c25dc828SAlex Williamson 	}
112c25dc828SAlex Williamson 
113c25dc828SAlex Williamson 	return ret;
114c25dc828SAlex Williamson }
115c25dc828SAlex Williamson 
pci_do_find_bus(struct pci_bus * bus,unsigned char busnr)11696bde06aSSam Ravnborg static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
1171da177e4SLinus Torvalds {
1181da177e4SLinus Torvalds 	struct pci_bus *child;
11994e6a9b9SYijing Wang 	struct pci_bus *tmp;
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	if (bus->number == busnr)
1221da177e4SLinus Torvalds 		return bus;
1231da177e4SLinus Torvalds 
12494e6a9b9SYijing Wang 	list_for_each_entry(tmp, &bus->children, node) {
12594e6a9b9SYijing Wang 		child = pci_do_find_bus(tmp, busnr);
1261da177e4SLinus Torvalds 		if (child)
1271da177e4SLinus Torvalds 			return child;
1281da177e4SLinus Torvalds 	}
1291da177e4SLinus Torvalds 	return NULL;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds /**
1331da177e4SLinus Torvalds  * pci_find_bus - locate PCI bus from a given domain and bus number
1341da177e4SLinus Torvalds  * @domain: number of PCI domain to search
1351da177e4SLinus Torvalds  * @busnr: number of desired PCI bus
1361da177e4SLinus Torvalds  *
1371da177e4SLinus Torvalds  * Given a PCI bus number and domain number, the desired PCI bus is located
1381da177e4SLinus Torvalds  * in the global list of PCI buses.  If the bus is found, a pointer to its
1391da177e4SLinus Torvalds  * data structure is returned.  If no bus is found, %NULL is returned.
1401da177e4SLinus Torvalds  */
pci_find_bus(int domain,int busnr)141c8439cfcSRandy Dunlap struct pci_bus *pci_find_bus(int domain, int busnr)
1421da177e4SLinus Torvalds {
1431da177e4SLinus Torvalds 	struct pci_bus *bus = NULL;
1441da177e4SLinus Torvalds 	struct pci_bus *tmp_bus;
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds 	while ((bus = pci_find_next_bus(bus)) != NULL)  {
1471da177e4SLinus Torvalds 		if (pci_domain_nr(bus) != domain)
1481da177e4SLinus Torvalds 			continue;
1491da177e4SLinus Torvalds 		tmp_bus = pci_do_find_bus(bus, busnr);
1501da177e4SLinus Torvalds 		if (tmp_bus)
1511da177e4SLinus Torvalds 			return tmp_bus;
1521da177e4SLinus Torvalds 	}
1531da177e4SLinus Torvalds 	return NULL;
1541da177e4SLinus Torvalds }
155b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_find_bus);
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /**
1581da177e4SLinus Torvalds  * pci_find_next_bus - begin or continue searching for a PCI bus
1591da177e4SLinus Torvalds  * @from: Previous PCI bus found, or %NULL for new search.
1601da177e4SLinus Torvalds  *
161f7625980SBjorn Helgaas  * Iterates through the list of known PCI buses.  A new search is
162d75763d2SRandy Dunlap  * initiated by passing %NULL as the @from argument.  Otherwise if
1631da177e4SLinus Torvalds  * @from is not %NULL, searches continue from next device on the
1641da177e4SLinus Torvalds  * global list.
1651da177e4SLinus Torvalds  */
pci_find_next_bus(const struct pci_bus * from)1663c78bc61SRyan Desfosses struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
1671da177e4SLinus Torvalds {
1681da177e4SLinus Torvalds 	struct list_head *n;
1691da177e4SLinus Torvalds 	struct pci_bus *b = NULL;
1701da177e4SLinus Torvalds 
171d71374daSZhang Yanmin 	down_read(&pci_bus_sem);
1721da177e4SLinus Torvalds 	n = from ? from->node.next : pci_root_buses.next;
1731da177e4SLinus Torvalds 	if (n != &pci_root_buses)
17494e6a9b9SYijing Wang 		b = list_entry(n, struct pci_bus, node);
175d71374daSZhang Yanmin 	up_read(&pci_bus_sem);
1761da177e4SLinus Torvalds 	return b;
1771da177e4SLinus Torvalds }
178b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_find_next_bus);
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds /**
1811da177e4SLinus Torvalds  * pci_get_slot - locate PCI device for a given PCI slot
1821da177e4SLinus Torvalds  * @bus: PCI bus on which desired PCI device resides
1831da177e4SLinus Torvalds  * @devfn: encodes number of PCI slot in which the desired PCI
1841da177e4SLinus Torvalds  * device resides and the logical device number within that slot
1851da177e4SLinus Torvalds  * in case of multi-function devices.
1861da177e4SLinus Torvalds  *
1871da177e4SLinus Torvalds  * Given a PCI bus and slot/function number, the desired PCI device
1881da177e4SLinus Torvalds  * is located in the list of PCI devices.
1891da177e4SLinus Torvalds  * If the device is found, its reference count is increased and this
1901da177e4SLinus Torvalds  * function returns a pointer to its data structure.  The caller must
1911da177e4SLinus Torvalds  * decrement the reference count by calling pci_dev_put().
1921da177e4SLinus Torvalds  * If no device is found, %NULL is returned.
1931da177e4SLinus Torvalds  */
pci_get_slot(struct pci_bus * bus,unsigned int devfn)1941da177e4SLinus Torvalds struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	struct pci_dev *dev;
1971da177e4SLinus Torvalds 
198d71374daSZhang Yanmin 	down_read(&pci_bus_sem);
1991da177e4SLinus Torvalds 
20066455f54SBjorn Helgaas 	list_for_each_entry(dev, &bus->devices, bus_list) {
2011da177e4SLinus Torvalds 		if (dev->devfn == devfn)
2021da177e4SLinus Torvalds 			goto out;
2031da177e4SLinus Torvalds 	}
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	dev = NULL;
2061da177e4SLinus Torvalds  out:
2071da177e4SLinus Torvalds 	pci_dev_get(dev);
208d71374daSZhang Yanmin 	up_read(&pci_bus_sem);
2091da177e4SLinus Torvalds 	return dev;
2101da177e4SLinus Torvalds }
211b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_get_slot);
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds /**
2143c299dc2SAndrew Patterson  * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot
2153c299dc2SAndrew Patterson  * @domain: PCI domain/segment on which the PCI device resides.
2163c299dc2SAndrew Patterson  * @bus: PCI bus on which desired PCI device resides
2173c299dc2SAndrew Patterson  * @devfn: encodes number of PCI slot in which the desired PCI device
2183c299dc2SAndrew Patterson  * resides and the logical device number within that slot in case of
2193c299dc2SAndrew Patterson  * multi-function devices.
22029f3eb64SAlan Cox  *
2213c299dc2SAndrew Patterson  * Given a PCI domain, bus, and slot/function number, the desired PCI
2223c299dc2SAndrew Patterson  * device is located in the list of PCI devices. If the device is
2233c299dc2SAndrew Patterson  * found, its reference count is increased and this function returns a
2243c299dc2SAndrew Patterson  * pointer to its data structure.  The caller must decrement the
2253c299dc2SAndrew Patterson  * reference count by calling pci_dev_put().  If no device is found,
2263c299dc2SAndrew Patterson  * %NULL is returned.
22729f3eb64SAlan Cox  */
pci_get_domain_bus_and_slot(int domain,unsigned int bus,unsigned int devfn)2283c299dc2SAndrew Patterson struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
2293c299dc2SAndrew Patterson 					    unsigned int devfn)
23029f3eb64SAlan Cox {
23129f3eb64SAlan Cox 	struct pci_dev *dev = NULL;
23229f3eb64SAlan Cox 
2334e344b1cSKulikov Vasiliy 	for_each_pci_dev(dev) {
2343c299dc2SAndrew Patterson 		if (pci_domain_nr(dev->bus) == domain &&
2355463d9f0SRandy Dunlap 		    (dev->bus->number == bus && dev->devfn == devfn))
23629f3eb64SAlan Cox 			return dev;
23729f3eb64SAlan Cox 	}
23829f3eb64SAlan Cox 	return NULL;
23929f3eb64SAlan Cox }
2403c299dc2SAndrew Patterson EXPORT_SYMBOL(pci_get_domain_bus_and_slot);
24129f3eb64SAlan Cox 
match_pci_dev_by_id(struct device * dev,const void * data)242418e3ea1SSuzuki K Poulose static int match_pci_dev_by_id(struct device *dev, const void *data)
2431da177e4SLinus Torvalds {
24495247b57SGreg Kroah-Hartman 	struct pci_dev *pdev = to_pci_dev(dev);
245418e3ea1SSuzuki K Poulose 	const struct pci_device_id *id = data;
2461da177e4SLinus Torvalds 
24795247b57SGreg Kroah-Hartman 	if (pci_match_one_device(id, pdev))
24895247b57SGreg Kroah-Hartman 		return 1;
24995247b57SGreg Kroah-Hartman 	return 0;
25095247b57SGreg Kroah-Hartman }
2516ae4adf5SArd van Breemen 
2526ae4adf5SArd van Breemen /*
25395247b57SGreg Kroah-Hartman  * pci_get_dev_by_id - begin or continue searching for a PCI device by id
25495247b57SGreg Kroah-Hartman  * @id: pointer to struct pci_device_id to match for the device
2551da177e4SLinus Torvalds  * @from: Previous PCI device found in search, or %NULL for new search.
2561da177e4SLinus Torvalds  *
257d75763d2SRandy Dunlap  * Iterates through the list of known PCI devices.  If a PCI device is found
25895247b57SGreg Kroah-Hartman  * with a matching id a pointer to its device structure is returned, and the
25995247b57SGreg Kroah-Hartman  * reference count to the device is incremented.  Otherwise, %NULL is returned.
26095247b57SGreg Kroah-Hartman  * A new search is initiated by passing %NULL as the @from argument.  Otherwise
26195247b57SGreg Kroah-Hartman  * if @from is not %NULL, searches continue from next device on the global
26295247b57SGreg Kroah-Hartman  * list.  The reference count for @from is always decremented if it is not
26395247b57SGreg Kroah-Hartman  * %NULL.
2641da177e4SLinus Torvalds  *
26595247b57SGreg Kroah-Hartman  * This is an internal function for use by the other search functions in
26695247b57SGreg Kroah-Hartman  * this file.
2671da177e4SLinus Torvalds  */
pci_get_dev_by_id(const struct pci_device_id * id,struct pci_dev * from)26895247b57SGreg Kroah-Hartman static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
269b08508c4SGreg KH 					 struct pci_dev *from)
2701da177e4SLinus Torvalds {
27195247b57SGreg Kroah-Hartman 	struct device *dev;
27295247b57SGreg Kroah-Hartman 	struct device *dev_start = NULL;
27395247b57SGreg Kroah-Hartman 	struct pci_dev *pdev = NULL;
27495247b57SGreg Kroah-Hartman 
275c4ed02faSMatthew Wilcox 	if (from)
276c4ed02faSMatthew Wilcox 		dev_start = &from->dev;
27795247b57SGreg Kroah-Hartman 	dev = bus_find_device(&pci_bus_type, dev_start, (void *)id,
27895247b57SGreg Kroah-Hartman 			      match_pci_dev_by_id);
27995247b57SGreg Kroah-Hartman 	if (dev)
28095247b57SGreg Kroah-Hartman 		pdev = to_pci_dev(dev);
281ebca4f1bSGreg KH 	pci_dev_put(from);
28295247b57SGreg Kroah-Hartman 	return pdev;
28395247b57SGreg Kroah-Hartman }
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds /**
2861da177e4SLinus Torvalds  * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
2871da177e4SLinus Torvalds  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
2881da177e4SLinus Torvalds  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
2891da177e4SLinus Torvalds  * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
2901da177e4SLinus Torvalds  * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
2911da177e4SLinus Torvalds  * @from: Previous PCI device found in search, or %NULL for new search.
2921da177e4SLinus Torvalds  *
293d75763d2SRandy Dunlap  * Iterates through the list of known PCI devices.  If a PCI device is found
294d75763d2SRandy Dunlap  * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
2951da177e4SLinus Torvalds  * device structure is returned, and the reference count to the device is
2961da177e4SLinus Torvalds  * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
297d75763d2SRandy Dunlap  * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
2981da177e4SLinus Torvalds  * searches continue from next device on the global list.
2991da177e4SLinus Torvalds  * The reference count for @from is always decremented if it is not %NULL.
3001da177e4SLinus Torvalds  */
pci_get_subsys(unsigned int vendor,unsigned int device,unsigned int ss_vendor,unsigned int ss_device,struct pci_dev * from)30195247b57SGreg Kroah-Hartman struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
3021da177e4SLinus Torvalds 			       unsigned int ss_vendor, unsigned int ss_device,
303b08508c4SGreg KH 			       struct pci_dev *from)
3041da177e4SLinus Torvalds {
305b9443f40SFeng Tang 	struct pci_device_id id = {
306b9443f40SFeng Tang 		.vendor = vendor,
307b9443f40SFeng Tang 		.device = device,
308b9443f40SFeng Tang 		.subvendor = ss_vendor,
309b9443f40SFeng Tang 		.subdevice = ss_device,
310b9443f40SFeng Tang 	};
3116ae4adf5SArd van Breemen 
312b9443f40SFeng Tang 	return pci_get_dev_by_id(&id, from);
3131da177e4SLinus Torvalds }
314b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_get_subsys);
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds /**
3171da177e4SLinus Torvalds  * pci_get_device - begin or continue searching for a PCI device by vendor/device id
3181da177e4SLinus Torvalds  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
3191da177e4SLinus Torvalds  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
3201da177e4SLinus Torvalds  * @from: Previous PCI device found in search, or %NULL for new search.
3211da177e4SLinus Torvalds  *
3221da177e4SLinus Torvalds  * Iterates through the list of known PCI devices.  If a PCI device is
3231da177e4SLinus Torvalds  * found with a matching @vendor and @device, the reference count to the
3241da177e4SLinus Torvalds  * device is incremented and a pointer to its device structure is returned.
3251da177e4SLinus Torvalds  * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
326d75763d2SRandy Dunlap  * as the @from argument.  Otherwise if @from is not %NULL, searches continue
3271da177e4SLinus Torvalds  * from next device on the global list.  The reference count for @from is
3281da177e4SLinus Torvalds  * always decremented if it is not %NULL.
3291da177e4SLinus Torvalds  */
pci_get_device(unsigned int vendor,unsigned int device,struct pci_dev * from)3303c78bc61SRyan Desfosses struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
3313c78bc61SRyan Desfosses 			       struct pci_dev *from)
3321da177e4SLinus Torvalds {
3331da177e4SLinus Torvalds 	return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
3341da177e4SLinus Torvalds }
335b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_get_device);
3361da177e4SLinus Torvalds 
33729f3eb64SAlan Cox /**
3381da177e4SLinus Torvalds  * pci_get_class - begin or continue searching for a PCI device by class
3391da177e4SLinus Torvalds  * @class: search for a PCI device with this class designation
3401da177e4SLinus Torvalds  * @from: Previous PCI device found in search, or %NULL for new search.
3411da177e4SLinus Torvalds  *
3421da177e4SLinus Torvalds  * Iterates through the list of known PCI devices.  If a PCI device is
3431da177e4SLinus Torvalds  * found with a matching @class, the reference count to the device is
3441da177e4SLinus Torvalds  * incremented and a pointer to its device structure is returned.
3451da177e4SLinus Torvalds  * Otherwise, %NULL is returned.
346d75763d2SRandy Dunlap  * A new search is initiated by passing %NULL as the @from argument.
3471da177e4SLinus Torvalds  * Otherwise if @from is not %NULL, searches continue from next device
3481da177e4SLinus Torvalds  * on the global list.  The reference count for @from is always decremented
3491da177e4SLinus Torvalds  * if it is not %NULL.
3501da177e4SLinus Torvalds  */
pci_get_class(unsigned int class,struct pci_dev * from)3511da177e4SLinus Torvalds struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
3521da177e4SLinus Torvalds {
353b9443f40SFeng Tang 	struct pci_device_id id = {
354b9443f40SFeng Tang 		.vendor = PCI_ANY_ID,
355b9443f40SFeng Tang 		.device = PCI_ANY_ID,
356b9443f40SFeng Tang 		.subvendor = PCI_ANY_ID,
357b9443f40SFeng Tang 		.subdevice = PCI_ANY_ID,
358b9443f40SFeng Tang 		.class_mask = PCI_ANY_ID,
359b9443f40SFeng Tang 		.class = class,
360b9443f40SFeng Tang 	};
3611da177e4SLinus Torvalds 
362b9443f40SFeng Tang 	return pci_get_dev_by_id(&id, from);
3631da177e4SLinus Torvalds }
364b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_get_class);
3651da177e4SLinus Torvalds 
366448432c4SGreg Kroah-Hartman /**
367*ccab04dcSSui Jingfeng  * pci_get_base_class - searching for a PCI device by matching against the base class code only
368*ccab04dcSSui Jingfeng  * @class: search for a PCI device with this base class code
369*ccab04dcSSui Jingfeng  * @from: Previous PCI device found in search, or %NULL for new search.
370*ccab04dcSSui Jingfeng  *
371*ccab04dcSSui Jingfeng  * Iterates through the list of known PCI devices. If a PCI device is found
372*ccab04dcSSui Jingfeng  * with a matching base class code, the reference count to the device is
373*ccab04dcSSui Jingfeng  * incremented. See pci_match_one_device() to figure out how does this works.
374*ccab04dcSSui Jingfeng  * A new search is initiated by passing %NULL as the @from argument.
375*ccab04dcSSui Jingfeng  * Otherwise if @from is not %NULL, searches continue from next device on the
376*ccab04dcSSui Jingfeng  * global list. The reference count for @from is always decremented if it is
377*ccab04dcSSui Jingfeng  * not %NULL.
378*ccab04dcSSui Jingfeng  *
379*ccab04dcSSui Jingfeng  * Returns:
380*ccab04dcSSui Jingfeng  * A pointer to a matched PCI device, %NULL Otherwise.
381*ccab04dcSSui Jingfeng  */
pci_get_base_class(unsigned int class,struct pci_dev * from)382*ccab04dcSSui Jingfeng struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from)
383*ccab04dcSSui Jingfeng {
384*ccab04dcSSui Jingfeng 	struct pci_device_id id = {
385*ccab04dcSSui Jingfeng 		.vendor = PCI_ANY_ID,
386*ccab04dcSSui Jingfeng 		.device = PCI_ANY_ID,
387*ccab04dcSSui Jingfeng 		.subvendor = PCI_ANY_ID,
388*ccab04dcSSui Jingfeng 		.subdevice = PCI_ANY_ID,
389*ccab04dcSSui Jingfeng 		.class_mask = 0xFF0000,
390*ccab04dcSSui Jingfeng 		.class = class << 16,
391*ccab04dcSSui Jingfeng 	};
392*ccab04dcSSui Jingfeng 
393*ccab04dcSSui Jingfeng 	return pci_get_dev_by_id(&id, from);
394*ccab04dcSSui Jingfeng }
395*ccab04dcSSui Jingfeng EXPORT_SYMBOL(pci_get_base_class);
396*ccab04dcSSui Jingfeng 
397*ccab04dcSSui Jingfeng /**
398448432c4SGreg Kroah-Hartman  * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
399448432c4SGreg Kroah-Hartman  * @ids: A pointer to a null terminated list of struct pci_device_id structures
400448432c4SGreg Kroah-Hartman  * that describe the type of PCI device the caller is trying to find.
401448432c4SGreg Kroah-Hartman  *
402448432c4SGreg Kroah-Hartman  * Obvious fact: You do not have a reference to any device that might be found
403448432c4SGreg Kroah-Hartman  * by this function, so if that device is removed from the system right after
404448432c4SGreg Kroah-Hartman  * this function is finished, the value will be stale.  Use this function to
405448432c4SGreg Kroah-Hartman  * find devices that are usually built into a system, or for a general hint as
406448432c4SGreg Kroah-Hartman  * to if another device happens to be present at this specific moment in time.
407448432c4SGreg Kroah-Hartman  */
pci_dev_present(const struct pci_device_id * ids)408448432c4SGreg Kroah-Hartman int pci_dev_present(const struct pci_device_id *ids)
409d86f90f9SAlan Cox {
41095247b57SGreg Kroah-Hartman 	struct pci_dev *found = NULL;
411d86f90f9SAlan Cox 
412d86f90f9SAlan Cox 	while (ids->vendor || ids->subvendor || ids->class_mask) {
41395247b57SGreg Kroah-Hartman 		found = pci_get_dev_by_id(ids, NULL);
414d5af7d98SJiang Liu 		if (found) {
415d5af7d98SJiang Liu 			pci_dev_put(found);
416d5af7d98SJiang Liu 			return 1;
417d5af7d98SJiang Liu 		}
418d86f90f9SAlan Cox 		ids++;
419d86f90f9SAlan Cox 	}
420d5af7d98SJiang Liu 
421448432c4SGreg Kroah-Hartman 	return 0;
422d86f90f9SAlan Cox }
4231da177e4SLinus Torvalds EXPORT_SYMBOL(pci_dev_present);
424