Skip to content

Commit 5d756f3

Browse files
committed
Merge branch 'pci/locking'
- Make pci_stop_dev() and pci_destroy_dev() concurrent safe (Keith Busch) - Move __pci_walk_bus() mutex up into the caller, which avoids the need for a parameter to control locking (Keith Busch) - Simplify __pci_walk_bus() by making it recursive (Keith Busch) - Unexport pci_walk_bus_locked(), which is only used internally by the PCI core (Keith Busch) * pci/locking: PCI: Unexport pci_walk_bus_locked() PCI: Convert __pci_walk_bus() to be recursive PCI: Move __pci_walk_bus() mutex to where we need it PCI: Make pci_destroy_dev() concurrent safe PCI: Make pci_stop_dev() concurrent safe
2 parents 665e4a3 + 38a18df commit 5d756f3

File tree

4 files changed

+44
-48
lines changed

4 files changed

+44
-48
lines changed

drivers/pci/bus.c

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ void pci_bus_add_device(struct pci_dev *dev)
358358
if (retval < 0 && retval != -EPROBE_DEFER)
359359
pci_warn(dev, "device attach failed (%d)\n", retval);
360360

361-
pci_dev_assign_added(dev, true);
361+
pci_dev_assign_added(dev);
362362

363363
if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
364364
retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
@@ -399,41 +399,23 @@ void pci_bus_add_devices(const struct pci_bus *bus)
399399
}
400400
EXPORT_SYMBOL(pci_bus_add_devices);
401401

402-
static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
403-
void *userdata, bool locked)
402+
static int __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
403+
void *userdata)
404404
{
405405
struct pci_dev *dev;
406-
struct pci_bus *bus;
407-
struct list_head *next;
408-
int retval;
406+
int ret = 0;
409407

410-
bus = top;
411-
if (!locked)
412-
down_read(&pci_bus_sem);
413-
next = top->devices.next;
414-
for (;;) {
415-
if (next == &bus->devices) {
416-
/* end of this bus, go up or finish */
417-
if (bus == top)
408+
list_for_each_entry(dev, &top->devices, bus_list) {
409+
ret = cb(dev, userdata);
410+
if (ret)
411+
break;
412+
if (dev->subordinate) {
413+
ret = __pci_walk_bus(dev->subordinate, cb, userdata);
414+
if (ret)
418415
break;
419-
next = bus->self->bus_list.next;
420-
bus = bus->self->bus;
421-
continue;
422416
}
423-
dev = list_entry(next, struct pci_dev, bus_list);
424-
if (dev->subordinate) {
425-
/* this is a pci-pci bridge, do its devices next */
426-
next = dev->subordinate->devices.next;
427-
bus = dev->subordinate;
428-
} else
429-
next = dev->bus_list.next;
430-
431-
retval = cb(dev, userdata);
432-
if (retval)
433-
break;
434417
}
435-
if (!locked)
436-
up_read(&pci_bus_sem);
418+
return ret;
437419
}
438420

439421
/**
@@ -451,17 +433,18 @@ static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void
451433
*/
452434
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
453435
{
454-
__pci_walk_bus(top, cb, userdata, false);
436+
down_read(&pci_bus_sem);
437+
__pci_walk_bus(top, cb, userdata);
438+
up_read(&pci_bus_sem);
455439
}
456440
EXPORT_SYMBOL_GPL(pci_walk_bus);
457441

458442
void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
459443
{
460444
lockdep_assert_held(&pci_bus_sem);
461445

462-
__pci_walk_bus(top, cb, userdata, true);
446+
__pci_walk_bus(top, cb, userdata);
463447
}
464-
EXPORT_SYMBOL_GPL(pci_walk_bus_locked);
465448

466449
struct pci_bus *pci_bus_get(struct pci_bus *bus)
467450
{

drivers/pci/pci.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ void __pci_bus_assign_resources(const struct pci_bus *bus,
323323
struct list_head *realloc_head,
324324
struct list_head *fail_head);
325325
bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
326+
void pci_walk_bus_locked(struct pci_bus *top,
327+
int (*cb)(struct pci_dev *, void *),
328+
void *userdata);
326329

327330
const char *pci_resource_name(struct pci_dev *dev, unsigned int i);
328331

@@ -493,17 +496,30 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
493496
#define PCI_DEV_ADDED 0
494497
#define PCI_DPC_RECOVERED 1
495498
#define PCI_DPC_RECOVERING 2
499+
#define PCI_DEV_REMOVED 3
496500

497-
static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
501+
static inline void pci_dev_assign_added(struct pci_dev *dev)
498502
{
499-
assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);
503+
smp_mb__before_atomic();
504+
set_bit(PCI_DEV_ADDED, &dev->priv_flags);
505+
smp_mb__after_atomic();
506+
}
507+
508+
static inline bool pci_dev_test_and_clear_added(struct pci_dev *dev)
509+
{
510+
return test_and_clear_bit(PCI_DEV_ADDED, &dev->priv_flags);
500511
}
501512

502513
static inline bool pci_dev_is_added(const struct pci_dev *dev)
503514
{
504515
return test_bit(PCI_DEV_ADDED, &dev->priv_flags);
505516
}
506517

518+
static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
519+
{
520+
return test_and_set_bit(PCI_DEV_REMOVED, &dev->priv_flags);
521+
}
522+
507523
#ifdef CONFIG_PCIEAER
508524
#include <linux/aer.h>
509525

drivers/pci/remove.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,20 @@ static void pci_stop_dev(struct pci_dev *dev)
3333
{
3434
pci_pme_active(dev, false);
3535

36-
if (pci_dev_is_added(dev)) {
37-
device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev),
38-
pci_pwrctl_unregister);
39-
device_release_driver(&dev->dev);
40-
pci_proc_detach_device(dev);
41-
pci_remove_sysfs_dev_files(dev);
42-
of_pci_remove_node(dev);
43-
44-
pci_dev_assign_added(dev, false);
45-
}
36+
if (!pci_dev_test_and_clear_added(dev))
37+
return;
38+
39+
device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev),
40+
pci_pwrctl_unregister);
41+
device_release_driver(&dev->dev);
42+
pci_proc_detach_device(dev);
43+
pci_remove_sysfs_dev_files(dev);
44+
of_pci_remove_node(dev);
4645
}
4746

4847
static void pci_destroy_dev(struct pci_dev *dev)
4948
{
50-
if (!dev->dev.kobj.parent)
49+
if (pci_dev_test_and_set_removed(dev))
5150
return;
5251

5352
pci_npem_remove(dev);

include/linux/pci.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,8 +1612,6 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
16121612

16131613
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
16141614
void *userdata);
1615-
void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
1616-
void *userdata);
16171615
int pci_cfg_space_size(struct pci_dev *dev);
16181616
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
16191617
void pci_setup_bridge(struct pci_bus *bus);

0 commit comments

Comments
 (0)