Source
* pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
// SPDX-License-Identifier: GPL-2.0
/*
* PCI searching functions
*
* Copyright (C) 1993 -- 1997 Drew Eckhardt, Frederic Potter,
* David Mosberger-Tang
* Copyright (C) 1997 -- 2000 Martin Mares <mj@ucw.cz>
* Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com>
*/
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->dma_alias_mask)) {
u8 devfn;
for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) {
ret = fn(pdev, PCI_DEVID(pdev->bus->number, 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;
/* stop at bridge where translation unit is associated */
if (tmp->dev_flags & PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT)
return ret;
/*
* 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,