[PATCH 6.18 291/752] PCI: Fix pci_slot_lock () device locking

Sasha Levin
2026-02-28T17:52:12Z

From: Keith Busch <kbusch@kernel.org>

[ Upstream commit 1f5e57c622b4dc9b8e7d291d560138d92cfbe5bf ]

Like pci_bus_lock(), pci_slot_lock() needs to lock the bridge device to
prevent warnings like:

pcieport 0000:e2:05.0: unlocked secondary bus reset via: pciehp_reset_slot+0x55/0xa0

Take and release the lock for the bridge providing the slot for the
lock/trylock and unlock routines.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Link: https://patch.msgid.link/20260130165953.751063-3-kbusch@meta.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pci/pci.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 82e323b5aaa25..31d443f819a7c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5438,10 +5438,9 @@ static int pci_bus_trylock(struct pci_bus *bus)
/* Do any devices on or below this slot prevent a bus reset? */
static bool pci_slot_resettable(struct pci_slot *slot)
{
- struct pci_dev *dev;
+ struct pci_dev *dev, *bridge = slot->bus->self;

- if (slot->bus->self &&
- (slot->bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
+ if (bridge && (bridge->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET))
return false;

list_for_each_entry(dev, &slot->bus->devices, bus_list) {
@@ -5458,7 +5457,10 @@ static bool pci_slot_resettable(struct pci_slot *slot)
/* Lock devices from the top of the tree down */
static void pci_slot_lock(struct pci_slot *slot)
{
- struct pci_dev *dev;
+ struct pci_dev *dev, *bridge = slot->bus->self;
+
+ if (bridge)
+ pci_dev_lock(bridge);

list_for_each_entry(dev, &slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
@@ -5473,7 +5475,7 @@ static void pci_slot_lock(struct pci_slot *slot)
/* Unlock devices from the bottom of the tree up */
static void pci_slot_unlock(struct pci_slot *slot)
{
- struct pci_dev *dev;
+ struct pci_dev *dev, *bridge = slot->bus->self;

list_for_each_entry(dev, &slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
@@ -5483,12 +5485,18 @@ static void pci_slot_unlock(struct pci_slot *slot)
else
pci_dev_unlock(dev);
}
+
+ if (bridge)
+ pci_dev_unlock(bridge);
}

/* Return 1 on successful lock, 0 on contention */
static int pci_slot_trylock(struct pci_slot *slot)
{
- struct pci_dev *dev;
+ struct pci_dev *dev, *bridge = slot->bus->self;
+
+ if (bridge && !pci_dev_trylock(bridge))
+ return 0;

list_for_each_entry(dev, &slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
@@ -5513,6 +5521,9 @@ static int pci_slot_trylock(struct pci_slot *slot)
else
pci_dev_unlock(dev);
}
+
+ if (bridge)
+ pci_dev_unlock(bridge);
return 0;
}

--
2.51.0