linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] Don't make noise about disconnected USB4 devices
@ 2025-06-20  2:55 Mario Limonciello
  2025-06-20  2:55 ` [PATCH v3 1/2] PCI/PM: Skip resuming to D0 if disconnected Mario Limonciello
  2025-06-20  2:55 ` [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug Mario Limonciello
  0 siblings, 2 replies; 19+ messages in thread
From: Mario Limonciello @ 2025-06-20  2:55 UTC (permalink / raw)
  To: Bjorn Helgaas, open list:PCI SUBSYSTEM
  Cc: linux-pm, Rafael J . Wysocki, Mario Limonciello

From: Mario Limonciello <mario.limonciello@amd.com>

When a USB4 or TBT3 dock is disconnected a lot of warnings and errors
are emitted related to the PCIe tunnels in the dock.

The messages are loud, but it's mostly because the functions that
emit the messages don't check whether the device is actually alive.
The PCIe hotplug services mark the device disconnected, so that
can be used to avoid an unnecessary wakeup on a disconnected device.

There is also a case of a runtime PM imbalance from this situation that
is fixed.

v2: https://lore.kernel.org/linux-pci/20250616192813.3829124-1-superm1@kernel.org/

Mario Limonciello (2):
  PCI/PM: Skip resuming to D0 if disconnected
  PCI: Fix runtime PM usage count underflow on device unplug

 drivers/pci/pci-driver.c | 3 ---
 drivers/pci/pci.c        | 5 +++++
 drivers/pci/pci.h        | 1 +
 3 files changed, 6 insertions(+), 3 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 1/2] PCI/PM: Skip resuming to D0 if disconnected
  2025-06-20  2:55 [PATCH v3 0/2] Don't make noise about disconnected USB4 devices Mario Limonciello
@ 2025-06-20  2:55 ` Mario Limonciello
  2025-06-23 17:48   ` Lukas Wunner
  2025-06-20  2:55 ` [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug Mario Limonciello
  1 sibling, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2025-06-20  2:55 UTC (permalink / raw)
  To: Bjorn Helgaas, open list:PCI SUBSYSTEM
  Cc: linux-pm, Rafael J . Wysocki, Mario Limonciello, Lukas Wunner

From: Mario Limonciello <mario.limonciello@amd.com>

When a USB4 dock is unplugged the PCIe bridge it's connected to will
remove issue a "Link Down" and "Card not detected event". The PCI core
will treat this as a surprise hotplug event and unconfigure all downstream
devices. This involves setting the device error state to
`pci_channel_io_perm_failure` which pci_dev_is_disconnected() will check.

It doesn't make sense to runtime resume disconnected devices to D0 and
report the (expected) error to do so.  It is still useful information
that a device is disconnected though, so add an info message for that
purpose.

Suggested-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
v3:
 * Adjust text and subject
 * Add an info message instead
v2:
 * Use pci_dev_is_disconnected()
v1: https://lore.kernel.org/linux-usb/20250609020223.269407-1-superm1@kernel.org/T/#mf95c947990d016fbfccfd11afe60b8ae08aafa0b
---
 drivers/pci/pci.c | 5 +++++
 drivers/pci/pci.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 9e42090fb1089..160a9a482c732 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1374,6 +1374,11 @@ int pci_power_up(struct pci_dev *dev)
 		return -EIO;
 	}
 
+	if (pci_dev_is_disconnected(dev)) {
+		dev->current_state = PCI_D3cold;
+		return -EIO;
+	}
+
 	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 	if (PCI_POSSIBLE_ERROR(pmcsr)) {
 		pci_err(dev, "Unable to change power state from %s to D0, device inaccessible\n",
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 12215ee72afb6..57aaf9c63e2e8 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -550,6 +550,7 @@ static inline bool pci_dev_set_io_state(struct pci_dev *dev,
 
 static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
 {
+	pci_info(dev, "Device disconnected\n");
 	pci_dev_set_io_state(dev, pci_channel_io_perm_failure);
 	pci_doe_disconnected(dev);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-20  2:55 [PATCH v3 0/2] Don't make noise about disconnected USB4 devices Mario Limonciello
  2025-06-20  2:55 ` [PATCH v3 1/2] PCI/PM: Skip resuming to D0 if disconnected Mario Limonciello
@ 2025-06-20  2:55 ` Mario Limonciello
  2025-06-21 19:05   ` Lukas Wunner
  1 sibling, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2025-06-20  2:55 UTC (permalink / raw)
  To: Bjorn Helgaas, open list:PCI SUBSYSTEM
  Cc: linux-pm, Rafael J . Wysocki, Mario Limonciello

From: Mario Limonciello <mario.limonciello@amd.com>

When a USB4 dock is unplugged the PCIe bridge it's connected to will
remove issue a "Link Down" and "Card not detected event". The PCI core
will treat this as a surprise hotplug event and unconfigure all downstream
devices.

pci_stop_bus_device() will call device_release_driver(). As part of device
release sequence pm_runtime_put_sync() is called for the device which will
decrement the runtime counter to 0. After this, the device remove callback
(pci_device_remove()) will be called which again calls pm_runtime_put_sync()
but as the counter is already 0 will cause an underflow.

This behavior was introduced in commit 967577b062417 ("PCI/PM: Keep runtime
PM enabled for unbound PCI devices") to prevent asymmetrical get/put from
probe/remove, but this misses out on the point that when releasing a driver
the usage count is decremented from the device core.

Drop the extra call from pci_device_remove().

Fixes: 967577b062417 ("PCI/PM: Keep runtime PM enabled for unbound PCI devices")
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
v3:
 * git archeaology
 * Drop call alltogether, not just for the device disconnected case
v2:
 * Use pci_dev_is_disconnected()
v1: https://lore.kernel.org/linux-usb/20250609020223.269407-1-superm1@kernel.org/T/#mf95c947990d016fbfccfd11afe60b8ae08aafa0b
---
 drivers/pci/pci-driver.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index b78b98133e7df..63f1cb11906ad 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -478,9 +478,6 @@ static void pci_device_remove(struct device *dev)
 	pci_dev->driver = NULL;
 	pci_iov_remove(pci_dev);
 
-	/* Undo the runtime PM settings in local_pci_probe() */
-	pm_runtime_put_sync(dev);
-
 	/*
 	 * If the device is still on, set the power state as "unknown",
 	 * since it might change by the next time we load the driver.
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-20  2:55 ` [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug Mario Limonciello
@ 2025-06-21 19:05   ` Lukas Wunner
  2025-06-21 19:56     ` Mario Limonciello
  0 siblings, 1 reply; 19+ messages in thread
From: Lukas Wunner @ 2025-06-21 19:05 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On Thu, Jun 19, 2025 at 09:55:35PM -0500, Mario Limonciello wrote:
> When a USB4 dock is unplugged the PCIe bridge it's connected to will
> remove issue a "Link Down" and "Card not detected event". The PCI core
> will treat this as a surprise hotplug event and unconfigure all downstream
> devices.
> 
> pci_stop_bus_device() will call device_release_driver(). As part of device
> release sequence pm_runtime_put_sync() is called for the device which will
> decrement the runtime counter to 0. After this, the device remove callback
> (pci_device_remove()) will be called which again calls pm_runtime_put_sync()
> but as the counter is already 0 will cause an underflow.
> 
> This behavior was introduced in commit 967577b062417 ("PCI/PM: Keep runtime
> PM enabled for unbound PCI devices") to prevent asymmetrical get/put from
> probe/remove, but this misses out on the point that when releasing a driver
> the usage count is decremented from the device core.
> 
> Drop the extra call from pci_device_remove().
> 
> Fixes: 967577b062417 ("PCI/PM: Keep runtime PM enabled for unbound PCI devices")

This doesn't look right.  The refcount underflow issue seems new,
we surely haven't been doing the wrong thing since 2012.


> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -478,9 +478,6 @@ static void pci_device_remove(struct device *dev)
>  	pci_dev->driver = NULL;
>  	pci_iov_remove(pci_dev);
>  
> -	/* Undo the runtime PM settings in local_pci_probe() */
> -	pm_runtime_put_sync(dev);
> -

local_pci_probe() increases the refcount to keep the device in D0.
If the driver wants to use runtime suspend, it needs to decrement
the refcount on ->probe() and re-increment on ->remove().

In the dmesg output attached to...

https://bugzilla.kernel.org/show_bug.cgi?id=220216

... the device exhibiting the refcount underflow is a PCIe port.
Are you also seeing this on a PCIe port or is it a different device?

So the refcount decrement happens in pcie_portdrv_probe() and
the refcount increment happens in pcie_portdrv_remove().
Both times it's conditional on pci_bridge_d3_possible().
Does that return a different value on probe versus remove?

Does any of the port service drivers decrement the refcount
once too often?  I've just looked through pciehp but cannot
find anything out of the ordinary.

Looking through recent changes, 002bf2fbc00e and bca84a7b93fd
look like potential candidates causing a regression, but the
former is for AER (which isn't used in the dmesg attached to
the bugzilla) and the latter touches suspend on system sleep,
not runtime suspend.

Can you maybe instrument the pm_runtime_{get,put}*() functions
with a printk() and/or dump_stack() to see where a gratuitous
refcount decrement occurs?

Alternatively, is there a known-good kernel version which does
not exhibit the issue and which could serve as anchor for
git bisect?

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-21 19:05   ` Lukas Wunner
@ 2025-06-21 19:56     ` Mario Limonciello
  2025-06-22  4:43       ` Lukas Wunner
  0 siblings, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2025-06-21 19:56 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello



On 6/21/25 2:05 PM, Lukas Wunner wrote:
> On Thu, Jun 19, 2025 at 09:55:35PM -0500, Mario Limonciello wrote:
>> When a USB4 dock is unplugged the PCIe bridge it's connected to will
>> remove issue a "Link Down" and "Card not detected event". The PCI core
>> will treat this as a surprise hotplug event and unconfigure all downstream
>> devices.
>>
>> pci_stop_bus_device() will call device_release_driver(). As part of device
>> release sequence pm_runtime_put_sync() is called for the device which will
>> decrement the runtime counter to 0. After this, the device remove callback
>> (pci_device_remove()) will be called which again calls pm_runtime_put_sync()
>> but as the counter is already 0 will cause an underflow.
>>
>> This behavior was introduced in commit 967577b062417 ("PCI/PM: Keep runtime
>> PM enabled for unbound PCI devices") to prevent asymmetrical get/put from
>> probe/remove, but this misses out on the point that when releasing a driver
>> the usage count is decremented from the device core.
>>
>> Drop the extra call from pci_device_remove().
>>
>> Fixes: 967577b062417 ("PCI/PM: Keep runtime PM enabled for unbound PCI devices")
> 
> This doesn't look right.  The refcount underflow issue seems new,
> we surely haven't been doing the wrong thing since 2012.
> 
> 
>> --- a/drivers/pci/pci-driver.c
>> +++ b/drivers/pci/pci-driver.c
>> @@ -478,9 +478,6 @@ static void pci_device_remove(struct device *dev)
>>   	pci_dev->driver = NULL;
>>   	pci_iov_remove(pci_dev);
>>   
>> -	/* Undo the runtime PM settings in local_pci_probe() */
>> -	pm_runtime_put_sync(dev);
>> -
> 
> local_pci_probe() increases the refcount to keep the device in D0.
> If the driver wants to use runtime suspend, it needs to decrement
> the refcount on ->probe() and re-increment on ->remove().
> 
> In the dmesg output attached to...
> 
> https://bugzilla.kernel.org/show_bug.cgi?id=220216
> 
> ... the device exhibiting the refcount underflow is a PCIe port.
> Are you also seeing this on a PCIe port or is it a different device?

The device with the underflow is the disconnected PCIe bridge.

In my case it was this bridge that was downstream.

pci 0000:02:04.0: [8086:15ef] type 01 class 0x060400 PCIe Switch 
Downstream Port
pci 0000:02:04.0: PCI bridge to [bus 04]
pci 0000:02:04.0: enabling Extended Tags
pci 0000:02:04.0: supports D1 D2
pci 0000:02:04.0: PME# supported from D0 D1 D2 D3hot D3cold

> 
> So the refcount decrement happens in pcie_portdrv_probe() and
> the refcount increment happens in pcie_portdrv_remove().
> Both times it's conditional on pci_bridge_d3_possible().
> Does that return a different value on probe versus remove?
> 
> Does any of the port service drivers decrement the refcount
> once too often?  I've just looked through pciehp but cannot
> find anything out of the ordinary.
> 
> Looking through recent changes, 002bf2fbc00e and bca84a7b93fd
> look like potential candidates causing a regression, but the
> former is for AER (which isn't used in the dmesg attached to
> the bugzilla) and the latter touches suspend on system sleep,
> not runtime suspend.
> 
> Can you maybe instrument the pm_runtime_{get,put}*() functions
> with a printk() and/or dump_stack() to see where a gratuitous
> refcount decrement occurs?
> 
That's exactly what I did to conclude this call was an extra one.


Here's the drop to 0:

pm_runtime: 0000:02:04.0 usage count is now 0 from 
__pm_runtime_idle+0x6f/0xd0
CPU: 7 UID: 0 PID: 196 Comm: irq/36-pciehp Not tainted 
6.16.0-rc2-00086-g4156cebf8a54 #281 PREEMPT(full) 
48d9dd361274f6fbfa98cd17f346d017a60ec738
Hardware name: Framework Laptop 13 (AMD Ryzen AI 300 Series)/FRANMGCP09, 
BIOS 03.03 03/10/2025
Call Trace:
  <TASK>
  dump_stack_lvl+0x53/0x70
  rpm_drop_usage_count+0x50/0x90
  __pm_runtime_idle+0x6f/0xd0
  device_release_driver_internal+0x197/0x200
  pci_stop_bus_device+0x6d/0x90
  pci_stop_bus_device+0x2c/0x90
  pci_stop_and_remove_bus_device+0x12/0x20
  pciehp_unconfigure_device+0x97/0x160
  pciehp_disable_slot+0x66/0x140
  pciehp_handle_presence_or_link_change+0x86/0x4b0
  pciehp_ist+0x196/0x280
  irq_thread_fn+0x20/0x60
  irq_thread+0x1ae/0x290
  ? __pfx_irq_thread_fn+0x10/0x10
  ? __pfx_irq_thread_dtor+0x10/0x10
  ? __pfx_irq_thread+0x10/0x10
  kthread+0xfb/0x260
  ? __pfx_kthread+0x10/0x10
  ret_from_fork+0x14a/0x180
  ? __pfx_kthread+0x10/0x10
  ret_from_fork_asm+0x1a/0x30
  </TASK>

And then here is a dev_WARN at the underflow case.

------------[ cut here ]------------
pcieport 0000:02:04.0: Runtime PM usage count underflow!
WARNING: CPU: 7 PID: 196 at drivers/base/power/runtime.c:1084 
rpm_drop_usage_count+0x82/0x90
Modules linked in: vivaldi_fmap aesni_intel thunderbolt(+) ccp nvme_core 
i8042 tpm_tis i2c_hid_acpi serio tpm_tis_core i2c_hid tpm libaescfb 
ecdh_generic
CPU: 7 UID: 0 PID: 196 Comm: irq/36-pciehp Not tainted 
6.16.0-rc2-00086-g4156cebf8a54 #281 PREEMPT(full) 
48d9dd361274f6fbfa98cd17f346d017a60ec738
Hardware name: Framework Laptop 13 (AMD Ryzen AI 300 Series)/FRANMGCP09, 
BIOS 03.03 03/10/2025
RIP: 0010:rpm_drop_usage_count+0x82/0x90
Code: f0 ff 87 b0 01 00 00 48 8b 5f 50 48 85 db 75 03 48 8b 1f e8 20 44 
fe ff 48 89 da 48 c7 c7 80 52 c8 a0 48 89 c6 e8 8e 3f 6e ff <0f> 0b bb 
ea ff ff ff eb 9b>
RSP: 0018:ffffd240c09e7c28 EFLAGS: 00010282
RAX: 0000000000000000 RBX: ffff8997c213f430 RCX: 0000000000000027
RDX: ffff899f1dbdc288 RSI: 0000000000000001 RDI: ffff899f1dbdc280
RBP: ffff8997c29150c8 R08: 0000000000000000 R09: 0000000000000003
R10: ffffd240c09e7ab0 R11: ffff899f1e129368 R12: ffffffffa1161ca0
R13: ffff8997c2915148 R14: 0000000000000080 R15: ffff8997c1613914
FS:  0000000000000000(0000) GS:ffff899f7c175000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fbbc1357750 CR3: 0000000111245000 CR4: 0000000000b50ef0
Call Trace:
  <TASK>
  __pm_runtime_idle+0x6f/0xd0
  pci_device_remove+0x7e/0xb0
  device_release_driver_internal+0x19f/0x200
  pci_stop_bus_device+0x6d/0x90
  pci_stop_bus_device+0x2c/0x90
  pci_stop_and_remove_bus_device+0x12/0x20
  pciehp_unconfigure_device+0x97/0x160
  pciehp_disable_slot+0x66/0x140
  pciehp_handle_presence_or_link_change+0x86/0x4b0
  pciehp_ist+0x196/0x280
  irq_thread_fn+0x20/0x60
  irq_thread+0x1ae/0x290
  ? __pfx_irq_thread_fn+0x10/0x10
  ? __pfx_irq_thread_dtor+0x10/0x10
  ? __pfx_irq_thread+0x10/0x10
  kthread+0xfb/0x260
  ? __pfx_kthread+0x10/0x10
  ret_from_fork+0x14a/0x180
  ? __pfx_kthread+0x10/0x10
  ret_from_fork_asm+0x1a/0x30
  </TASK>
---[ end trace 0000000000000000 ]---

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-21 19:56     ` Mario Limonciello
@ 2025-06-22  4:43       ` Lukas Wunner
  2025-06-22 18:39         ` Mario Limonciello
  0 siblings, 1 reply; 19+ messages in thread
From: Lukas Wunner @ 2025-06-22  4:43 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On Sat, Jun 21, 2025 at 02:56:08PM -0500, Mario Limonciello wrote:
> On 6/21/25 2:05 PM, Lukas Wunner wrote:
> > In the dmesg output attached to...
> > 
> > https://bugzilla.kernel.org/show_bug.cgi?id=220216
> > 
> > ... the device exhibiting the refcount underflow is a PCIe port.
> > Are you also seeing this on a PCIe port or is it a different device?
> 
> The device with the underflow is the disconnected PCIe bridge.
> 
> In my case it was this bridge that was downstream.

Okay, in both cases the refcount underflow occurs on a PCIe port.
So it seems likely the gratuitous refcount decrement is in portdrv.c
or one of the port services drivers.

Your patch changes the code path for *all* PCI devices.
Not just PCIe ports.  Hence it's likely not the right fix.

It may fix the issue on this particular PCIe port but
I strongly suspect it'll leak a runtime PM ref on all other devices.


> > So the refcount decrement happens in pcie_portdrv_probe() and
> > the refcount increment happens in pcie_portdrv_remove().
> > Both times it's conditional on pci_bridge_d3_possible().
> > Does that return a different value on probe versus remove?

Could you please answer this?


> > Does any of the port service drivers decrement the refcount
> > once too often?  I've just looked through pciehp but cannot
> > find anything out of the ordinary.
> > 
> > Looking through recent changes, 002bf2fbc00e and bca84a7b93fd
> > look like potential candidates causing a regression, but the
> > former is for AER (which isn't used in the dmesg attached to
> > the bugzilla) and the latter touches suspend on system sleep,
> > not runtime suspend.
> > 
> > Can you maybe instrument the pm_runtime_{get,put}*() functions
> > with a printk() and/or dump_stack() to see where a gratuitous
> > refcount decrement occurs?
> 
> That's exactly what I did to conclude this call was an extra one.
> 
> Here's the drop to 0:

The drop to 0 is uninteresting.  You need to record *all*
refcount increments/decrements so that we can see where the
gratuitous one occurs.  It happens earlier than the drop to 0.

However, please first check whether the pci_bridge_d3_possible()
return value changes on probe versus remove of the PCIe port
in question.  If it does, then that's the root cause and there's
no need to look any further.

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-22  4:43       ` Lukas Wunner
@ 2025-06-22 18:39         ` Mario Limonciello
  2025-06-23  1:47           ` Mario Limonciello
  2025-06-23  6:43           ` Lukas Wunner
  0 siblings, 2 replies; 19+ messages in thread
From: Mario Limonciello @ 2025-06-22 18:39 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On 6/21/2025 11:43 PM, Lukas Wunner wrote:
> On Sat, Jun 21, 2025 at 02:56:08PM -0500, Mario Limonciello wrote:
>> On 6/21/25 2:05 PM, Lukas Wunner wrote:
>>> In the dmesg output attached to...
>>>
>>> https://bugzilla.kernel.org/show_bug.cgi?id=220216
>>>
>>> ... the device exhibiting the refcount underflow is a PCIe port.
>>> Are you also seeing this on a PCIe port or is it a different device?
>>
>> The device with the underflow is the disconnected PCIe bridge.
>>
>> In my case it was this bridge that was downstream.
> 
> Okay, in both cases the refcount underflow occurs on a PCIe port.
> So it seems likely the gratuitous refcount decrement is in portdrv.c
> or one of the port services drivers.
> 
> Your patch changes the code path for *all* PCI devices.
> Not just PCIe ports.  Hence it's likely not the right fix.
> 
> It may fix the issue on this particular PCIe port but
> I strongly suspect it'll leak a runtime PM ref on all other devices.
> 

Thanks, I see your point.

> 
>>> So the refcount decrement happens in pcie_portdrv_probe() and
>>> the refcount increment happens in pcie_portdrv_remove().
>>> Both times it's conditional on pci_bridge_d3_possible().
>>> Does that return a different value on probe versus remove?
> 
> Could you please answer this?

I did this check and yes specifically on this PCIe port with the 
underflow the d3 possible lookup returns false during 
pcie_portdrv_remove().  It returns true during pcie_portdrv_probe().

> 
> 
>>> Does any of the port service drivers decrement the refcount
>>> once too often?  I've just looked through pciehp but cannot
>>> find anything out of the ordinary.
>>>
>>> Looking through recent changes, 002bf2fbc00e and bca84a7b93fd
>>> look like potential candidates causing a regression, but the
>>> former is for AER (which isn't used in the dmesg attached to
>>> the bugzilla) and the latter touches suspend on system sleep,
>>> not runtime suspend.
>>>
>>> Can you maybe instrument the pm_runtime_{get,put}*() functions
>>> with a printk() and/or dump_stack() to see where a gratuitous
>>> refcount decrement occurs?
>>
>> That's exactly what I did to conclude this call was an extra one.
>>
>> Here's the drop to 0:
> 
> The drop to 0 is uninteresting.  You need to record *all*
> refcount increments/decrements so that we can see where the
> gratuitous one occurs.  It happens earlier than the drop to 0.
> 
> However, please first check whether the pci_bridge_d3_possible()
> return value changes on probe versus remove of the PCIe port
> in question.  If it does, then that's the root cause and there's
> no need to look any further.
> 

That was a great hypothesis that's spot on.

Just for posterity this was all the increment/decrement calls that I saw 
happen.

pci 0000:02:04.0: inc usage cnt from 0, caller: pci_pm_init+0x84/0x2d0
pci 0000:02:04.0: inc usage cnt from 1, caller: 
pci_scan_bridge_extend+0x6d/0x710
pci 0000:02:04.0: dec usage cnt from 2, caller: 
pci_scan_bridge_extend+0x19e/0x710
pci 0000:02:04.0: inc usage cnt from 1, caller: 
pci_scan_bridge_extend+0x6d/0x710
pci 0000:02:04.0: dec usage cnt from 2, caller: 
pci_scan_bridge_extend+0x19e/0x710
pcieport 0000:02:04.0: inc usage cnt from 1, caller: 
local_pci_probe+0x2d/0xa0
pcieport 0000:02:04.0: inc usage cnt from 2, caller: 
__device_attach+0x9c/0x1b0
pcieport 0000:02:04.0: inc usage cnt from 3, caller: 
__driver_probe_device+0x5c/0x150
pcieport 0000:02:04.0: dec usage cnt from 4, caller: 
__driver_probe_device+0x9a/0x150
pcieport 0000:02:04.0: dec usage cnt from 3, caller: 
__device_attach+0x145/0x1b0
pcieport 0000:02:04.0: dec usage cnt from 2, caller: 
pcie_portdrv_probe+0x19d/0x6d0
pcieport 0000:02:04.0: dec usage cnt from 1, caller: 
pcie_portdrv_probe+0x1a5/0x6d0
pcieport 0000:02:04.0: inc usage cnt from 0, caller: 
device_release_driver_internal+0xac/0x200
pcieport 0000:02:04.0: dec usage cnt from 1, caller: 
device_release_driver_internal+0x197/0x200
pcieport 0000:02:04.0: inc usage cnt from 0, caller: 
pci_device_remove+0x2d/0xb0
pcieport 0000:02:04.0: dec usage cnt from 0, caller: 
pci_device_remove+0x7e/0xb0
pcieport 0000:02:04.0: Runtime PM usage cnt underflow!

What's your suggestion on what to actually do here then?


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-22 18:39         ` Mario Limonciello
@ 2025-06-23  1:47           ` Mario Limonciello
  2025-06-23  6:53             ` Lukas Wunner
  2025-06-23  6:43           ` Lukas Wunner
  1 sibling, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2025-06-23  1:47 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello



On 6/22/25 1:39 PM, Mario Limonciello wrote:
> On 6/21/2025 11:43 PM, Lukas Wunner wrote:
>> On Sat, Jun 21, 2025 at 02:56:08PM -0500, Mario Limonciello wrote:
>>> On 6/21/25 2:05 PM, Lukas Wunner wrote:
>>>> In the dmesg output attached to...
>>>>
>>>> https://bugzilla.kernel.org/show_bug.cgi?id=220216
>>>>
>>>> ... the device exhibiting the refcount underflow is a PCIe port.
>>>> Are you also seeing this on a PCIe port or is it a different device?
>>>
>>> The device with the underflow is the disconnected PCIe bridge.
>>>
>>> In my case it was this bridge that was downstream.
>>
>> Okay, in both cases the refcount underflow occurs on a PCIe port.
>> So it seems likely the gratuitous refcount decrement is in portdrv.c
>> or one of the port services drivers.
>>
>> Your patch changes the code path for *all* PCI devices.
>> Not just PCIe ports.  Hence it's likely not the right fix.
>>
>> It may fix the issue on this particular PCIe port but
>> I strongly suspect it'll leak a runtime PM ref on all other devices.
>>
> 
> Thanks, I see your point.
> 
>>
>>>> So the refcount decrement happens in pcie_portdrv_probe() and
>>>> the refcount increment happens in pcie_portdrv_remove().
>>>> Both times it's conditional on pci_bridge_d3_possible().
>>>> Does that return a different value on probe versus remove?
>>
>> Could you please answer this?
> 
> I did this check and yes specifically on this PCIe port with the 
> underflow the d3 possible lookup returns false during 
> pcie_portdrv_remove().  It returns true during pcie_portdrv_probe().
> 
>>
>>
>>>> Does any of the port service drivers decrement the refcount
>>>> once too often?  I've just looked through pciehp but cannot
>>>> find anything out of the ordinary.
>>>>
>>>> Looking through recent changes, 002bf2fbc00e and bca84a7b93fd
>>>> look like potential candidates causing a regression, but the
>>>> former is for AER (which isn't used in the dmesg attached to
>>>> the bugzilla) and the latter touches suspend on system sleep,
>>>> not runtime suspend.
>>>>
>>>> Can you maybe instrument the pm_runtime_{get,put}*() functions
>>>> with a printk() and/or dump_stack() to see where a gratuitous
>>>> refcount decrement occurs?
>>>
>>> That's exactly what I did to conclude this call was an extra one.
>>>
>>> Here's the drop to 0:
>>
>> The drop to 0 is uninteresting.  You need to record *all*
>> refcount increments/decrements so that we can see where the
>> gratuitous one occurs.  It happens earlier than the drop to 0.
>>
>> However, please first check whether the pci_bridge_d3_possible()
>> return value changes on probe versus remove of the PCIe port
>> in question.  If it does, then that's the root cause and there's
>> no need to look any further.
>>
> 
> That was a great hypothesis that's spot on.
> 
> Just for posterity this was all the increment/decrement calls that I saw 
> happen.
> 
> pci 0000:02:04.0: inc usage cnt from 0, caller: pci_pm_init+0x84/0x2d0
> pci 0000:02:04.0: inc usage cnt from 1, caller: 
> pci_scan_bridge_extend+0x6d/0x710
> pci 0000:02:04.0: dec usage cnt from 2, caller: 
> pci_scan_bridge_extend+0x19e/0x710
> pci 0000:02:04.0: inc usage cnt from 1, caller: 
> pci_scan_bridge_extend+0x6d/0x710
> pci 0000:02:04.0: dec usage cnt from 2, caller: 
> pci_scan_bridge_extend+0x19e/0x710
> pcieport 0000:02:04.0: inc usage cnt from 1, caller: 
> local_pci_probe+0x2d/0xa0
> pcieport 0000:02:04.0: inc usage cnt from 2, caller: 
> __device_attach+0x9c/0x1b0
> pcieport 0000:02:04.0: inc usage cnt from 3, caller: 
> __driver_probe_device+0x5c/0x150
> pcieport 0000:02:04.0: dec usage cnt from 4, caller: 
> __driver_probe_device+0x9a/0x150
> pcieport 0000:02:04.0: dec usage cnt from 3, caller: 
> __device_attach+0x145/0x1b0
> pcieport 0000:02:04.0: dec usage cnt from 2, caller: 
> pcie_portdrv_probe+0x19d/0x6d0
> pcieport 0000:02:04.0: dec usage cnt from 1, caller: 
> pcie_portdrv_probe+0x1a5/0x6d0
> pcieport 0000:02:04.0: inc usage cnt from 0, caller: 
> device_release_driver_internal+0xac/0x200
> pcieport 0000:02:04.0: dec usage cnt from 1, caller: 
> device_release_driver_internal+0x197/0x200
> pcieport 0000:02:04.0: inc usage cnt from 0, caller: 
> pci_device_remove+0x2d/0xb0
> pcieport 0000:02:04.0: dec usage cnt from 0, caller: 
> pci_device_remove+0x7e/0xb0
> pcieport 0000:02:04.0: Runtime PM usage cnt underflow!
> 
> What's your suggestion on what to actually do here then?
> 
> 

Actually I came up with the idea to forbid runtime PM on the service 
when it doesn't allow d3 at probe which I believe means no need to check 
again on remove.

This works cleanly for me.  LMK what you think of this.

diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
index e8318fd5f6ed5..a85cd7412cf4d 100644
--- a/drivers/pci/pcie/portdrv.c
+++ b/drivers/pci/pcie/portdrv.c
@@ -717,6 +717,8 @@ static int pcie_portdrv_probe(struct pci_dev *dev,
                 pm_runtime_mark_last_busy(&dev->dev);
                 pm_runtime_put_autosuspend(&dev->dev);
                 pm_runtime_allow(&dev->dev);
+       } else {
+               pm_runtime_forbid(&dev->dev);
         }

         return 0;
@@ -724,11 +726,9 @@ static int pcie_portdrv_probe(struct pci_dev *dev,

  static void pcie_portdrv_remove(struct pci_dev *dev)
  {
-       if (pci_bridge_d3_possible(dev)) {
-               pm_runtime_forbid(&dev->dev);
-               pm_runtime_get_noresume(&dev->dev);
-               pm_runtime_dont_use_autosuspend(&dev->dev);
-       }
+       pm_runtime_forbid(&dev->dev);
+       pm_runtime_get_noresume(&dev->dev);
+       pm_runtime_dont_use_autosuspend(&dev->dev);

         pcie_port_device_remove(dev);

@@ -737,11 +737,9 @@ static void pcie_portdrv_remove(struct pci_dev *dev)

  static void pcie_portdrv_shutdown(struct pci_dev *dev)
  {
-       if (pci_bridge_d3_possible(dev)) {
-               pm_runtime_forbid(&dev->dev);
-               pm_runtime_get_noresume(&dev->dev);
-               pm_runtime_dont_use_autosuspend(&dev->dev);
-       }
+       pm_runtime_forbid(&dev->dev);
+       pm_runtime_get_noresume(&dev->dev);
+       pm_runtime_dont_use_autosuspend(&dev->dev);

         pcie_port_device_remove(dev);
  }

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-22 18:39         ` Mario Limonciello
  2025-06-23  1:47           ` Mario Limonciello
@ 2025-06-23  6:43           ` Lukas Wunner
  2025-06-23  7:37             ` Lukas Wunner
  1 sibling, 1 reply; 19+ messages in thread
From: Lukas Wunner @ 2025-06-23  6:43 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On Sun, Jun 22, 2025 at 01:39:26PM -0500, Mario Limonciello wrote:
> > > On 6/21/25 2:05 PM, Lukas Wunner wrote:
> > > > So the refcount decrement happens in pcie_portdrv_probe() and
> > > > the refcount increment happens in pcie_portdrv_remove().
> > > > Both times it's conditional on pci_bridge_d3_possible().
> > > > Does that return a different value on probe versus remove?
> 
> I did this check and yes specifically on this PCIe port with the underflow
> the d3 possible lookup returns false during pcie_portdrv_remove().  It
> returns true during pcie_portdrv_probe().

That's not supposed to happen.  The expectation is that
pci_bridge_d3_possible() always returns the same value.

For this reason the return value on ->probe() isn't cached.

So which of the conditions changes in pci_bridge_d3_possible()
on probe versus remove?  Could you instrument each with a printk()
so that we can understand what's going wrong there?

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23  1:47           ` Mario Limonciello
@ 2025-06-23  6:53             ` Lukas Wunner
  0 siblings, 0 replies; 19+ messages in thread
From: Lukas Wunner @ 2025-06-23  6:53 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On Sun, Jun 22, 2025 at 08:47:03PM -0500, Mario Limonciello wrote:
> Actually I came up with the idea to forbid runtime PM on the service when it
> doesn't allow d3 at probe which I believe means no need to check again on
> remove.
> 
> This works cleanly for me.  LMK what you think of this.

User space can override the allow/forbid setting through the
sysfs "control" attribute, hence this doesn't seem like a
suitable way to somehow cache the return value of
pci_bridge_d3_possible() and thus avoid its re-execution
on remove.

However we shouldn't have to cache the return value anyway
as the underlying assumption is that the function always
returns the same value.

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23  6:43           ` Lukas Wunner
@ 2025-06-23  7:37             ` Lukas Wunner
  2025-06-23 10:05               ` Lukas Wunner
  0 siblings, 1 reply; 19+ messages in thread
From: Lukas Wunner @ 2025-06-23  7:37 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On Mon, Jun 23, 2025 at 08:43:25AM +0200, Lukas Wunner wrote:
> On Sun, Jun 22, 2025 at 01:39:26PM -0500, Mario Limonciello wrote:
> > > > On 6/21/25 2:05 PM, Lukas Wunner wrote:
> > > > > So the refcount decrement happens in pcie_portdrv_probe() and
> > > > > the refcount increment happens in pcie_portdrv_remove().
> > > > > Both times it's conditional on pci_bridge_d3_possible().
> > > > > Does that return a different value on probe versus remove?
> > 
> > I did this check and yes specifically on this PCIe port with the underflow
> > the d3 possible lookup returns false during pcie_portdrv_remove().  It
> > returns true during pcie_portdrv_probe().
> 
> That's not supposed to happen.  The expectation is that
> pci_bridge_d3_possible() always returns the same value.

I'm wondering if the patch below fixes the issue?

Normally the "is_thunderbolt" check in pci_bridge_d3_possible()
should return true for this particular device.

But there's a check for pciehp_is_native() before that and
it accesses config space to check if the Hot-Plug Capable bit
is set.  The device is inaccessible, so the expectation is that
"all ones" is returned, which implies a set HPC bit.

But maybe for some reason "all ones" isn't returned anymore?
If the patch below does help, could you check what the read
of the Slot Capabilities register returns?

Thanks!

-- >8 --

From: Lukas Wunner <lukas@wunner.de>
Subject: [PATCH] PCI/ACPI: Use cached is_hotplug_bridge value in
 pciehp_is_native()

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/pci/pci-acpi.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index b78e0e4..909ca4a 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -821,8 +821,7 @@ bool pciehp_is_native(struct pci_dev *bridge)
 	if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
 		return false;
 
-	pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
-	if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
+	if (!bridge->is_hotplug_bridge)
 		return false;
 
 	if (pcie_ports_native)
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23  7:37             ` Lukas Wunner
@ 2025-06-23 10:05               ` Lukas Wunner
  2025-06-23 10:11                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 19+ messages in thread
From: Lukas Wunner @ 2025-06-23 10:05 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On Mon, Jun 23, 2025 at 09:37:07AM +0200, Lukas Wunner wrote:
> On Mon, Jun 23, 2025 at 08:43:25AM +0200, Lukas Wunner wrote:
> > On Sun, Jun 22, 2025 at 01:39:26PM -0500, Mario Limonciello wrote:
> > > > > On 6/21/25 2:05 PM, Lukas Wunner wrote:
> > > > > > So the refcount decrement happens in pcie_portdrv_probe() and
> > > > > > the refcount increment happens in pcie_portdrv_remove().
> > > > > > Both times it's conditional on pci_bridge_d3_possible().
> > > > > > Does that return a different value on probe versus remove?
> > > 
> > > I did this check and yes specifically on this PCIe port with the underflow
> > > the d3 possible lookup returns false during pcie_portdrv_remove().  It
> > > returns true during pcie_portdrv_probe().
> > 
> > That's not supposed to happen.  The expectation is that
> > pci_bridge_d3_possible() always returns the same value.
> 
> I'm wondering if the patch below fixes the issue?

Refined patch below with proper commit message,
also avoids a compiler warning caused by an unused variable.

-- >8 --

From: Lukas Wunner <lukas@wunner.de>
Subject: [PATCH] PCI/ACPI: Fix runtime PM ref imbalance on hot-plug capable
 ports

pcie_portdrv_probe() and pcie_portdrv_remove() both call
pci_bridge_d3_possible() to determine whether to use runtime power
management.  The underlying assumption is that pci_bridge_d3_possible()
always returns the same value because otherwise a runtime PM reference
imbalance occurs.

That assumption falls apart if the device is inaccessible on ->remove()
due to hot-unplug:  pci_bridge_d3_possible() calls pciehp_is_native(),
which accesses Config Space to determine whether the device is Hot-Plug
Capable.   An inaccessible device generally returns "all ones" for such
Config Read Requests.  Hence the device may seem Hot-Plug Capable on
->remove() even though it wasn't on ->probe().

Use the cached copy of the Hot-Plug Capable bit to avoid the Config Space
access and the resulting runtime PM ref imbalance.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/pci/pci-acpi.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index b78e0e4..8859cce 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -816,13 +816,11 @@ int pci_acpi_program_hp_params(struct pci_dev *dev)
 bool pciehp_is_native(struct pci_dev *bridge)
 {
 	const struct pci_host_bridge *host;
-	u32 slot_cap;
 
 	if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
 		return false;
 
-	pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
-	if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
+	if (!bridge->is_hotplug_bridge)
 		return false;
 
 	if (pcie_ports_native)
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23 10:05               ` Lukas Wunner
@ 2025-06-23 10:11                 ` Rafael J. Wysocki
  2025-06-23 11:37                   ` Mario Limonciello
  0 siblings, 1 reply; 19+ messages in thread
From: Rafael J. Wysocki @ 2025-06-23 10:11 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: Mario Limonciello, Bjorn Helgaas, open list:PCI SUBSYSTEM,
	linux-pm, Rafael J . Wysocki, Mario Limonciello

On Mon, Jun 23, 2025 at 12:05 PM Lukas Wunner <lukas@wunner.de> wrote:
>
> On Mon, Jun 23, 2025 at 09:37:07AM +0200, Lukas Wunner wrote:
> > On Mon, Jun 23, 2025 at 08:43:25AM +0200, Lukas Wunner wrote:
> > > On Sun, Jun 22, 2025 at 01:39:26PM -0500, Mario Limonciello wrote:
> > > > > > On 6/21/25 2:05 PM, Lukas Wunner wrote:
> > > > > > > So the refcount decrement happens in pcie_portdrv_probe() and
> > > > > > > the refcount increment happens in pcie_portdrv_remove().
> > > > > > > Both times it's conditional on pci_bridge_d3_possible().
> > > > > > > Does that return a different value on probe versus remove?
> > > >
> > > > I did this check and yes specifically on this PCIe port with the underflow
> > > > the d3 possible lookup returns false during pcie_portdrv_remove().  It
> > > > returns true during pcie_portdrv_probe().
> > >
> > > That's not supposed to happen.  The expectation is that
> > > pci_bridge_d3_possible() always returns the same value.
> >
> > I'm wondering if the patch below fixes the issue?
>
> Refined patch below with proper commit message,
> also avoids a compiler warning caused by an unused variable.
>
> -- >8 --
>
> From: Lukas Wunner <lukas@wunner.de>
> Subject: [PATCH] PCI/ACPI: Fix runtime PM ref imbalance on hot-plug capable
>  ports
>
> pcie_portdrv_probe() and pcie_portdrv_remove() both call
> pci_bridge_d3_possible() to determine whether to use runtime power
> management.  The underlying assumption is that pci_bridge_d3_possible()
> always returns the same value because otherwise a runtime PM reference
> imbalance occurs.
>
> That assumption falls apart if the device is inaccessible on ->remove()
> due to hot-unplug:  pci_bridge_d3_possible() calls pciehp_is_native(),
> which accesses Config Space to determine whether the device is Hot-Plug
> Capable.   An inaccessible device generally returns "all ones" for such
> Config Read Requests.  Hence the device may seem Hot-Plug Capable on
> ->remove() even though it wasn't on ->probe().
>
> Use the cached copy of the Hot-Plug Capable bit to avoid the Config Space
> access and the resulting runtime PM ref imbalance.
>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>

LGTM

Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>

> ---
>  drivers/pci/pci-acpi.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
> index b78e0e4..8859cce 100644
> --- a/drivers/pci/pci-acpi.c
> +++ b/drivers/pci/pci-acpi.c
> @@ -816,13 +816,11 @@ int pci_acpi_program_hp_params(struct pci_dev *dev)
>  bool pciehp_is_native(struct pci_dev *bridge)
>  {
>         const struct pci_host_bridge *host;
> -       u32 slot_cap;
>
>         if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
>                 return false;
>
> -       pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
> -       if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
> +       if (!bridge->is_hotplug_bridge)
>                 return false;
>
>         if (pcie_ports_native)
> --
> 2.47.2
>
>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23 10:11                 ` Rafael J. Wysocki
@ 2025-06-23 11:37                   ` Mario Limonciello
  2025-06-23 12:19                     ` Lukas Wunner
  2025-06-23 17:23                     ` Lukas Wunner
  0 siblings, 2 replies; 19+ messages in thread
From: Mario Limonciello @ 2025-06-23 11:37 UTC (permalink / raw)
  To: Rafael J. Wysocki, Lukas Wunner
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello



On 6/23/25 5:11 AM, Rafael J. Wysocki wrote:
> On Mon, Jun 23, 2025 at 12:05 PM Lukas Wunner <lukas@wunner.de> wrote:
>>
>> On Mon, Jun 23, 2025 at 09:37:07AM +0200, Lukas Wunner wrote:
>>> On Mon, Jun 23, 2025 at 08:43:25AM +0200, Lukas Wunner wrote:
>>>> On Sun, Jun 22, 2025 at 01:39:26PM -0500, Mario Limonciello wrote:
>>>>>>> On 6/21/25 2:05 PM, Lukas Wunner wrote:
>>>>>>>> So the refcount decrement happens in pcie_portdrv_probe() and
>>>>>>>> the refcount increment happens in pcie_portdrv_remove().
>>>>>>>> Both times it's conditional on pci_bridge_d3_possible().
>>>>>>>> Does that return a different value on probe versus remove?
>>>>>
>>>>> I did this check and yes specifically on this PCIe port with the underflow
>>>>> the d3 possible lookup returns false during pcie_portdrv_remove().  It
>>>>> returns true during pcie_portdrv_probe().
>>>>
>>>> That's not supposed to happen.  The expectation is that
>>>> pci_bridge_d3_possible() always returns the same value.
>>>
>>> I'm wondering if the patch below fixes the issue?
>>
>> Refined patch below with proper commit message,
>> also avoids a compiler warning caused by an unused variable.

Yes this works, thanks!

>>
>> -- >8 --
>>
>> From: Lukas Wunner <lukas@wunner.de>
>> Subject: [PATCH] PCI/ACPI: Fix runtime PM ref imbalance on hot-plug capable
>>   ports
>>
>> pcie_portdrv_probe() and pcie_portdrv_remove() both call
>> pci_bridge_d3_possible() to determine whether to use runtime power
>> management.  The underlying assumption is that pci_bridge_d3_possible()
>> always returns the same value because otherwise a runtime PM reference
>> imbalance occurs.
>>
>> That assumption falls apart if the device is inaccessible on ->remove()
>> due to hot-unplug:  pci_bridge_d3_possible() calls pciehp_is_native(),
>> which accesses Config Space to determine whether the device is Hot-Plug
>> Capable.   An inaccessible device generally returns "all ones" for such
>> Config Read Requests.  Hence the device may seem Hot-Plug Capable on
>> ->remove() even though it wasn't on ->probe().
>>
>> Use the cached copy of the Hot-Plug Capable bit to avoid the Config Space
>> access and the resulting runtime PM ref imbalance.
>>
>> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> 
> LGTM
> 
> Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>

Tested-by: Mario Limonciello <mario.limonciello@amd.com>>
>> ---
>>   drivers/pci/pci-acpi.c | 4 +---
>>   1 file changed, 1 insertion(+), 3 deletions(-)
>>
>> diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
>> index b78e0e4..8859cce 100644
>> --- a/drivers/pci/pci-acpi.c
>> +++ b/drivers/pci/pci-acpi.c
>> @@ -816,13 +816,11 @@ int pci_acpi_program_hp_params(struct pci_dev *dev)
>>   bool pciehp_is_native(struct pci_dev *bridge)
>>   {
>>          const struct pci_host_bridge *host;
>> -       u32 slot_cap;
>>
>>          if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
>>                  return false;
>>
>> -       pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
>> -       if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
>> +       if (!bridge->is_hotplug_bridge)
>>                  return false;
>>
>>          if (pcie_ports_native)
>> --
>> 2.47.2
>>
>>
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23 11:37                   ` Mario Limonciello
@ 2025-06-23 12:19                     ` Lukas Wunner
  2025-06-23 12:45                       ` Mario Limonciello
  2025-06-23 17:23                     ` Lukas Wunner
  1 sibling, 1 reply; 19+ messages in thread
From: Lukas Wunner @ 2025-06-23 12:19 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Rafael J. Wysocki, Bjorn Helgaas, open list:PCI SUBSYSTEM,
	linux-pm, Rafael J . Wysocki, Mario Limonciello

On Mon, Jun 23, 2025 at 06:37:33AM -0500, Mario Limonciello wrote:
> On 6/23/25 5:11 AM, Rafael J. Wysocki wrote:
> > On Mon, Jun 23, 2025 at 12:05???PM Lukas Wunner <lukas@wunner.de> wrote:
> > > On Mon, Jun 23, 2025 at 09:37:07AM +0200, Lukas Wunner wrote:
> > > > On Mon, Jun 23, 2025 at 08:43:25AM +0200, Lukas Wunner wrote:
> > > > > On Sun, Jun 22, 2025 at 01:39:26PM -0500, Mario Limonciello wrote:
> > > > > > I did this check and yes specifically on this PCIe port with
> > > > > > the underflow the d3 possible lookup returns false during
> > > > > > pcie_portdrv_remove().  It returns true during
> > > > > > pcie_portdrv_probe().
> > > > > 
> > > > > That's not supposed to happen.  The expectation is that
> > > > > pci_bridge_d3_possible() always returns the same value.
> > > > 
> > > > I'm wondering if the patch below fixes the issue?
> 
> Yes this works, thanks!

Could you still check what the value read from the Slot Capabilities
register is in pciehp_is_native() (if the patch is not applied)?

I guess it must be something else than "all ones" and I'd like to
understand why.

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23 12:19                     ` Lukas Wunner
@ 2025-06-23 12:45                       ` Mario Limonciello
  0 siblings, 0 replies; 19+ messages in thread
From: Mario Limonciello @ 2025-06-23 12:45 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: Rafael J. Wysocki, Bjorn Helgaas, open list:PCI SUBSYSTEM,
	linux-pm, Rafael J . Wysocki, Mario Limonciello



On 6/23/25 7:19 AM, Lukas Wunner wrote:
> On Mon, Jun 23, 2025 at 06:37:33AM -0500, Mario Limonciello wrote:
>> On 6/23/25 5:11 AM, Rafael J. Wysocki wrote:
>>> On Mon, Jun 23, 2025 at 12:05???PM Lukas Wunner <lukas@wunner.de> wrote:
>>>> On Mon, Jun 23, 2025 at 09:37:07AM +0200, Lukas Wunner wrote:
>>>>> On Mon, Jun 23, 2025 at 08:43:25AM +0200, Lukas Wunner wrote:
>>>>>> On Sun, Jun 22, 2025 at 01:39:26PM -0500, Mario Limonciello wrote:
>>>>>>> I did this check and yes specifically on this PCIe port with
>>>>>>> the underflow the d3 possible lookup returns false during
>>>>>>> pcie_portdrv_remove().  It returns true during
>>>>>>> pcie_portdrv_probe().
>>>>>>
>>>>>> That's not supposed to happen.  The expectation is that
>>>>>> pci_bridge_d3_possible() always returns the same value.
>>>>>
>>>>> I'm wondering if the patch below fixes the issue?
>>
>> Yes this works, thanks!
> 
> Could you still check what the value read from the Slot Capabilities
> register is in pciehp_is_native() (if the patch is not applied)?
> 
> I guess it must be something else than "all ones" and I'd like to
> understand why.
> 
> Thanks,
> 
> Lukas

At probe:
0x00240060

At remove:
0x00000000

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23 11:37                   ` Mario Limonciello
  2025-06-23 12:19                     ` Lukas Wunner
@ 2025-06-23 17:23                     ` Lukas Wunner
  2025-06-23 17:25                       ` Mario Limonciello
  1 sibling, 1 reply; 19+ messages in thread
From: Lukas Wunner @ 2025-06-23 17:23 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Rafael J. Wysocki, Bjorn Helgaas, open list:PCI SUBSYSTEM,
	linux-pm, Rafael J . Wysocki, Mario Limonciello, Mika Westerberg

[cc += Mika]

On Mon, Jun 23, 2025 at 06:37:33AM -0500, Mario Limonciello wrote:
> On 6/23/25 5:11 AM, Rafael J. Wysocki wrote:
> > On Mon, Jun 23, 2025 at 12:05 PM Lukas Wunner <lukas@wunner.de> wrote:
> > > pcie_portdrv_probe() and pcie_portdrv_remove() both call
> > > pci_bridge_d3_possible() to determine whether to use runtime power
> > > management.  The underlying assumption is that pci_bridge_d3_possible()
> > > always returns the same value because otherwise a runtime PM reference
> > > imbalance occurs.
> > > 
> > > That assumption falls apart if the device is inaccessible on ->remove()
> > > due to hot-unplug:  pci_bridge_d3_possible() calls pciehp_is_native(),
> > > which accesses Config Space to determine whether the device is Hot-Plug
> > > Capable.   An inaccessible device generally returns "all ones" for such
> > > Config Read Requests.  Hence the device may seem Hot-Plug Capable on
> > > ->remove() even though it wasn't on ->probe().
> > > 
> > > Use the cached copy of the Hot-Plug Capable bit to avoid the Config Space
> > > access and the resulting runtime PM ref imbalance.
> > > 
> > > Signed-off-by: Lukas Wunner <lukas@wunner.de>
> > 
> > Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>
> 
> Tested-by: Mario Limonciello <mario.limonciello@amd.com>>

I ended up changing the patch significantly, so I did not include
Rafael's Reviewed-by and Mario's Tested-by in the final patch.
My apologies for this!

Looking at the commit which introduced the Config Space read,
5352a44a561d, I got the impression that Mika may have deliberately
avoided using the is_hotplug_bridge flag.  Notably, is_hotplug_bridge
is also set by check_hotplug_bridge() in acpiphp_glue.c, and his
intention was probably to avoid matching those bridges in
pciehp_is_native().

So I decided to err on the side of caution and keep the Config Space
read if pciehp_is_native() is called from hotplug_is_native().
Just to avoid any potential regressions since the fix is tagged for
stable.

I also searched lore for occurrences of the keywords...

  pcieport Runtime PM usage count underflow

...and did find quite a few reports, but this error message was just
a side effect and the reports were about completely different issues.
It does prove though that this bug has existed for a while!

Thanks Laurent for the report and Mario for root-causing this!

Lukas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug
  2025-06-23 17:23                     ` Lukas Wunner
@ 2025-06-23 17:25                       ` Mario Limonciello
  0 siblings, 0 replies; 19+ messages in thread
From: Mario Limonciello @ 2025-06-23 17:25 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: Rafael J. Wysocki, Bjorn Helgaas, open list:PCI SUBSYSTEM,
	linux-pm, Rafael J . Wysocki, Mario Limonciello, Mika Westerberg

On 6/23/25 12:23 PM, Lukas Wunner wrote:
> [cc += Mika]
> 
> On Mon, Jun 23, 2025 at 06:37:33AM -0500, Mario Limonciello wrote:
>> On 6/23/25 5:11 AM, Rafael J. Wysocki wrote:
>>> On Mon, Jun 23, 2025 at 12:05 PM Lukas Wunner <lukas@wunner.de> wrote:
>>>> pcie_portdrv_probe() and pcie_portdrv_remove() both call
>>>> pci_bridge_d3_possible() to determine whether to use runtime power
>>>> management.  The underlying assumption is that pci_bridge_d3_possible()
>>>> always returns the same value because otherwise a runtime PM reference
>>>> imbalance occurs.
>>>>
>>>> That assumption falls apart if the device is inaccessible on ->remove()
>>>> due to hot-unplug:  pci_bridge_d3_possible() calls pciehp_is_native(),
>>>> which accesses Config Space to determine whether the device is Hot-Plug
>>>> Capable.   An inaccessible device generally returns "all ones" for such
>>>> Config Read Requests.  Hence the device may seem Hot-Plug Capable on
>>>> ->remove() even though it wasn't on ->probe().
>>>>
>>>> Use the cached copy of the Hot-Plug Capable bit to avoid the Config Space
>>>> access and the resulting runtime PM ref imbalance.
>>>>
>>>> Signed-off-by: Lukas Wunner <lukas@wunner.de>
>>>
>>> Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>
>>
>> Tested-by: Mario Limonciello <mario.limonciello@amd.com>>
> 
> I ended up changing the patch significantly, so I did not include
> Rafael's Reviewed-by and Mario's Tested-by in the final patch.
> My apologies for this!
> 
> Looking at the commit which introduced the Config Space read,
> 5352a44a561d, I got the impression that Mika may have deliberately
> avoided using the is_hotplug_bridge flag.  Notably, is_hotplug_bridge
> is also set by check_hotplug_bridge() in acpiphp_glue.c, and his
> intention was probably to avoid matching those bridges in
> pciehp_is_native().
> 
> So I decided to err on the side of caution and keep the Config Space
> read if pciehp_is_native() is called from hotplug_is_native().
> Just to avoid any potential regressions since the fix is tagged for
> stable.
> 
> I also searched lore for occurrences of the keywords...
> 
>    pcieport Runtime PM usage count underflow
> 
> ...and did find quite a few reports, but this error message was just
> a side effect and the reports were about completely different issues.
> It does prove though that this bug has existed for a while!
> 
> Thanks Laurent for the report and Mario for root-causing this!
> 
> Lukas

Thanks Lukas!

I still do think my patch 1/2 in this series makes sense though, can you 
review that separately?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 1/2] PCI/PM: Skip resuming to D0 if disconnected
  2025-06-20  2:55 ` [PATCH v3 1/2] PCI/PM: Skip resuming to D0 if disconnected Mario Limonciello
@ 2025-06-23 17:48   ` Lukas Wunner
  0 siblings, 0 replies; 19+ messages in thread
From: Lukas Wunner @ 2025-06-23 17:48 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Bjorn Helgaas, open list:PCI SUBSYSTEM, linux-pm,
	Rafael J . Wysocki, Mario Limonciello

On Thu, Jun 19, 2025 at 09:55:34PM -0500, Mario Limonciello wrote:
> When a USB4 dock is unplugged the PCIe bridge it's connected to will
> remove issue a "Link Down" and "Card not detected event". The PCI core

Small nit here, the word "remove" seems superfluous.


> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1374,6 +1374,11 @@ int pci_power_up(struct pci_dev *dev)
>  		return -EIO;
>  	}
>  
> +	if (pci_dev_is_disconnected(dev)) {
> +		dev->current_state = PCI_D3cold;
> +		return -EIO;
> +	}
> +
>  	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
>  	if (PCI_POSSIBLE_ERROR(pmcsr)) {
>  		pci_err(dev, "Unable to change power state from %s to D0, device inaccessible\n",

This hunk looks good to me.


> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -550,6 +550,7 @@ static inline bool pci_dev_set_io_state(struct pci_dev *dev,
>  
>  static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
>  {
> +	pci_info(dev, "Device disconnected\n");
>  	pci_dev_set_io_state(dev, pci_channel_io_perm_failure);
>  	pci_doe_disconnected(dev);

However this one (which I think was newly added in v3) seems problematic:

pci_dev_set_disconnected() needs to be fast so that devices are marked
unplugged as quickly as possible.  We want to minimize the time window
where MMIO and Config Space reads already return "all ones" and writes
go to nirvana, but pci_dev_is_disconnected() still returns false.
However printk() isn't a cheap operation, so it may unduly delay
marking the removed devices disconnected.

Second, the object of the patch is to make hot-removal less noisy,
but this change *increases* noise.  It will emit an extra message
for every removed device.

Third, the change is somewhat orthogonal to the first hunk in the patch,
so I would have put this in a separate patch.

Bottom line is, at the very least I'd recommend making this a pci_dbg(),
but I'm not even sure the extra message adds sufficient value to justify
the change.

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2025-06-23 17:48 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-20  2:55 [PATCH v3 0/2] Don't make noise about disconnected USB4 devices Mario Limonciello
2025-06-20  2:55 ` [PATCH v3 1/2] PCI/PM: Skip resuming to D0 if disconnected Mario Limonciello
2025-06-23 17:48   ` Lukas Wunner
2025-06-20  2:55 ` [PATCH v3 2/2] PCI: Fix runtime PM usage count underflow on device unplug Mario Limonciello
2025-06-21 19:05   ` Lukas Wunner
2025-06-21 19:56     ` Mario Limonciello
2025-06-22  4:43       ` Lukas Wunner
2025-06-22 18:39         ` Mario Limonciello
2025-06-23  1:47           ` Mario Limonciello
2025-06-23  6:53             ` Lukas Wunner
2025-06-23  6:43           ` Lukas Wunner
2025-06-23  7:37             ` Lukas Wunner
2025-06-23 10:05               ` Lukas Wunner
2025-06-23 10:11                 ` Rafael J. Wysocki
2025-06-23 11:37                   ` Mario Limonciello
2025-06-23 12:19                     ` Lukas Wunner
2025-06-23 12:45                       ` Mario Limonciello
2025-06-23 17:23                     ` Lukas Wunner
2025-06-23 17:25                       ` Mario Limonciello

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).