diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2024-07-19 10:10:23 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2024-07-19 10:10:23 -0500 |
commit | 62281339e34ba39c062d7ee13a02e9f2f3c739f8 (patch) | |
tree | 1aba8974bde592f7d8605553e8e5cfe874a02577 | |
parent | 675ba773c6b3175b331db0933eea88346ec78d83 (diff) | |
parent | a4e772898f8bf2e7e1cf661a12c60a5612c4afab (diff) | |
download | linux-62281339e34ba39c062d7ee13a02e9f2f3c739f8.tar.gz linux-62281339e34ba39c062d7ee13a02e9f2f3c739f8.tar.bz2 linux-62281339e34ba39c062d7ee13a02e9f2f3c739f8.zip |
Merge branch 'pci/reset'
- Warn about doing a Secondary Bus Reset without holding the device lock
(Dan Williams)
- Lock bridge in addition to downstream hierarchy before doing a Secondary
Bus Reset (Dan Williams)
* pci/reset:
PCI: Add missing bridge lock to pci_bus_lock()
PCI: Warn on missing cfg_access_lock during secondary bus reset
-rw-r--r-- | drivers/pci/pci.c | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ef85cba4c8fb..8cf0941f70d1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4954,6 +4954,9 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) int pci_bridge_secondary_bus_reset(struct pci_dev *dev) { lock_map_assert_held(&dev->cfg_access_lock); + if (!dev->block_cfg_access) + pci_warn_once(dev, "unlocked secondary bus reset via: %pS\n", + __builtin_return_address(0)); pcibios_reset_secondary_bus(dev); return pci_bridge_wait_for_secondary_bus(dev, "bus reset"); @@ -5512,10 +5515,12 @@ static void pci_bus_lock(struct pci_bus *bus) { struct pci_dev *dev; + pci_dev_lock(bus->self); list_for_each_entry(dev, &bus->devices, bus_list) { - pci_dev_lock(dev); if (dev->subordinate) pci_bus_lock(dev->subordinate); + else + pci_dev_lock(dev); } } @@ -5527,8 +5532,10 @@ static void pci_bus_unlock(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->subordinate) pci_bus_unlock(dev->subordinate); - pci_dev_unlock(dev); + else + pci_dev_unlock(dev); } + pci_dev_unlock(bus->self); } /* Return 1 on successful lock, 0 on contention */ @@ -5536,15 +5543,15 @@ static int pci_bus_trylock(struct pci_bus *bus) { struct pci_dev *dev; + if (!pci_dev_trylock(bus->self)) + return 0; + list_for_each_entry(dev, &bus->devices, bus_list) { - if (!pci_dev_trylock(dev)) - goto unlock; if (dev->subordinate) { - if (!pci_bus_trylock(dev->subordinate)) { - pci_dev_unlock(dev); + if (!pci_bus_trylock(dev->subordinate)) goto unlock; - } - } + } else if (!pci_dev_trylock(dev)) + goto unlock; } return 1; @@ -5552,8 +5559,10 @@ unlock: list_for_each_entry_continue_reverse(dev, &bus->devices, bus_list) { if (dev->subordinate) pci_bus_unlock(dev->subordinate); - pci_dev_unlock(dev); + else + pci_dev_unlock(dev); } + pci_dev_unlock(bus->self); return 0; } @@ -5585,9 +5594,10 @@ static void pci_slot_lock(struct pci_slot *slot) list_for_each_entry(dev, &slot->bus->devices, bus_list) { if (!dev->slot || dev->slot != slot) continue; - pci_dev_lock(dev); if (dev->subordinate) pci_bus_lock(dev->subordinate); + else + pci_dev_lock(dev); } } @@ -5613,14 +5623,13 @@ static int pci_slot_trylock(struct pci_slot *slot) list_for_each_entry(dev, &slot->bus->devices, bus_list) { if (!dev->slot || dev->slot != slot) continue; - if (!pci_dev_trylock(dev)) - goto unlock; if (dev->subordinate) { if (!pci_bus_trylock(dev->subordinate)) { pci_dev_unlock(dev); goto unlock; } - } + } else if (!pci_dev_trylock(dev)) + goto unlock; } return 1; @@ -5631,7 +5640,8 @@ unlock: continue; if (dev->subordinate) pci_bus_unlock(dev->subordinate); - pci_dev_unlock(dev); + else + pci_dev_unlock(dev); } return 0; } |