linux/drivers/pci/search.c
<<
>>
Prefs
   1/*
   2 *      PCI searching functions.
   3 *
   4 *      Copyright (C) 1993 -- 1997 Drew Eckhardt, Frederic Potter,
   5 *                                      David Mosberger-Tang
   6 *      Copyright (C) 1997 -- 2000 Martin Mares <mj@ucw.cz>
   7 *      Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com>
   8 */
   9
  10#include <linux/pci.h>
  11#include <linux/slab.h>
  12#include <linux/module.h>
  13#include <linux/interrupt.h>
  14#include "pci.h"
  15
  16DECLARE_RWSEM(pci_bus_sem);
  17EXPORT_SYMBOL_GPL(pci_bus_sem);
  18
  19/*
  20 * pci_for_each_dma_alias - Iterate over DMA aliases for a device
  21 * @pdev: starting downstream device
  22 * @fn: function to call for each alias
  23 * @data: opaque data to pass to @fn
  24 *
  25 * Starting @pdev, walk up the bus calling @fn for each possible alias
  26 * of @pdev at the root bus.
  27 */
  28int pci_for_each_dma_alias(struct pci_dev *pdev,
  29                           int (*fn)(struct pci_dev *pdev,
  30                                     u16 alias, void *data), void *data)
  31{
  32        struct pci_bus *bus;
  33        int ret;
  34
  35        ret = fn(pdev, PCI_DEVID(pdev->bus->number, pdev->devfn), data);
  36        if (ret)
  37                return ret;
  38
  39        /*
  40         * If the device is broken and uses an alias requester ID for
  41         * DMA, iterate over that too.
  42         */
  43        if (unlikely(pdev->dma_alias_mask)) {
  44                u8 devfn;
  45
  46                for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) {
  47                        ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn),
  48                                 data);
  49                        if (ret)
  50                                return ret;
  51                }
  52        }
  53
  54        for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
  55                struct pci_dev *tmp;
  56
  57                /* Skip virtual buses */
  58                if (!bus->self)
  59                        continue;
  60
  61                tmp = bus->self;
  62
  63                /* stop at bridge where translation unit is associated */
  64                if (tmp->dev_flags & PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT)
  65                        return ret;
  66
  67                /*
  68                 * PCIe-to-PCI/X bridges alias transactions from downstream
  69                 * devices using the subordinate bus number (PCI Express to
  70                 * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3).  For all cases
  71                 * where the upstream bus is PCI/X we alias to the bridge
  72                 * (there are various conditions in the previous reference
  73                 * where the bridge may take ownership of transactions, even
  74                 * when the secondary interface is PCI-X).
  75                 */
  76                if (pci_is_pcie(tmp)) {
  77                        switch (pci_pcie_type(tmp)) {
  78                        case PCI_EXP_TYPE_ROOT_PORT:
  79                        case PCI_EXP_TYPE_UPSTREAM:
  80                        case PCI_EXP_TYPE_DOWNSTREAM:
  81                                continue;
  82                        case PCI_EXP_TYPE_PCI_BRIDGE:
  83                                ret = fn(tmp,
  84                                         PCI_DEVID(tmp->subordinate->number,
  85                                                   PCI_DEVFN(0, 0)), data);
  86                                if (ret)
  87                                        return ret;
  88                                continue;
  89                        case PCI_EXP_TYPE_PCIE_BRIDGE:
  90                                ret = fn(tmp,
  91                                         PCI_DEVID(tmp->bus->number,
  92                                                   tmp->devfn), data);
  93                                if (ret)
  94                                        return ret;
  95                                continue;
  96                        }
  97                } else {
  98                        if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS)
  99                                ret = fn(tmp,
 100                                         PCI_DEVID(tmp->subordinate->number,
 101                                                   PCI_DEVFN(0, 0)), data);
 102                        else
 103                                ret = fn(tmp,
 104                                         PCI_DEVID(tmp->bus->number,
 105                                                   tmp->devfn), data);
 106                        if (ret)
 107                                return ret;
 108                }
 109        }
 110
 111        return ret;
 112}
 113
 114static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
 115{
 116        struct pci_bus *child;
 117        struct pci_bus *tmp;
 118
 119        if (bus->number == busnr)
 120                return bus;
 121
 122        list_for_each_entry(tmp, &bus->children, node) {
 123                child = pci_do_find_bus(tmp, busnr);
 124                if (child)
 125                        return child;
 126        }
 127        return NULL;
 128}
 129
 130/**
 131 * pci_find_bus - locate PCI bus from a given domain and bus number
 132 * @domain: number of PCI domain to search
 133 * @busnr: number of desired PCI bus
 134 *
 135 * Given a PCI bus number and domain number, the desired PCI bus is located
 136 * in the global list of PCI buses.  If the bus is found, a pointer to its
 137 * data structure is returned.  If no bus is found, %NULL is returned.
 138 */
 139struct pci_bus *pci_find_bus(int domain, int busnr)
 140{
 141        struct pci_bus *bus = NULL;
 142        struct pci_bus *tmp_bus;
 143
 144        while ((bus = pci_find_next_bus(bus)) != NULL)  {
 145                if (pci_domain_nr(bus) != domain)
 146                        continue;
 147                tmp_bus = pci_do_find_bus(bus, busnr);
 148                if (tmp_bus)
 149                        return tmp_bus;
 150        }
 151        return NULL;
 152}
 153EXPORT_SYMBOL(pci_find_bus);
 154
 155/**
 156 * pci_find_next_bus - begin or continue searching for a PCI bus
 157 * @from: Previous PCI bus found, or %NULL for new search.
 158 *
 159 * Iterates through the list of known PCI buses.  A new search is
 160 * initiated by passing %NULL as the @from argument.  Otherwise if
 161 * @from is not %NULL, searches continue from next device on the
 162 * global list.
 163 */
 164struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
 165{
 166        struct list_head *n;
 167        struct pci_bus *b = NULL;
 168
 169        WARN_ON(in_interrupt());
 170        down_read(&pci_bus_sem);
 171        n = from ? from->node.next : pci_root_buses.next;
 172        if (n != &pci_root_buses)
 173                b = list_entry(n, struct pci_bus, node);
 174        up_read(&pci_bus_sem);
 175        return b;
 176}
 177EXPORT_SYMBOL(pci_find_next_bus);
 178
 179/**
 180 * pci_get_slot - locate PCI device for a given PCI slot
 181 * @bus: PCI bus on which desired PCI device resides
 182 * @devfn: encodes number of PCI slot in which the desired PCI
 183 * device resides and the logical device number within that slot
 184 * in case of multi-function devices.
 185 *
 186 * Given a PCI bus and slot/function number, the desired PCI device
 187 * is located in the list of PCI devices.
 188 * If the device is found, its reference count is increased and this
 189 * function returns a pointer to its data structure.  The caller must
 190 * decrement the reference count by calling pci_dev_put().
 191 * If no device is found, %NULL is returned.
 192 */
 193struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn)
 194{
 195        struct pci_dev *dev;
 196
 197        WARN_ON(in_interrupt());
 198        down_read(&pci_bus_sem);
 199
 200        list_for_each_entry(dev, &bus->devices, bus_list) {
 201                if (dev->devfn == devfn)
 202                        goto out;
 203        }
 204
 205        dev = NULL;
 206 out:
 207        pci_dev_get(dev);
 208        up_read(&pci_bus_sem);
 209        return dev;
 210}
 211EXPORT_SYMBOL(pci_get_slot);
 212
 213/**
 214 * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot
 215 * @domain: PCI domain/segment on which the PCI device resides.
 216 * @bus: PCI bus on which desired PCI device resides
 217 * @devfn: encodes number of PCI slot in which the desired PCI device
 218 * resides and the logical device number within that slot in case of
 219 * multi-function devices.
 220 *
 221 * Given a PCI domain, bus, and slot/function number, the desired PCI
 222 * device is located in the list of PCI devices. If the device is
 223 * found, its reference count is increased and this function returns a
 224 * pointer to its data structure.  The caller must decrement the
 225 * reference count by calling pci_dev_put().  If no device is found,
 226 * %NULL is returned.
 227 */
 228struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
 229                                            unsigned int devfn)
 230{
 231        struct pci_dev *dev = NULL;
 232
 233        for_each_pci_dev(dev) {
 234                if (pci_domain_nr(dev->bus) == domain &&
 235                    (dev->bus->number == bus && dev->devfn == devfn))
 236                        return dev;
 237        }
 238        return NULL;
 239}
 240EXPORT_SYMBOL(pci_get_domain_bus_and_slot);
 241
 242static int match_pci_dev_by_id(struct device *dev, void *data)
 243{
 244        struct pci_dev *pdev = to_pci_dev(dev);
 245        struct pci_device_id *id = data;
 246
 247        if (pci_match_one_device(id, pdev))
 248                return 1;
 249        return 0;
 250}
 251
 252/*
 253 * pci_get_dev_by_id - begin or continue searching for a PCI device by id
 254 * @id: pointer to struct pci_device_id to match for the device
 255 * @from: Previous PCI device found in search, or %NULL for new search.
 256 *
 257 * Iterates through the list of known PCI devices.  If a PCI device is found
 258 * with a matching id a pointer to its device structure is returned, and the
 259 * reference count to the device is incremented.  Otherwise, %NULL is returned.
 260 * A new search is initiated by passing %NULL as the @from argument.  Otherwise
 261 * if @from is not %NULL, searches continue from next device on the global
 262 * list.  The reference count for @from is always decremented if it is not
 263 * %NULL.
 264 *
 265 * This is an internal function for use by the other search functions in
 266 * this file.
 267 */
 268static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
 269                                         struct pci_dev *from)
 270{
 271        struct device *dev;
 272        struct device *dev_start = NULL;
 273        struct pci_dev *pdev = NULL;
 274
 275        WARN_ON(in_interrupt());
 276        if (from)
 277                dev_start = &from->dev;
 278        dev = bus_find_device(&pci_bus_type, dev_start, (void *)id,
 279                              match_pci_dev_by_id);
 280        if (dev)
 281                pdev = to_pci_dev(dev);
 282        pci_dev_put(from);
 283        return pdev;
 284}
 285
 286/**
 287 * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
 288 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
 289 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
 290 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
 291 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
 292 * @from: Previous PCI device found in search, or %NULL for new search.
 293 *
 294 * Iterates through the list of known PCI devices.  If a PCI device is found
 295 * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
 296 * device structure is returned, and the reference count to the device is
 297 * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
 298 * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
 299 * searches continue from next device on the global list.
 300 * The reference count for @from is always decremented if it is not %NULL.
 301 */
 302struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
 303                               unsigned int ss_vendor, unsigned int ss_device,
 304                               struct pci_dev *from)
 305{
 306        struct pci_device_id id = {
 307                .vendor = vendor,
 308                .device = device,
 309                .subvendor = ss_vendor,
 310                .subdevice = ss_device,
 311        };
 312
 313        return pci_get_dev_by_id(&id, from);
 314}
 315EXPORT_SYMBOL(pci_get_subsys);
 316
 317/**
 318 * pci_get_device - begin or continue searching for a PCI device by vendor/device id
 319 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
 320 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
 321 * @from: Previous PCI device found in search, or %NULL for new search.
 322 *
 323 * Iterates through the list of known PCI devices.  If a PCI device is
 324 * found with a matching @vendor and @device, the reference count to the
 325 * device is incremented and a pointer to its device structure is returned.
 326 * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
 327 * as the @from argument.  Otherwise if @from is not %NULL, searches continue
 328 * from next device on the global list.  The reference count for @from is
 329 * always decremented if it is not %NULL.
 330 */
 331struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
 332                               struct pci_dev *from)
 333{
 334        return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
 335}
 336EXPORT_SYMBOL(pci_get_device);
 337
 338/**
 339 * pci_get_class - begin or continue searching for a PCI device by class
 340 * @class: search for a PCI device with this class designation
 341 * @from: Previous PCI device found in search, or %NULL for new search.
 342 *
 343 * Iterates through the list of known PCI devices.  If a PCI device is
 344 * found with a matching @class, the reference count to the device is
 345 * incremented and a pointer to its device structure is returned.
 346 * Otherwise, %NULL is returned.
 347 * A new search is initiated by passing %NULL as the @from argument.
 348 * Otherwise if @from is not %NULL, searches continue from next device
 349 * on the global list.  The reference count for @from is always decremented
 350 * if it is not %NULL.
 351 */
 352struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
 353{
 354        struct pci_device_id id = {
 355                .vendor = PCI_ANY_ID,
 356                .device = PCI_ANY_ID,
 357                .subvendor = PCI_ANY_ID,
 358                .subdevice = PCI_ANY_ID,
 359                .class_mask = PCI_ANY_ID,
 360                .class = class,
 361        };
 362
 363        return pci_get_dev_by_id(&id, from);
 364}
 365EXPORT_SYMBOL(pci_get_class);
 366
 367/**
 368 * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
 369 * @ids: A pointer to a null terminated list of struct pci_device_id structures
 370 * that describe the type of PCI device the caller is trying to find.
 371 *
 372 * Obvious fact: You do not have a reference to any device that might be found
 373 * by this function, so if that device is removed from the system right after
 374 * this function is finished, the value will be stale.  Use this function to
 375 * find devices that are usually built into a system, or for a general hint as
 376 * to if another device happens to be present at this specific moment in time.
 377 */
 378int pci_dev_present(const struct pci_device_id *ids)
 379{
 380        struct pci_dev *found = NULL;
 381
 382        WARN_ON(in_interrupt());
 383        while (ids->vendor || ids->subvendor || ids->class_mask) {
 384                found = pci_get_dev_by_id(ids, NULL);
 385                if (found) {
 386                        pci_dev_put(found);
 387                        return 1;
 388                }
 389                ids++;
 390        }
 391
 392        return 0;
 393}
 394EXPORT_SYMBOL(pci_dev_present);
 395