mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-06 13:16:22 +00:00
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
This commit is contained in:
commit
5d756f3fa8
@ -358,7 +358,7 @@ void pci_bus_add_device(struct pci_dev *dev)
|
|||||||
if (retval < 0 && retval != -EPROBE_DEFER)
|
if (retval < 0 && retval != -EPROBE_DEFER)
|
||||||
pci_warn(dev, "device attach failed (%d)\n", retval);
|
pci_warn(dev, "device attach failed (%d)\n", retval);
|
||||||
|
|
||||||
pci_dev_assign_added(dev, true);
|
pci_dev_assign_added(dev);
|
||||||
|
|
||||||
if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
|
if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) {
|
||||||
retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL,
|
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)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pci_bus_add_devices);
|
EXPORT_SYMBOL(pci_bus_add_devices);
|
||||||
|
|
||||||
static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
static int __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||||
void *userdata, bool locked)
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
struct pci_bus *bus;
|
int ret = 0;
|
||||||
struct list_head *next;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
bus = top;
|
list_for_each_entry(dev, &top->devices, bus_list) {
|
||||||
if (!locked)
|
ret = cb(dev, userdata);
|
||||||
down_read(&pci_bus_sem);
|
if (ret)
|
||||||
next = top->devices.next;
|
|
||||||
for (;;) {
|
|
||||||
if (next == &bus->devices) {
|
|
||||||
/* end of this bus, go up or finish */
|
|
||||||
if (bus == top)
|
|
||||||
break;
|
|
||||||
next = bus->self->bus_list.next;
|
|
||||||
bus = bus->self->bus;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dev = list_entry(next, struct pci_dev, bus_list);
|
|
||||||
if (dev->subordinate) {
|
|
||||||
/* this is a pci-pci bridge, do its devices next */
|
|
||||||
next = dev->subordinate->devices.next;
|
|
||||||
bus = dev->subordinate;
|
|
||||||
} else
|
|
||||||
next = dev->bus_list.next;
|
|
||||||
|
|
||||||
retval = cb(dev, userdata);
|
|
||||||
if (retval)
|
|
||||||
break;
|
break;
|
||||||
|
if (dev->subordinate) {
|
||||||
|
ret = __pci_walk_bus(dev->subordinate, cb, userdata);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!locked)
|
return ret;
|
||||||
up_read(&pci_bus_sem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -451,7 +433,9 @@ static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void
|
|||||||
*/
|
*/
|
||||||
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
|
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
|
||||||
{
|
{
|
||||||
__pci_walk_bus(top, cb, userdata, false);
|
down_read(&pci_bus_sem);
|
||||||
|
__pci_walk_bus(top, cb, userdata);
|
||||||
|
up_read(&pci_bus_sem);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_walk_bus);
|
EXPORT_SYMBOL_GPL(pci_walk_bus);
|
||||||
|
|
||||||
@ -459,9 +443,8 @@ void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *
|
|||||||
{
|
{
|
||||||
lockdep_assert_held(&pci_bus_sem);
|
lockdep_assert_held(&pci_bus_sem);
|
||||||
|
|
||||||
__pci_walk_bus(top, cb, userdata, true);
|
__pci_walk_bus(top, cb, userdata);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pci_walk_bus_locked);
|
|
||||||
|
|
||||||
struct pci_bus *pci_bus_get(struct pci_bus *bus)
|
struct pci_bus *pci_bus_get(struct pci_bus *bus)
|
||||||
{
|
{
|
||||||
|
@ -323,6 +323,9 @@ void __pci_bus_assign_resources(const struct pci_bus *bus,
|
|||||||
struct list_head *realloc_head,
|
struct list_head *realloc_head,
|
||||||
struct list_head *fail_head);
|
struct list_head *fail_head);
|
||||||
bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
|
bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
|
||||||
|
void pci_walk_bus_locked(struct pci_bus *top,
|
||||||
|
int (*cb)(struct pci_dev *, void *),
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
const char *pci_resource_name(struct pci_dev *dev, unsigned int i);
|
const char *pci_resource_name(struct pci_dev *dev, unsigned int i);
|
||||||
|
|
||||||
@ -493,10 +496,18 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
|
|||||||
#define PCI_DEV_ADDED 0
|
#define PCI_DEV_ADDED 0
|
||||||
#define PCI_DPC_RECOVERED 1
|
#define PCI_DPC_RECOVERED 1
|
||||||
#define PCI_DPC_RECOVERING 2
|
#define PCI_DPC_RECOVERING 2
|
||||||
|
#define PCI_DEV_REMOVED 3
|
||||||
|
|
||||||
static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
|
static inline void pci_dev_assign_added(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);
|
smp_mb__before_atomic();
|
||||||
|
set_bit(PCI_DEV_ADDED, &dev->priv_flags);
|
||||||
|
smp_mb__after_atomic();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool pci_dev_test_and_clear_added(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return test_and_clear_bit(PCI_DEV_ADDED, &dev->priv_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool pci_dev_is_added(const struct pci_dev *dev)
|
static inline bool pci_dev_is_added(const struct pci_dev *dev)
|
||||||
@ -504,6 +515,11 @@ static inline bool pci_dev_is_added(const struct pci_dev *dev)
|
|||||||
return test_bit(PCI_DEV_ADDED, &dev->priv_flags);
|
return test_bit(PCI_DEV_ADDED, &dev->priv_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
return test_and_set_bit(PCI_DEV_REMOVED, &dev->priv_flags);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PCIEAER
|
#ifdef CONFIG_PCIEAER
|
||||||
#include <linux/aer.h>
|
#include <linux/aer.h>
|
||||||
|
|
||||||
|
@ -33,21 +33,20 @@ static void pci_stop_dev(struct pci_dev *dev)
|
|||||||
{
|
{
|
||||||
pci_pme_active(dev, false);
|
pci_pme_active(dev, false);
|
||||||
|
|
||||||
if (pci_dev_is_added(dev)) {
|
if (!pci_dev_test_and_clear_added(dev))
|
||||||
device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev),
|
return;
|
||||||
pci_pwrctl_unregister);
|
|
||||||
device_release_driver(&dev->dev);
|
|
||||||
pci_proc_detach_device(dev);
|
|
||||||
pci_remove_sysfs_dev_files(dev);
|
|
||||||
of_pci_remove_node(dev);
|
|
||||||
|
|
||||||
pci_dev_assign_added(dev, false);
|
device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev),
|
||||||
}
|
pci_pwrctl_unregister);
|
||||||
|
device_release_driver(&dev->dev);
|
||||||
|
pci_proc_detach_device(dev);
|
||||||
|
pci_remove_sysfs_dev_files(dev);
|
||||||
|
of_pci_remove_node(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_destroy_dev(struct pci_dev *dev)
|
static void pci_destroy_dev(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
if (!dev->dev.kobj.parent)
|
if (pci_dev_test_and_set_removed(dev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pci_npem_remove(dev);
|
pci_npem_remove(dev);
|
||||||
|
@ -1612,8 +1612,6 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
|
|||||||
|
|
||||||
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
||||||
void *userdata);
|
void *userdata);
|
||||||
void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
|
|
||||||
void *userdata);
|
|
||||||
int pci_cfg_space_size(struct pci_dev *dev);
|
int pci_cfg_space_size(struct pci_dev *dev);
|
||||||
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
|
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
|
||||||
void pci_setup_bridge(struct pci_bus *bus);
|
void pci_setup_bridge(struct pci_bus *bus);
|
||||||
|
Loading…
Reference in New Issue
Block a user