18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCI searching functions
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1993 -- 1997 Drew Eckhardt, Frederic Potter,
68c2ecf20Sopenharmony_ci *					David Mosberger-Tang
78c2ecf20Sopenharmony_ci * Copyright (C) 1997 -- 2000 Martin Mares <mj@ucw.cz>
88c2ecf20Sopenharmony_ci * Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/pci.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include "pci.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciDECLARE_RWSEM(pci_bus_sem);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * pci_for_each_dma_alias - Iterate over DMA aliases for a device
218c2ecf20Sopenharmony_ci * @pdev: starting downstream device
228c2ecf20Sopenharmony_ci * @fn: function to call for each alias
238c2ecf20Sopenharmony_ci * @data: opaque data to pass to @fn
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * Starting @pdev, walk up the bus calling @fn for each possible alias
268c2ecf20Sopenharmony_ci * of @pdev at the root bus.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ciint pci_for_each_dma_alias(struct pci_dev *pdev,
298c2ecf20Sopenharmony_ci			   int (*fn)(struct pci_dev *pdev,
308c2ecf20Sopenharmony_ci				     u16 alias, void *data), void *data)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct pci_bus *bus;
338c2ecf20Sopenharmony_ci	int ret;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/*
368c2ecf20Sopenharmony_ci	 * The device may have an explicit alias requester ID for DMA where the
378c2ecf20Sopenharmony_ci	 * requester is on another PCI bus.
388c2ecf20Sopenharmony_ci	 */
398c2ecf20Sopenharmony_ci	pdev = pci_real_dma_dev(pdev);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	ret = fn(pdev, pci_dev_id(pdev), data);
428c2ecf20Sopenharmony_ci	if (ret)
438c2ecf20Sopenharmony_ci		return ret;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/*
468c2ecf20Sopenharmony_ci	 * If the device is broken and uses an alias requester ID for
478c2ecf20Sopenharmony_ci	 * DMA, iterate over that too.
488c2ecf20Sopenharmony_ci	 */
498c2ecf20Sopenharmony_ci	if (unlikely(pdev->dma_alias_mask)) {
508c2ecf20Sopenharmony_ci		unsigned int devfn;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci		for_each_set_bit(devfn, pdev->dma_alias_mask, MAX_NR_DEVFNS) {
538c2ecf20Sopenharmony_ci			ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn),
548c2ecf20Sopenharmony_ci				 data);
558c2ecf20Sopenharmony_ci			if (ret)
568c2ecf20Sopenharmony_ci				return ret;
578c2ecf20Sopenharmony_ci		}
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
618c2ecf20Sopenharmony_ci		struct pci_dev *tmp;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		/* Skip virtual buses */
648c2ecf20Sopenharmony_ci		if (!bus->self)
658c2ecf20Sopenharmony_ci			continue;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		tmp = bus->self;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		/* stop at bridge where translation unit is associated */
708c2ecf20Sopenharmony_ci		if (tmp->dev_flags & PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT)
718c2ecf20Sopenharmony_ci			return ret;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci		/*
748c2ecf20Sopenharmony_ci		 * PCIe-to-PCI/X bridges alias transactions from downstream
758c2ecf20Sopenharmony_ci		 * devices using the subordinate bus number (PCI Express to
768c2ecf20Sopenharmony_ci		 * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3).  For all cases
778c2ecf20Sopenharmony_ci		 * where the upstream bus is PCI/X we alias to the bridge
788c2ecf20Sopenharmony_ci		 * (there are various conditions in the previous reference
798c2ecf20Sopenharmony_ci		 * where the bridge may take ownership of transactions, even
808c2ecf20Sopenharmony_ci		 * when the secondary interface is PCI-X).
818c2ecf20Sopenharmony_ci		 */
828c2ecf20Sopenharmony_ci		if (pci_is_pcie(tmp)) {
838c2ecf20Sopenharmony_ci			switch (pci_pcie_type(tmp)) {
848c2ecf20Sopenharmony_ci			case PCI_EXP_TYPE_ROOT_PORT:
858c2ecf20Sopenharmony_ci			case PCI_EXP_TYPE_UPSTREAM:
868c2ecf20Sopenharmony_ci			case PCI_EXP_TYPE_DOWNSTREAM:
878c2ecf20Sopenharmony_ci				continue;
888c2ecf20Sopenharmony_ci			case PCI_EXP_TYPE_PCI_BRIDGE:
898c2ecf20Sopenharmony_ci				ret = fn(tmp,
908c2ecf20Sopenharmony_ci					 PCI_DEVID(tmp->subordinate->number,
918c2ecf20Sopenharmony_ci						   PCI_DEVFN(0, 0)), data);
928c2ecf20Sopenharmony_ci				if (ret)
938c2ecf20Sopenharmony_ci					return ret;
948c2ecf20Sopenharmony_ci				continue;
958c2ecf20Sopenharmony_ci			case PCI_EXP_TYPE_PCIE_BRIDGE:
968c2ecf20Sopenharmony_ci				ret = fn(tmp, pci_dev_id(tmp), data);
978c2ecf20Sopenharmony_ci				if (ret)
988c2ecf20Sopenharmony_ci					return ret;
998c2ecf20Sopenharmony_ci				continue;
1008c2ecf20Sopenharmony_ci			}
1018c2ecf20Sopenharmony_ci		} else {
1028c2ecf20Sopenharmony_ci			if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS)
1038c2ecf20Sopenharmony_ci				ret = fn(tmp,
1048c2ecf20Sopenharmony_ci					 PCI_DEVID(tmp->subordinate->number,
1058c2ecf20Sopenharmony_ci						   PCI_DEVFN(0, 0)), data);
1068c2ecf20Sopenharmony_ci			else
1078c2ecf20Sopenharmony_ci				ret = fn(tmp, pci_dev_id(tmp), data);
1088c2ecf20Sopenharmony_ci			if (ret)
1098c2ecf20Sopenharmony_ci				return ret;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return ret;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct pci_bus *child;
1198c2ecf20Sopenharmony_ci	struct pci_bus *tmp;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (bus->number == busnr)
1228c2ecf20Sopenharmony_ci		return bus;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &bus->children, node) {
1258c2ecf20Sopenharmony_ci		child = pci_do_find_bus(tmp, busnr);
1268c2ecf20Sopenharmony_ci		if (child)
1278c2ecf20Sopenharmony_ci			return child;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci	return NULL;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/**
1338c2ecf20Sopenharmony_ci * pci_find_bus - locate PCI bus from a given domain and bus number
1348c2ecf20Sopenharmony_ci * @domain: number of PCI domain to search
1358c2ecf20Sopenharmony_ci * @busnr: number of desired PCI bus
1368c2ecf20Sopenharmony_ci *
1378c2ecf20Sopenharmony_ci * Given a PCI bus number and domain number, the desired PCI bus is located
1388c2ecf20Sopenharmony_ci * in the global list of PCI buses.  If the bus is found, a pointer to its
1398c2ecf20Sopenharmony_ci * data structure is returned.  If no bus is found, %NULL is returned.
1408c2ecf20Sopenharmony_ci */
1418c2ecf20Sopenharmony_cistruct pci_bus *pci_find_bus(int domain, int busnr)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct pci_bus *bus = NULL;
1448c2ecf20Sopenharmony_ci	struct pci_bus *tmp_bus;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	while ((bus = pci_find_next_bus(bus)) != NULL)  {
1478c2ecf20Sopenharmony_ci		if (pci_domain_nr(bus) != domain)
1488c2ecf20Sopenharmony_ci			continue;
1498c2ecf20Sopenharmony_ci		tmp_bus = pci_do_find_bus(bus, busnr);
1508c2ecf20Sopenharmony_ci		if (tmp_bus)
1518c2ecf20Sopenharmony_ci			return tmp_bus;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci	return NULL;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_find_bus);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/**
1588c2ecf20Sopenharmony_ci * pci_find_next_bus - begin or continue searching for a PCI bus
1598c2ecf20Sopenharmony_ci * @from: Previous PCI bus found, or %NULL for new search.
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci * Iterates through the list of known PCI buses.  A new search is
1628c2ecf20Sopenharmony_ci * initiated by passing %NULL as the @from argument.  Otherwise if
1638c2ecf20Sopenharmony_ci * @from is not %NULL, searches continue from next device on the
1648c2ecf20Sopenharmony_ci * global list.
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_cistruct pci_bus *pci_find_next_bus(const struct pci_bus *from)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct list_head *n;
1698c2ecf20Sopenharmony_ci	struct pci_bus *b = NULL;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	WARN_ON(in_interrupt());
1728c2ecf20Sopenharmony_ci	down_read(&pci_bus_sem);
1738c2ecf20Sopenharmony_ci	n = from ? from->node.next : pci_root_buses.next;
1748c2ecf20Sopenharmony_ci	if (n != &pci_root_buses)
1758c2ecf20Sopenharmony_ci		b = list_entry(n, struct pci_bus, node);
1768c2ecf20Sopenharmony_ci	up_read(&pci_bus_sem);
1778c2ecf20Sopenharmony_ci	return b;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_find_next_bus);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/**
1828c2ecf20Sopenharmony_ci * pci_get_slot - locate PCI device for a given PCI slot
1838c2ecf20Sopenharmony_ci * @bus: PCI bus on which desired PCI device resides
1848c2ecf20Sopenharmony_ci * @devfn: encodes number of PCI slot in which the desired PCI
1858c2ecf20Sopenharmony_ci * device resides and the logical device number within that slot
1868c2ecf20Sopenharmony_ci * in case of multi-function devices.
1878c2ecf20Sopenharmony_ci *
1888c2ecf20Sopenharmony_ci * Given a PCI bus and slot/function number, the desired PCI device
1898c2ecf20Sopenharmony_ci * is located in the list of PCI devices.
1908c2ecf20Sopenharmony_ci * If the device is found, its reference count is increased and this
1918c2ecf20Sopenharmony_ci * function returns a pointer to its data structure.  The caller must
1928c2ecf20Sopenharmony_ci * decrement the reference count by calling pci_dev_put().
1938c2ecf20Sopenharmony_ci * If no device is found, %NULL is returned.
1948c2ecf20Sopenharmony_ci */
1958c2ecf20Sopenharmony_cistruct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct pci_dev *dev;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	WARN_ON(in_interrupt());
2008c2ecf20Sopenharmony_ci	down_read(&pci_bus_sem);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
2038c2ecf20Sopenharmony_ci		if (dev->devfn == devfn)
2048c2ecf20Sopenharmony_ci			goto out;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	dev = NULL;
2088c2ecf20Sopenharmony_ci out:
2098c2ecf20Sopenharmony_ci	pci_dev_get(dev);
2108c2ecf20Sopenharmony_ci	up_read(&pci_bus_sem);
2118c2ecf20Sopenharmony_ci	return dev;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_get_slot);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/**
2168c2ecf20Sopenharmony_ci * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot
2178c2ecf20Sopenharmony_ci * @domain: PCI domain/segment on which the PCI device resides.
2188c2ecf20Sopenharmony_ci * @bus: PCI bus on which desired PCI device resides
2198c2ecf20Sopenharmony_ci * @devfn: encodes number of PCI slot in which the desired PCI device
2208c2ecf20Sopenharmony_ci * resides and the logical device number within that slot in case of
2218c2ecf20Sopenharmony_ci * multi-function devices.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * Given a PCI domain, bus, and slot/function number, the desired PCI
2248c2ecf20Sopenharmony_ci * device is located in the list of PCI devices. If the device is
2258c2ecf20Sopenharmony_ci * found, its reference count is increased and this function returns a
2268c2ecf20Sopenharmony_ci * pointer to its data structure.  The caller must decrement the
2278c2ecf20Sopenharmony_ci * reference count by calling pci_dev_put().  If no device is found,
2288c2ecf20Sopenharmony_ci * %NULL is returned.
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_cistruct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
2318c2ecf20Sopenharmony_ci					    unsigned int devfn)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct pci_dev *dev = NULL;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	for_each_pci_dev(dev) {
2368c2ecf20Sopenharmony_ci		if (pci_domain_nr(dev->bus) == domain &&
2378c2ecf20Sopenharmony_ci		    (dev->bus->number == bus && dev->devfn == devfn))
2388c2ecf20Sopenharmony_ci			return dev;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci	return NULL;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_get_domain_bus_and_slot);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int match_pci_dev_by_id(struct device *dev, const void *data)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
2478c2ecf20Sopenharmony_ci	const struct pci_device_id *id = data;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (pci_match_one_device(id, pdev))
2508c2ecf20Sopenharmony_ci		return 1;
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/*
2558c2ecf20Sopenharmony_ci * pci_get_dev_by_id - begin or continue searching for a PCI device by id
2568c2ecf20Sopenharmony_ci * @id: pointer to struct pci_device_id to match for the device
2578c2ecf20Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is found
2608c2ecf20Sopenharmony_ci * with a matching id a pointer to its device structure is returned, and the
2618c2ecf20Sopenharmony_ci * reference count to the device is incremented.  Otherwise, %NULL is returned.
2628c2ecf20Sopenharmony_ci * A new search is initiated by passing %NULL as the @from argument.  Otherwise
2638c2ecf20Sopenharmony_ci * if @from is not %NULL, searches continue from next device on the global
2648c2ecf20Sopenharmony_ci * list.  The reference count for @from is always decremented if it is not
2658c2ecf20Sopenharmony_ci * %NULL.
2668c2ecf20Sopenharmony_ci *
2678c2ecf20Sopenharmony_ci * This is an internal function for use by the other search functions in
2688c2ecf20Sopenharmony_ci * this file.
2698c2ecf20Sopenharmony_ci */
2708c2ecf20Sopenharmony_cistatic struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
2718c2ecf20Sopenharmony_ci					 struct pci_dev *from)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct device *dev;
2748c2ecf20Sopenharmony_ci	struct device *dev_start = NULL;
2758c2ecf20Sopenharmony_ci	struct pci_dev *pdev = NULL;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	WARN_ON(in_interrupt());
2788c2ecf20Sopenharmony_ci	if (from)
2798c2ecf20Sopenharmony_ci		dev_start = &from->dev;
2808c2ecf20Sopenharmony_ci	dev = bus_find_device(&pci_bus_type, dev_start, (void *)id,
2818c2ecf20Sopenharmony_ci			      match_pci_dev_by_id);
2828c2ecf20Sopenharmony_ci	if (dev)
2838c2ecf20Sopenharmony_ci		pdev = to_pci_dev(dev);
2848c2ecf20Sopenharmony_ci	pci_dev_put(from);
2858c2ecf20Sopenharmony_ci	return pdev;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/**
2898c2ecf20Sopenharmony_ci * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
2908c2ecf20Sopenharmony_ci * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
2918c2ecf20Sopenharmony_ci * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
2928c2ecf20Sopenharmony_ci * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
2938c2ecf20Sopenharmony_ci * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
2948c2ecf20Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
2958c2ecf20Sopenharmony_ci *
2968c2ecf20Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is found
2978c2ecf20Sopenharmony_ci * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
2988c2ecf20Sopenharmony_ci * device structure is returned, and the reference count to the device is
2998c2ecf20Sopenharmony_ci * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
3008c2ecf20Sopenharmony_ci * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
3018c2ecf20Sopenharmony_ci * searches continue from next device on the global list.
3028c2ecf20Sopenharmony_ci * The reference count for @from is always decremented if it is not %NULL.
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_cistruct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
3058c2ecf20Sopenharmony_ci			       unsigned int ss_vendor, unsigned int ss_device,
3068c2ecf20Sopenharmony_ci			       struct pci_dev *from)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	struct pci_device_id id = {
3098c2ecf20Sopenharmony_ci		.vendor = vendor,
3108c2ecf20Sopenharmony_ci		.device = device,
3118c2ecf20Sopenharmony_ci		.subvendor = ss_vendor,
3128c2ecf20Sopenharmony_ci		.subdevice = ss_device,
3138c2ecf20Sopenharmony_ci	};
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	return pci_get_dev_by_id(&id, from);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_get_subsys);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci/**
3208c2ecf20Sopenharmony_ci * pci_get_device - begin or continue searching for a PCI device by vendor/device id
3218c2ecf20Sopenharmony_ci * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
3228c2ecf20Sopenharmony_ci * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
3238c2ecf20Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is
3268c2ecf20Sopenharmony_ci * found with a matching @vendor and @device, the reference count to the
3278c2ecf20Sopenharmony_ci * device is incremented and a pointer to its device structure is returned.
3288c2ecf20Sopenharmony_ci * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
3298c2ecf20Sopenharmony_ci * as the @from argument.  Otherwise if @from is not %NULL, searches continue
3308c2ecf20Sopenharmony_ci * from next device on the global list.  The reference count for @from is
3318c2ecf20Sopenharmony_ci * always decremented if it is not %NULL.
3328c2ecf20Sopenharmony_ci */
3338c2ecf20Sopenharmony_cistruct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
3348c2ecf20Sopenharmony_ci			       struct pci_dev *from)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_get_device);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci/**
3418c2ecf20Sopenharmony_ci * pci_get_class - begin or continue searching for a PCI device by class
3428c2ecf20Sopenharmony_ci * @class: search for a PCI device with this class designation
3438c2ecf20Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
3448c2ecf20Sopenharmony_ci *
3458c2ecf20Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is
3468c2ecf20Sopenharmony_ci * found with a matching @class, the reference count to the device is
3478c2ecf20Sopenharmony_ci * incremented and a pointer to its device structure is returned.
3488c2ecf20Sopenharmony_ci * Otherwise, %NULL is returned.
3498c2ecf20Sopenharmony_ci * A new search is initiated by passing %NULL as the @from argument.
3508c2ecf20Sopenharmony_ci * Otherwise if @from is not %NULL, searches continue from next device
3518c2ecf20Sopenharmony_ci * on the global list.  The reference count for @from is always decremented
3528c2ecf20Sopenharmony_ci * if it is not %NULL.
3538c2ecf20Sopenharmony_ci */
3548c2ecf20Sopenharmony_cistruct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct pci_device_id id = {
3578c2ecf20Sopenharmony_ci		.vendor = PCI_ANY_ID,
3588c2ecf20Sopenharmony_ci		.device = PCI_ANY_ID,
3598c2ecf20Sopenharmony_ci		.subvendor = PCI_ANY_ID,
3608c2ecf20Sopenharmony_ci		.subdevice = PCI_ANY_ID,
3618c2ecf20Sopenharmony_ci		.class_mask = PCI_ANY_ID,
3628c2ecf20Sopenharmony_ci		.class = class,
3638c2ecf20Sopenharmony_ci	};
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return pci_get_dev_by_id(&id, from);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_get_class);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/**
3708c2ecf20Sopenharmony_ci * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
3718c2ecf20Sopenharmony_ci * @ids: A pointer to a null terminated list of struct pci_device_id structures
3728c2ecf20Sopenharmony_ci * that describe the type of PCI device the caller is trying to find.
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci * Obvious fact: You do not have a reference to any device that might be found
3758c2ecf20Sopenharmony_ci * by this function, so if that device is removed from the system right after
3768c2ecf20Sopenharmony_ci * this function is finished, the value will be stale.  Use this function to
3778c2ecf20Sopenharmony_ci * find devices that are usually built into a system, or for a general hint as
3788c2ecf20Sopenharmony_ci * to if another device happens to be present at this specific moment in time.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_ciint pci_dev_present(const struct pci_device_id *ids)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	struct pci_dev *found = NULL;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	WARN_ON(in_interrupt());
3858c2ecf20Sopenharmony_ci	while (ids->vendor || ids->subvendor || ids->class_mask) {
3868c2ecf20Sopenharmony_ci		found = pci_get_dev_by_id(ids, NULL);
3878c2ecf20Sopenharmony_ci		if (found) {
3888c2ecf20Sopenharmony_ci			pci_dev_put(found);
3898c2ecf20Sopenharmony_ci			return 1;
3908c2ecf20Sopenharmony_ci		}
3918c2ecf20Sopenharmony_ci		ids++;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_dev_present);
397