]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: Fix pci_slot_lock () device locking
authorKeith Busch <kbusch@kernel.org>
Fri, 30 Jan 2026 16:59:51 +0000 (08:59 -0800)
committerSasha Levin <sashal@kernel.org>
Wed, 4 Mar 2026 12:20:33 +0000 (07:20 -0500)
[ 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

index a05978f5cf2c770370dcc3d0baae94200bdb70a2..41596bc72f1dca862745da347acbf9f66fc63335 100644 (file)
@@ -5293,10 +5293,9 @@ unlock:
 /* 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) {
@@ -5313,7 +5312,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)
@@ -5328,7 +5330,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)
@@ -5338,12 +5340,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)
@@ -5368,6 +5376,9 @@ unlock:
                else
                        pci_dev_unlock(dev);
        }
+
+       if (bridge)
+               pci_dev_unlock(bridge);
        return 0;
 }