search.c 12.8 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *	PCI searching functions.
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11
 *
 *	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>
 */

#include <linux/init.h>
#include <linux/pci.h>
12
#include <linux/slab.h>
L
Linus Torvalds 已提交
13 14 15 16
#include <linux/module.h>
#include <linux/interrupt.h>
#include "pci.h"

17
DECLARE_RWSEM(pci_bus_sem);
18 19
EXPORT_SYMBOL_GPL(pci_bus_sem);

A
Alex Williamson 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/*
 * 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;

40 41 42 43 44 45 46 47 48 49 50
	/*
	 * If the device is broken and uses an alias requester ID for
	 * DMA, iterate over that too.
	 */
	if (unlikely(pdev->dev_flags & PCI_DEV_FLAGS_DMA_ALIAS_DEVFN)) {
		ret = fn(pdev, PCI_DEVID(pdev->bus->number,
					 pdev->dma_alias_devfn), data);
		if (ret)
			return ret;
	}

A
Alex Williamson 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	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;

		/*
		 * 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,
						   tmp->devfn), data);
				if (ret)
					return ret;
				continue;
			}
		} else {
91 92 93 94 95 96 97 98
			if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS)
				ret = fn(tmp,
					 PCI_DEVID(tmp->subordinate->number,
						   PCI_DEVFN(0, 0)), data);
			else
				ret = fn(tmp,
					 PCI_DEVID(tmp->bus->number,
						   tmp->devfn), data);
A
Alex Williamson 已提交
99 100 101 102 103 104 105 106
			if (ret)
				return ret;
		}
	}

	return ret;
}

107
/*
108
 * find the upstream PCIe-to-PCI bridge of a PCI device
109
 * if the device is PCIE, return NULL
110
 * if the device isn't connected to a PCIe bridge (that is its parent is a
111 112 113 114 115 116 117 118
 * legacy PCI bridge and the bridge is directly connected to bus 0), return its
 * parent
 */
struct pci_dev *
pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
{
	struct pci_dev *tmp = NULL;

119
	if (pci_is_pcie(pdev))
120 121
		return NULL;
	while (1) {
122
		if (pci_is_root_bus(pdev->bus))
123 124 125
			break;
		pdev = pdev->bus->self;
		/* a p2p bridge */
126
		if (!pci_is_pcie(pdev)) {
127 128 129
			tmp = pdev;
			continue;
		}
130
		/* PCI device should connect to a PCIe bridge */
131
		if (pci_pcie_type(pdev) != PCI_EXP_TYPE_PCI_BRIDGE) {
132 133 134 135 136 137 138 139 140
			/* Busted hardware? */
			WARN_ON_ONCE(1);
			return NULL;
		}
		return pdev;
	}

	return tmp;
}
L
Linus Torvalds 已提交
141

142
static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
L
Linus Torvalds 已提交
143
{
144 145
	struct pci_bus *child;
	struct pci_bus *tmp;
L
Linus Torvalds 已提交
146 147 148 149

	if(bus->number == busnr)
		return bus;

150 151
	list_for_each_entry(tmp, &bus->children, node) {
		child = pci_do_find_bus(tmp, busnr);
L
Linus Torvalds 已提交
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
		if(child)
			return child;
	}
	return NULL;
}

/**
 * pci_find_bus - locate PCI bus from a given domain and bus number
 * @domain: number of PCI domain to search
 * @busnr: number of desired PCI bus
 *
 * Given a PCI bus number and domain number, the desired PCI bus is located
 * in the global list of PCI buses.  If the bus is found, a pointer to its
 * data structure is returned.  If no bus is found, %NULL is returned.
 */
167
struct pci_bus * pci_find_bus(int domain, int busnr)
L
Linus Torvalds 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
{
	struct pci_bus *bus = NULL;
	struct pci_bus *tmp_bus;

	while ((bus = pci_find_next_bus(bus)) != NULL)  {
		if (pci_domain_nr(bus) != domain)
			continue;
		tmp_bus = pci_do_find_bus(bus, busnr);
		if (tmp_bus)
			return tmp_bus;
	}
	return NULL;
}

/**
 * pci_find_next_bus - begin or continue searching for a PCI bus
 * @from: Previous PCI bus found, or %NULL for new search.
 *
186
 * Iterates through the list of known PCI buses.  A new search is
187
 * initiated by passing %NULL as the @from argument.  Otherwise if
L
Linus Torvalds 已提交
188 189 190
 * @from is not %NULL, searches continue from next device on the
 * global list.
 */
191
struct pci_bus *
L
Linus Torvalds 已提交
192 193 194 195 196 197
pci_find_next_bus(const struct pci_bus *from)
{
	struct list_head *n;
	struct pci_bus *b = NULL;

	WARN_ON(in_interrupt());
198
	down_read(&pci_bus_sem);
L
Linus Torvalds 已提交
199 200
	n = from ? from->node.next : pci_root_buses.next;
	if (n != &pci_root_buses)
201
		b = list_entry(n, struct pci_bus, node);
202
	up_read(&pci_bus_sem);
L
Linus Torvalds 已提交
203 204 205 206 207 208
	return b;
}

/**
 * pci_get_slot - locate PCI device for a given PCI slot
 * @bus: PCI bus on which desired PCI device resides
209 210
 * @devfn: encodes number of PCI slot in which the desired PCI
 * device resides and the logical device number within that slot
L
Linus Torvalds 已提交
211 212
 * in case of multi-function devices.
 *
213
 * Given a PCI bus and slot/function number, the desired PCI device
L
Linus Torvalds 已提交
214 215 216 217 218 219
 * is located in the list of PCI devices.
 * If the device is found, its reference count is increased and this
 * function returns a pointer to its data structure.  The caller must
 * decrement the reference count by calling pci_dev_put().
 * If no device is found, %NULL is returned.
 */
220
struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn)
L
Linus Torvalds 已提交
221 222 223 224
{
	struct pci_dev *dev;

	WARN_ON(in_interrupt());
225
	down_read(&pci_bus_sem);
L
Linus Torvalds 已提交
226

227
	list_for_each_entry(dev, &bus->devices, bus_list) {
L
Linus Torvalds 已提交
228 229 230 231 232 233 234
		if (dev->devfn == devfn)
			goto out;
	}

	dev = NULL;
 out:
	pci_dev_get(dev);
235
	up_read(&pci_bus_sem);
L
Linus Torvalds 已提交
236 237 238
	return dev;
}

A
Alan Cox 已提交
239
/**
240 241 242 243 244 245
 * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot
 * @domain: PCI domain/segment on which the PCI device resides.
 * @bus: PCI bus on which desired PCI device resides
 * @devfn: encodes number of PCI slot in which the desired PCI device
 * resides and the logical device number within that slot in case of
 * multi-function devices.
246
 *
247 248 249 250 251 252
 * Given a PCI domain, bus, and slot/function number, the desired PCI
 * device is located in the list of PCI devices. If the device is
 * found, its reference count is increased and this function returns a
 * pointer to its data structure.  The caller must decrement the
 * reference count by calling pci_dev_put().  If no device is found,
 * %NULL is returned.
A
Alan Cox 已提交
253
 */
254 255
struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
					    unsigned int devfn)
A
Alan Cox 已提交
256 257 258
{
	struct pci_dev *dev = NULL;

K
Kulikov Vasiliy 已提交
259
	for_each_pci_dev(dev) {
260 261
		if (pci_domain_nr(dev->bus) == domain &&
		    (dev->bus->number == bus && dev->devfn == devfn))
A
Alan Cox 已提交
262 263 264 265
			return dev;
	}
	return NULL;
}
266
EXPORT_SYMBOL(pci_get_domain_bus_and_slot);
A
Alan Cox 已提交
267

268
static int match_pci_dev_by_id(struct device *dev, void *data)
L
Linus Torvalds 已提交
269
{
270 271
	struct pci_dev *pdev = to_pci_dev(dev);
	struct pci_device_id *id = data;
L
Linus Torvalds 已提交
272

273 274 275
	if (pci_match_one_device(id, pdev))
		return 1;
	return 0;
L
Linus Torvalds 已提交
276 277
}

278 279 280
/*
 * pci_get_dev_by_id - begin or continue searching for a PCI device by id
 * @id: pointer to struct pci_device_id to match for the device
L
Linus Torvalds 已提交
281 282
 * @from: Previous PCI device found in search, or %NULL for new search.
 *
283
 * Iterates through the list of known PCI devices.  If a PCI device is found
284 285 286 287 288 289 290 291 292
 * with a matching id a pointer to its device structure is returned, and the
 * reference count to the device is incremented.  Otherwise, %NULL is returned.
 * A new search is initiated by passing %NULL as the @from argument.  Otherwise
 * if @from is not %NULL, searches continue from next device on the global
 * list.  The reference count for @from is always decremented if it is not
 * %NULL.
 *
 * This is an internal function for use by the other search functions in
 * this file.
L
Linus Torvalds 已提交
293
 */
294
static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
295
					 struct pci_dev *from)
L
Linus Torvalds 已提交
296
{
297 298 299 300 301
	struct device *dev;
	struct device *dev_start = NULL;
	struct pci_dev *pdev = NULL;

	WARN_ON(in_interrupt());
M
Matthew Wilcox 已提交
302 303
	if (from)
		dev_start = &from->dev;
304 305 306 307
	dev = bus_find_device(&pci_bus_type, dev_start, (void *)id,
			      match_pci_dev_by_id);
	if (dev)
		pdev = to_pci_dev(dev);
308 309
	if (from)
		pci_dev_put(from);
310
	return pdev;
L
Linus Torvalds 已提交
311 312 313 314 315 316 317 318 319 320
}

/**
 * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
 * @from: Previous PCI device found in search, or %NULL for new search.
 *
321 322
 * Iterates through the list of known PCI devices.  If a PCI device is found
 * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
L
Linus Torvalds 已提交
323 324
 * device structure is returned, and the reference count to the device is
 * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
325
 * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
L
Linus Torvalds 已提交
326 327 328
 * searches continue from next device on the global list.
 * The reference count for @from is always decremented if it is not %NULL.
 */
329 330
struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
			       unsigned int ss_vendor, unsigned int ss_device,
331
			       struct pci_dev *from)
L
Linus Torvalds 已提交
332
{
333 334 335 336 337 338
	struct pci_device_id id = {
		.vendor = vendor,
		.device = device,
		.subvendor = ss_vendor,
		.subdevice = ss_device,
	};
339

340
	return pci_get_dev_by_id(&id, from);
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348 349 350 351 352
}

/**
 * pci_get_device - begin or continue searching for a PCI device by vendor/device id
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
 * @from: Previous PCI device found in search, or %NULL for new search.
 *
 * Iterates through the list of known PCI devices.  If a PCI device is
 * found with a matching @vendor and @device, the reference count to the
 * device is incremented and a pointer to its device structure is returned.
 * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
353
 * as the @from argument.  Otherwise if @from is not %NULL, searches continue
L
Linus Torvalds 已提交
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
 * from next device on the global list.  The reference count for @from is
 * always decremented if it is not %NULL.
 */
struct pci_dev *
pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
{
	return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}

/**
 * pci_get_class - begin or continue searching for a PCI device by class
 * @class: search for a PCI device with this class designation
 * @from: Previous PCI device found in search, or %NULL for new search.
 *
 * Iterates through the list of known PCI devices.  If a PCI device is
 * found with a matching @class, the reference count to the device is
 * incremented and a pointer to its device structure is returned.
 * Otherwise, %NULL is returned.
372
 * A new search is initiated by passing %NULL as the @from argument.
L
Linus Torvalds 已提交
373 374 375 376 377 378
 * Otherwise if @from is not %NULL, searches continue from next device
 * on the global list.  The reference count for @from is always decremented
 * if it is not %NULL.
 */
struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
{
379 380 381 382 383 384 385 386 387 388
	struct pci_device_id id = {
		.vendor = PCI_ANY_ID,
		.device = PCI_ANY_ID,
		.subvendor = PCI_ANY_ID,
		.subdevice = PCI_ANY_ID,
		.class_mask = PCI_ANY_ID,
		.class = class,
	};

	return pci_get_dev_by_id(&id, from);
L
Linus Torvalds 已提交
389 390
}

391 392 393 394 395 396 397 398 399 400 401 402
/**
 * 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
 * that describe the type of PCI device the caller is trying to find.
 *
 * Obvious fact: You do not have a reference to any device that might be found
 * by this function, so if that device is removed from the system right after
 * this function is finished, the value will be stale.  Use this function to
 * find devices that are usually built into a system, or for a general hint as
 * to if another device happens to be present at this specific moment in time.
 */
int pci_dev_present(const struct pci_device_id *ids)
A
Alan Cox 已提交
403
{
404
	struct pci_dev *found = NULL;
A
Alan Cox 已提交
405 406 407

	WARN_ON(in_interrupt());
	while (ids->vendor || ids->subvendor || ids->class_mask) {
408
		found = pci_get_dev_by_id(ids, NULL);
409 410 411 412
		if (found) {
			pci_dev_put(found);
			return 1;
		}
A
Alan Cox 已提交
413 414
		ids++;
	}
415

416
	return 0;
L
Linus Torvalds 已提交
417 418 419
}
EXPORT_SYMBOL(pci_dev_present);

A
Alan Cox 已提交
420 421 422 423
/* For boot time work */
EXPORT_SYMBOL(pci_find_bus);
EXPORT_SYMBOL(pci_find_next_bus);
/* For everyone */
L
Linus Torvalds 已提交
424 425 426 427
EXPORT_SYMBOL(pci_get_device);
EXPORT_SYMBOL(pci_get_subsys);
EXPORT_SYMBOL(pci_get_slot);
EXPORT_SYMBOL(pci_get_class);