OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [pci/] [search.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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/init.h>
11
#include <linux/pci.h>
12
#include <linux/module.h>
13
#include <linux/interrupt.h>
14
#include "pci.h"
15
 
16
DECLARE_RWSEM(pci_bus_sem);
17
/*
18
 * find the upstream PCIE-to-PCI bridge of a PCI device
19
 * if the device is PCIE, return NULL
20
 * if the device isn't connected to a PCIE bridge (that is its parent is a
21
 * legacy PCI bridge and the bridge is directly connected to bus 0), return its
22
 * parent
23
 */
24
struct pci_dev *
25
pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
26
{
27
        struct pci_dev *tmp = NULL;
28
 
29
        if (pdev->is_pcie)
30
                return NULL;
31
        while (1) {
32
                if (!pdev->bus->self)
33
                        break;
34
                pdev = pdev->bus->self;
35
                /* a p2p bridge */
36
                if (!pdev->is_pcie) {
37
                        tmp = pdev;
38
                        continue;
39
                }
40
                /* PCI device should connect to a PCIE bridge */
41
                if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
42
                        /* Busted hardware? */
43
                        WARN_ON_ONCE(1);
44
                        return NULL;
45
                }
46
                return pdev;
47
        }
48
 
49
        return tmp;
50
}
51
 
52
static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
53
{
54
        struct pci_bus* child;
55
        struct list_head *tmp;
56
 
57
        if(bus->number == busnr)
58
                return bus;
59
 
60
        list_for_each(tmp, &bus->children) {
61
                child = pci_do_find_bus(pci_bus_b(tmp), busnr);
62
                if(child)
63
                        return child;
64
        }
65
        return NULL;
66
}
67
 
68
/**
69
 * pci_find_bus - locate PCI bus from a given domain and bus number
70
 * @domain: number of PCI domain to search
71
 * @busnr: number of desired PCI bus
72
 *
73
 * Given a PCI bus number and domain number, the desired PCI bus is located
74
 * in the global list of PCI buses.  If the bus is found, a pointer to its
75
 * data structure is returned.  If no bus is found, %NULL is returned.
76
 */
77
struct pci_bus * pci_find_bus(int domain, int busnr)
78
{
79
        struct pci_bus *bus = NULL;
80
        struct pci_bus *tmp_bus;
81
 
82
        while ((bus = pci_find_next_bus(bus)) != NULL)  {
83
                if (pci_domain_nr(bus) != domain)
84
                        continue;
85
                tmp_bus = pci_do_find_bus(bus, busnr);
86
                if (tmp_bus)
87
                        return tmp_bus;
88
        }
89
        return NULL;
90
}
91
 
92
/**
93
 * pci_find_next_bus - begin or continue searching for a PCI bus
94
 * @from: Previous PCI bus found, or %NULL for new search.
95
 *
96
 * Iterates through the list of known PCI busses.  A new search is
97
 * initiated by passing %NULL as the @from argument.  Otherwise if
98
 * @from is not %NULL, searches continue from next device on the
99
 * global list.
100
 */
101
struct pci_bus *
102
pci_find_next_bus(const struct pci_bus *from)
103
{
104
        struct list_head *n;
105
        struct pci_bus *b = NULL;
106
 
107
        WARN_ON(in_interrupt());
108
        down_read(&pci_bus_sem);
109
        n = from ? from->node.next : pci_root_buses.next;
110
        if (n != &pci_root_buses)
111
                b = pci_bus_b(n);
112
        up_read(&pci_bus_sem);
113
        return b;
114
}
115
 
116
#ifdef CONFIG_PCI_LEGACY
117
 
118
/**
119
 * pci_find_slot - locate PCI device from a given PCI slot
120
 * @bus: number of PCI bus on which desired PCI device resides
121
 * @devfn: encodes number of PCI slot in which the desired PCI
122
 * device resides and the logical device number within that slot
123
 * in case of multi-function devices.
124
 *
125
 * Given a PCI bus and slot/function number, the desired PCI device
126
 * is located in system global list of PCI devices.  If the device
127
 * is found, a pointer to its data structure is returned.  If no
128
 * device is found, %NULL is returned.
129
 */
130
struct pci_dev *
131
pci_find_slot(unsigned int bus, unsigned int devfn)
132
{
133
        struct pci_dev *dev = NULL;
134
 
135
        while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
136
                if (dev->bus->number == bus && dev->devfn == devfn)
137
                        return dev;
138
        }
139
        return NULL;
140
}
141
 
142
#endif /* CONFIG_PCI_LEGACY */
143
 
144
/**
145
 * pci_get_slot - locate PCI device for a given PCI slot
146
 * @bus: PCI bus on which desired PCI device resides
147
 * @devfn: encodes number of PCI slot in which the desired PCI
148
 * device resides and the logical device number within that slot
149
 * in case of multi-function devices.
150
 *
151
 * Given a PCI bus and slot/function number, the desired PCI device
152
 * is located in the list of PCI devices.
153
 * If the device is found, its reference count is increased and this
154
 * function returns a pointer to its data structure.  The caller must
155
 * decrement the reference count by calling pci_dev_put().
156
 * If no device is found, %NULL is returned.
157
 */
158
struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
159
{
160
        struct list_head *tmp;
161
        struct pci_dev *dev;
162
 
163
        WARN_ON(in_interrupt());
164
        down_read(&pci_bus_sem);
165
 
166
        list_for_each(tmp, &bus->devices) {
167
                dev = pci_dev_b(tmp);
168
                if (dev->devfn == devfn)
169
                        goto out;
170
        }
171
 
172
        dev = NULL;
173
 out:
174
        pci_dev_get(dev);
175
        up_read(&pci_bus_sem);
176
        return dev;
177
}
178
 
179
/**
180
 * pci_get_bus_and_slot - locate PCI device from a given PCI bus & slot
181
 * @bus: number of 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
 * Note: the bus/slot search is limited to PCI domain (segment) 0.
187
 *
188
 * Given a PCI bus and slot/function number, the desired PCI device
189
 * is located in system global list of PCI devices.  If the device
190
 * is found, a pointer to its data structure is returned.  If no
191
 * device is found, %NULL is returned. The returned device has its
192
 * reference count bumped by one.
193
 */
194
 
195
struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
196
{
197
        struct pci_dev *dev = NULL;
198
 
199
        while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
200
                if (pci_domain_nr(dev->bus) == 0 &&
201
                   (dev->bus->number == bus && dev->devfn == devfn))
202
                        return dev;
203
        }
204
        return NULL;
205
}
206
 
207
#ifdef CONFIG_PCI_LEGACY
208
/**
209
 * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
210
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
211
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
212
 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
213
 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
214
 * @from: Previous PCI device found in search, or %NULL for new search.
215
 *
216
 * Iterates through the list of known PCI devices.  If a PCI device is
217
 * found with a matching @vendor, @device, @ss_vendor and @ss_device, a
218
 * pointer to its device structure is returned.  Otherwise, %NULL is returned.
219
 * A new search is initiated by passing %NULL as the @from argument.
220
 * Otherwise if @from is not %NULL, searches continue from next device
221
 * on the global list.
222
 *
223
 * NOTE: Do not use this function any more; use pci_get_subsys() instead, as
224
 * the PCI device returned by this function can disappear at any moment in
225
 * time.
226
 */
227
static struct pci_dev * pci_find_subsys(unsigned int vendor,
228
                                        unsigned int device,
229
                                        unsigned int ss_vendor,
230
                                        unsigned int ss_device,
231
                                        const struct pci_dev *from)
232
{
233
        struct list_head *n;
234
        struct pci_dev *dev;
235
 
236
        WARN_ON(in_interrupt());
237
 
238
        /*
239
         * pci_find_subsys() can be called on the ide_setup() path, super-early
240
         * in boot.  But the down_read() will enable local interrupts, which
241
         * can cause some machines to crash.  So here we detect and flag that
242
         * situation and bail out early.
243
         */
244
        if (unlikely(no_pci_devices()))
245
                return NULL;
246
        down_read(&pci_bus_sem);
247
        n = from ? from->global_list.next : pci_devices.next;
248
 
249
        while (n && (n != &pci_devices)) {
250
                dev = pci_dev_g(n);
251
                if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
252
                    (device == PCI_ANY_ID || dev->device == device) &&
253
                    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
254
                    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
255
                        goto exit;
256
                n = n->next;
257
        }
258
        dev = NULL;
259
exit:
260
        up_read(&pci_bus_sem);
261
        return dev;
262
}
263
 
264
/**
265
 * pci_find_device - begin or continue searching for a PCI device by vendor/device id
266
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
267
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
268
 * @from: Previous PCI device found in search, or %NULL for new search.
269
 *
270
 * Iterates through the list of known PCI devices.  If a PCI device is found
271
 * with a matching @vendor and @device, a pointer to its device structure is
272
 * returned.  Otherwise, %NULL is returned.
273
 * A new search is initiated by passing %NULL as the @from argument.
274
 * Otherwise if @from is not %NULL, searches continue from next device
275
 * on the global list.
276
 *
277
 * NOTE: Do not use this function any more; use pci_get_device() instead, as
278
 * the PCI device returned by this function can disappear at any moment in
279
 * time.
280
 */
281
struct pci_dev *
282
pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
283
{
284
        return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
285
}
286
#endif /* CONFIG_PCI_LEGACY */
287
 
288
/**
289
 * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
290
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
291
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
292
 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
293
 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
294
 * @from: Previous PCI device found in search, or %NULL for new search.
295
 *
296
 * Iterates through the list of known PCI devices.  If a PCI device is found
297
 * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
298
 * device structure is returned, and the reference count to the device is
299
 * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
300
 * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
301
 * searches continue from next device on the global list.
302
 * The reference count for @from is always decremented if it is not %NULL.
303
 */
304
struct pci_dev *
305
pci_get_subsys(unsigned int vendor, unsigned int device,
306
               unsigned int ss_vendor, unsigned int ss_device,
307
               struct pci_dev *from)
308
{
309
        struct list_head *n;
310
        struct pci_dev *dev;
311
 
312
        WARN_ON(in_interrupt());
313
 
314
        /*
315
         * pci_get_subsys() can potentially be called by drivers super-early
316
         * in boot.  But the down_read() will enable local interrupts, which
317
         * can cause some machines to crash.  So here we detect and flag that
318
         * situation and bail out early.
319
         */
320
        if (unlikely(no_pci_devices()))
321
                return NULL;
322
        down_read(&pci_bus_sem);
323
        n = from ? from->global_list.next : pci_devices.next;
324
 
325
        while (n && (n != &pci_devices)) {
326
                dev = pci_dev_g(n);
327
                if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
328
                    (device == PCI_ANY_ID || dev->device == device) &&
329
                    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
330
                    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
331
                        goto exit;
332
                n = n->next;
333
        }
334
        dev = NULL;
335
exit:
336
        dev = pci_dev_get(dev);
337
        up_read(&pci_bus_sem);
338
        pci_dev_put(from);
339
        return dev;
340
}
341
 
342
/**
343
 * pci_get_device - begin or continue searching for a PCI device by vendor/device id
344
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
345
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
346
 * @from: Previous PCI device found in search, or %NULL for new search.
347
 *
348
 * Iterates through the list of known PCI devices.  If a PCI device is
349
 * found with a matching @vendor and @device, the reference count to the
350
 * device is incremented and a pointer to its device structure is returned.
351
 * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
352
 * as the @from argument.  Otherwise if @from is not %NULL, searches continue
353
 * from next device on the global list.  The reference count for @from is
354
 * always decremented if it is not %NULL.
355
 */
356
struct pci_dev *
357
pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
358
{
359
        return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
360
}
361
 
362
/**
363
 * pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id
364
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
365
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
366
 * @from: Previous PCI device found in search, or %NULL for new search.
367
 *
368
 * Iterates through the list of known PCI devices in the reverse order of
369
 * pci_get_device.
370
 * If a PCI device is found with a matching @vendor and @device, the reference
371
 * count to the  device is incremented and a pointer to its device structure
372
 * is returned Otherwise, %NULL is returned.  A new search is initiated by
373
 * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
374
 * searches continue from next device on the global list.  The reference
375
 * count for @from is always decremented if it is not %NULL.
376
 */
377
struct pci_dev *
378
pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from)
379
{
380
        struct list_head *n;
381
        struct pci_dev *dev;
382
 
383
        WARN_ON(in_interrupt());
384
        down_read(&pci_bus_sem);
385
        n = from ? from->global_list.prev : pci_devices.prev;
386
 
387
        while (n && (n != &pci_devices)) {
388
                dev = pci_dev_g(n);
389
                if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
390
                    (device == PCI_ANY_ID || dev->device == device))
391
                        goto exit;
392
                n = n->prev;
393
        }
394
        dev = NULL;
395
exit:
396
        dev = pci_dev_get(dev);
397
        up_read(&pci_bus_sem);
398
        pci_dev_put(from);
399
        return dev;
400
}
401
 
402
/**
403
 * pci_get_class - begin or continue searching for a PCI device by class
404
 * @class: search for a PCI device with this class designation
405
 * @from: Previous PCI device found in search, or %NULL for new search.
406
 *
407
 * Iterates through the list of known PCI devices.  If a PCI device is
408
 * found with a matching @class, the reference count to the device is
409
 * incremented and a pointer to its device structure is returned.
410
 * Otherwise, %NULL is returned.
411
 * A new search is initiated by passing %NULL as the @from argument.
412
 * Otherwise if @from is not %NULL, searches continue from next device
413
 * on the global list.  The reference count for @from is always decremented
414
 * if it is not %NULL.
415
 */
416
struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
417
{
418
        struct list_head *n;
419
        struct pci_dev *dev;
420
 
421
        WARN_ON(in_interrupt());
422
        down_read(&pci_bus_sem);
423
        n = from ? from->global_list.next : pci_devices.next;
424
 
425
        while (n && (n != &pci_devices)) {
426
                dev = pci_dev_g(n);
427
                if (dev->class == class)
428
                        goto exit;
429
                n = n->next;
430
        }
431
        dev = NULL;
432
exit:
433
        dev = pci_dev_get(dev);
434
        up_read(&pci_bus_sem);
435
        pci_dev_put(from);
436
        return dev;
437
}
438
 
439
const struct pci_device_id *pci_find_present(const struct pci_device_id *ids)
440
{
441
        struct pci_dev *dev;
442
        const struct pci_device_id *found = NULL;
443
 
444
        WARN_ON(in_interrupt());
445
        down_read(&pci_bus_sem);
446
        while (ids->vendor || ids->subvendor || ids->class_mask) {
447
                list_for_each_entry(dev, &pci_devices, global_list) {
448
                        if ((found = pci_match_one_device(ids, dev)) != NULL)
449
                                goto exit;
450
                }
451
                ids++;
452
        }
453
exit:
454
        up_read(&pci_bus_sem);
455
        return found;
456
}
457
 
458
/**
459
 * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
460
 * @ids: A pointer to a null terminated list of struct pci_device_id structures
461
 * that describe the type of PCI device the caller is trying to find.
462
 *
463
 * Obvious fact: You do not have a reference to any device that might be found
464
 * by this function, so if that device is removed from the system right after
465
 * this function is finished, the value will be stale.  Use this function to
466
 * find devices that are usually built into a system, or for a general hint as
467
 * to if another device happens to be present at this specific moment in time.
468
 */
469
int pci_dev_present(const struct pci_device_id *ids)
470
{
471
        return pci_find_present(ids) == NULL ? 0 : 1;
472
}
473
 
474
EXPORT_SYMBOL(pci_dev_present);
475
EXPORT_SYMBOL(pci_find_present);
476
 
477
#ifdef CONFIG_PCI_LEGACY
478
EXPORT_SYMBOL(pci_find_device);
479
EXPORT_SYMBOL(pci_find_slot);
480
#endif /* CONFIG_PCI_LEGACY */
481
 
482
/* For boot time work */
483
EXPORT_SYMBOL(pci_find_bus);
484
EXPORT_SYMBOL(pci_find_next_bus);
485
/* For everyone */
486
EXPORT_SYMBOL(pci_get_device);
487
EXPORT_SYMBOL(pci_get_device_reverse);
488
EXPORT_SYMBOL(pci_get_subsys);
489
EXPORT_SYMBOL(pci_get_slot);
490
EXPORT_SYMBOL(pci_get_bus_and_slot);
491
EXPORT_SYMBOL(pci_get_class);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.