Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+145 -8
+38
drivers/base/bus.c
··· 334 334 return dev; 335 335 } 336 336 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 + 337 350 /** 338 351 * bus_for_each_dev - device iterator. 339 352 * @bus: bus type. ··· 426 413 return dev; 427 414 } 428 415 EXPORT_SYMBOL_GPL(bus_find_device); 416 + 417 + struct device *bus_find_device_reverse(const struct bus_type *bus, 418 + struct device *start, const void *data, 419 + device_match_t match) 420 + { 421 + struct subsys_private *sp = bus_to_subsys(bus); 422 + struct klist_iter i; 423 + struct device *dev; 424 + 425 + if (!sp) 426 + return NULL; 427 + 428 + klist_iter_init_node(&sp->klist_devices, &i, 429 + (start ? &start->p->knode_bus : NULL)); 430 + while ((dev = prev_device(&i))) { 431 + if (match(dev, data)) { 432 + get_device(dev); 433 + break; 434 + } 435 + } 436 + klist_iter_exit(&i); 437 + subsys_put(sp); 438 + return dev; 439 + } 440 + EXPORT_SYMBOL_GPL(bus_find_device_reverse); 429 441 430 442 static struct device_driver *next_driver(struct klist_iter *i) 431 443 {
+39
drivers/pci/bus.c
··· 8 8 */ 9 9 #include <linux/module.h> 10 10 #include <linux/kernel.h> 11 + #include <linux/cleanup.h> 11 12 #include <linux/pci.h> 12 13 #include <linux/errno.h> 13 14 #include <linux/ioport.h> ··· 433 432 return ret; 434 433 } 435 434 435 + static int __pci_walk_bus_reverse(struct pci_bus *top, 436 + int (*cb)(struct pci_dev *, void *), 437 + void *userdata) 438 + { 439 + struct pci_dev *dev; 440 + int ret = 0; 441 + 442 + list_for_each_entry_reverse(dev, &top->devices, bus_list) { 443 + if (dev->subordinate) { 444 + ret = __pci_walk_bus_reverse(dev->subordinate, cb, 445 + userdata); 446 + if (ret) 447 + break; 448 + } 449 + ret = cb(dev, userdata); 450 + if (ret) 451 + break; 452 + } 453 + return ret; 454 + } 455 + 436 456 /** 437 457 * pci_walk_bus - walk devices on/under bus, calling callback. 438 458 * @top: bus whose devices should be walked ··· 474 452 up_read(&pci_bus_sem); 475 453 } 476 454 EXPORT_SYMBOL_GPL(pci_walk_bus); 455 + 456 + /** 457 + * pci_walk_bus_reverse - walk devices on/under bus, calling callback. 458 + * @top: bus whose devices should be walked 459 + * @cb: callback to be called for each device found 460 + * @userdata: arbitrary pointer to be passed to callback 461 + * 462 + * Same semantics as pci_walk_bus(), but walks the bus in reverse order. 463 + */ 464 + void pci_walk_bus_reverse(struct pci_bus *top, 465 + int (*cb)(struct pci_dev *, void *), void *userdata) 466 + { 467 + down_read(&pci_bus_sem); 468 + __pci_walk_bus_reverse(top, cb, userdata); 469 + up_read(&pci_bus_sem); 470 + } 471 + EXPORT_SYMBOL_GPL(pci_walk_bus_reverse); 477 472 478 473 void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata) 479 474 {
+54 -8
drivers/pci/search.c
··· 282 282 return pdev; 283 283 } 284 284 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 + 285 324 /** 286 325 * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id 287 326 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids ··· 341 302 unsigned int ss_vendor, unsigned int ss_device, 342 303 struct pci_dev *from) 343 304 { 344 - struct pci_device_id id = { 345 - .vendor = vendor, 346 - .device = device, 347 - .subvendor = ss_vendor, 348 - .subdevice = ss_device, 349 - }; 350 - 351 - return pci_get_dev_by_id(&id, from); 305 + return __pci_get_subsys(vendor, device, ss_vendor, ss_device, from, 306 + PCI_SEARCH_FORWARD); 352 307 } 353 308 EXPORT_SYMBOL(pci_get_subsys); 354 309 ··· 366 333 return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); 367 334 } 368 335 EXPORT_SYMBOL(pci_get_device); 336 + 337 + /* 338 + * Same semantics as pci_get_device(), except walks the PCI device list 339 + * in reverse discovery order. 340 + */ 341 + struct pci_dev *pci_get_device_reverse(unsigned int vendor, 342 + unsigned int device, 343 + struct pci_dev *from) 344 + { 345 + return __pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from, 346 + PCI_SEARCH_REVERSE); 347 + } 348 + EXPORT_SYMBOL(pci_get_device_reverse); 369 349 370 350 /** 371 351 * pci_get_class - begin or continue searching for a PCI device by class
+3
include/linux/device/bus.h
··· 150 150 void *data, device_iter_t fn); 151 151 struct device *bus_find_device(const struct bus_type *bus, struct device *start, 152 152 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); 153 156 /** 154 157 * bus_find_device_by_name - device iterator for locating a particular device 155 158 * of a specific name.
+11
include/linux/pci.h
··· 582 582 583 583 #define to_pci_dev(n) container_of(n, struct pci_dev, dev) 584 584 #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) 585 587 586 588 static inline int pci_channel_offline(struct pci_dev *pdev) 587 589 { ··· 1244 1242 1245 1243 struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, 1246 1244 struct pci_dev *from); 1245 + struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device, 1246 + struct pci_dev *from); 1247 1247 struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, 1248 1248 unsigned int ss_vendor, unsigned int ss_device, 1249 1249 struct pci_dev *from); ··· 1665 1661 1666 1662 void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), 1667 1663 void *userdata); 1664 + void pci_walk_bus_reverse(struct pci_bus *top, 1665 + int (*cb)(struct pci_dev *, void *), void *userdata); 1668 1666 int pci_cfg_space_size(struct pci_dev *dev); 1669 1667 unsigned char pci_bus_max_busnr(struct pci_bus *bus); 1670 1668 resource_size_t pcibios_window_alignment(struct pci_bus *bus, ··· 2053 2047 static inline struct pci_dev *pci_get_device(unsigned int vendor, 2054 2048 unsigned int device, 2055 2049 struct pci_dev *from) 2050 + { return NULL; } 2051 + 2052 + static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor, 2053 + unsigned int device, 2054 + struct pci_dev *from) 2056 2055 { return NULL; } 2057 2056 2058 2057 static inline struct pci_dev *pci_get_subsys(unsigned int vendor,