Skip to content

Commit 215afa8

Browse files
committed
PCI: Introduce pci_walk_bus_reverse(), for_each_pci_dev_reverse()
PCI/TSM, the PCI core functionality for the PCIe TEE Device Interface Security Protocol (TDISP), has a need to walk all subordinate functions of a Device Security Manager (DSM) to setup a device security context. A DSM is physical function 0 of multi-function or SR-IOV device endpoint, or it is an upstream switch port. In error scenarios or when a TEE Security Manager (TSM) device is removed it needs to unwind all established DSM contexts. Introduce reverse versions of PCI device iteration helpers to mirror the setup path and ensure that dependent children are handled before parents. Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Link: https://patch.msgid.link/20251031212902.2256310-4-dan.j.williams@intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent f16469e commit 215afa8

5 files changed

Lines changed: 145 additions & 8 deletions

File tree

drivers/base/bus.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,19 @@ static struct device *next_device(struct klist_iter *i)
334334
return dev;
335335
}
336336

337+
static struct device *prev_device(struct klist_iter *i)
338+
{
339+
struct klist_node *n = klist_prev(i);
340+
struct device *dev = NULL;
341+
struct device_private *dev_prv;
342+
343+
if (n) {
344+
dev_prv = to_device_private_bus(n);
345+
dev = dev_prv->device;
346+
}
347+
return dev;
348+
}
349+
337350
/**
338351
* bus_for_each_dev - device iterator.
339352
* @bus: bus type.
@@ -414,6 +427,31 @@ struct device *bus_find_device(const struct bus_type *bus,
414427
}
415428
EXPORT_SYMBOL_GPL(bus_find_device);
416429

430+
struct device *bus_find_device_reverse(const struct bus_type *bus,
431+
struct device *start, const void *data,
432+
device_match_t match)
433+
{
434+
struct subsys_private *sp = bus_to_subsys(bus);
435+
struct klist_iter i;
436+
struct device *dev;
437+
438+
if (!sp)
439+
return NULL;
440+
441+
klist_iter_init_node(&sp->klist_devices, &i,
442+
(start ? &start->p->knode_bus : NULL));
443+
while ((dev = prev_device(&i))) {
444+
if (match(dev, data)) {
445+
get_device(dev);
446+
break;
447+
}
448+
}
449+
klist_iter_exit(&i);
450+
subsys_put(sp);
451+
return dev;
452+
}
453+
EXPORT_SYMBOL_GPL(bus_find_device_reverse);
454+
417455
static struct device_driver *next_driver(struct klist_iter *i)
418456
{
419457
struct klist_node *n = klist_next(i);

drivers/pci/bus.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
#include <linux/module.h>
1010
#include <linux/kernel.h>
11+
#include <linux/cleanup.h>
1112
#include <linux/pci.h>
1213
#include <linux/errno.h>
1314
#include <linux/ioport.h>
@@ -432,6 +433,27 @@ static int __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void
432433
return ret;
433434
}
434435

436+
static int __pci_walk_bus_reverse(struct pci_bus *top,
437+
int (*cb)(struct pci_dev *, void *),
438+
void *userdata)
439+
{
440+
struct pci_dev *dev;
441+
int ret = 0;
442+
443+
list_for_each_entry_reverse(dev, &top->devices, bus_list) {
444+
if (dev->subordinate) {
445+
ret = __pci_walk_bus_reverse(dev->subordinate, cb,
446+
userdata);
447+
if (ret)
448+
break;
449+
}
450+
ret = cb(dev, userdata);
451+
if (ret)
452+
break;
453+
}
454+
return ret;
455+
}
456+
435457
/**
436458
* pci_walk_bus - walk devices on/under bus, calling callback.
437459
* @top: bus whose devices should be walked
@@ -453,6 +475,23 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void
453475
}
454476
EXPORT_SYMBOL_GPL(pci_walk_bus);
455477

478+
/**
479+
* pci_walk_bus_reverse - walk devices on/under bus, calling callback.
480+
* @top: bus whose devices should be walked
481+
* @cb: callback to be called for each device found
482+
* @userdata: arbitrary pointer to be passed to callback
483+
*
484+
* Same semantics as pci_walk_bus(), but walks the bus in reverse order.
485+
*/
486+
void pci_walk_bus_reverse(struct pci_bus *top,
487+
int (*cb)(struct pci_dev *, void *), void *userdata)
488+
{
489+
down_read(&pci_bus_sem);
490+
__pci_walk_bus_reverse(top, cb, userdata);
491+
up_read(&pci_bus_sem);
492+
}
493+
EXPORT_SYMBOL_GPL(pci_walk_bus_reverse);
494+
456495
void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
457496
{
458497
lockdep_assert_held(&pci_bus_sem);

drivers/pci/search.c

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,45 @@ static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
282282
return pdev;
283283
}
284284

285+
static struct pci_dev *pci_get_dev_by_id_reverse(const struct pci_device_id *id,
286+
struct pci_dev *from)
287+
{
288+
struct device *dev;
289+
struct device *dev_start = NULL;
290+
struct pci_dev *pdev = NULL;
291+
292+
if (from)
293+
dev_start = &from->dev;
294+
dev = bus_find_device_reverse(&pci_bus_type, dev_start, (void *)id,
295+
match_pci_dev_by_id);
296+
if (dev)
297+
pdev = to_pci_dev(dev);
298+
pci_dev_put(from);
299+
return pdev;
300+
}
301+
302+
enum pci_search_direction {
303+
PCI_SEARCH_FORWARD,
304+
PCI_SEARCH_REVERSE,
305+
};
306+
307+
static struct pci_dev *__pci_get_subsys(unsigned int vendor, unsigned int device,
308+
unsigned int ss_vendor, unsigned int ss_device,
309+
struct pci_dev *from, enum pci_search_direction dir)
310+
{
311+
struct pci_device_id id = {
312+
.vendor = vendor,
313+
.device = device,
314+
.subvendor = ss_vendor,
315+
.subdevice = ss_device,
316+
};
317+
318+
if (dir == PCI_SEARCH_FORWARD)
319+
return pci_get_dev_by_id(&id, from);
320+
else
321+
return pci_get_dev_by_id_reverse(&id, from);
322+
}
323+
285324
/**
286325
* pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
287326
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
@@ -302,14 +341,8 @@ struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
302341
unsigned int ss_vendor, unsigned int ss_device,
303342
struct pci_dev *from)
304343
{
305-
struct pci_device_id id = {
306-
.vendor = vendor,
307-
.device = device,
308-
.subvendor = ss_vendor,
309-
.subdevice = ss_device,
310-
};
311-
312-
return pci_get_dev_by_id(&id, from);
344+
return __pci_get_subsys(vendor, device, ss_vendor, ss_device, from,
345+
PCI_SEARCH_FORWARD);
313346
}
314347
EXPORT_SYMBOL(pci_get_subsys);
315348

@@ -334,6 +367,19 @@ struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
334367
}
335368
EXPORT_SYMBOL(pci_get_device);
336369

370+
/*
371+
* Same semantics as pci_get_device(), except walks the PCI device list
372+
* in reverse discovery order.
373+
*/
374+
struct pci_dev *pci_get_device_reverse(unsigned int vendor,
375+
unsigned int device,
376+
struct pci_dev *from)
377+
{
378+
return __pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from,
379+
PCI_SEARCH_REVERSE);
380+
}
381+
EXPORT_SYMBOL(pci_get_device_reverse);
382+
337383
/**
338384
* pci_get_class - begin or continue searching for a PCI device by class
339385
* @class: search for a PCI device with this class designation

include/linux/device/bus.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ int bus_for_each_dev(const struct bus_type *bus, struct device *start,
150150
void *data, device_iter_t fn);
151151
struct device *bus_find_device(const struct bus_type *bus, struct device *start,
152152
const void *data, device_match_t match);
153+
struct device *bus_find_device_reverse(const struct bus_type *bus,
154+
struct device *start, const void *data,
155+
device_match_t match);
153156
/**
154157
* bus_find_device_by_name - device iterator for locating a particular device
155158
* of a specific name.

include/linux/pci.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus);
582582

583583
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
584584
#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
585+
#define for_each_pci_dev_reverse(d) \
586+
while ((d = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
585587

586588
static inline int pci_channel_offline(struct pci_dev *pdev)
587589
{
@@ -1242,6 +1244,8 @@ u64 pci_get_dsn(struct pci_dev *dev);
12421244

12431245
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
12441246
struct pci_dev *from);
1247+
struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device,
1248+
struct pci_dev *from);
12451249
struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
12461250
unsigned int ss_vendor, unsigned int ss_device,
12471251
struct pci_dev *from);
@@ -1661,6 +1665,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
16611665

16621666
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
16631667
void *userdata);
1668+
void pci_walk_bus_reverse(struct pci_bus *top,
1669+
int (*cb)(struct pci_dev *, void *), void *userdata);
16641670
int pci_cfg_space_size(struct pci_dev *dev);
16651671
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
16661672
resource_size_t pcibios_window_alignment(struct pci_bus *bus,
@@ -2049,6 +2055,11 @@ static inline struct pci_dev *pci_get_device(unsigned int vendor,
20492055
struct pci_dev *from)
20502056
{ return NULL; }
20512057

2058+
static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor,
2059+
unsigned int device,
2060+
struct pci_dev *from)
2061+
{ return NULL; }
2062+
20522063
static inline struct pci_dev *pci_get_subsys(unsigned int vendor,
20532064
unsigned int device,
20542065
unsigned int ss_vendor,

0 commit comments

Comments
 (0)