Verify devices transition from D3cold to D0
Subsystems (5)
v5 cover Verify devices transition from D3cold to D0
From: Mario Limonciello <[email protected]>
Gary has reported that when a dock is plugged into a system at the same time the autosuspend delay has tripped that the USB4 stack malfunctions.
Messages show up like this:
``` thunderbolt 0000:e5:00.6: ring_interrupt_active: interrupt for TX ring 0 is already enabled ```
Furthermore the USB4 router is non-functional at this point.
Those messages happen because the device is still in D3cold at the time that the PCI core handed control back to the USB4 connection manager (thunderbolt).
The issue is that it takes time for a device to enter D3cold and do a conventional reset, and then more time for it to exit D3cold.
This appears not to be a new problem; previously there were very similar reports from Ryzen XHCI controllers. Quirks were added for those. Furthermore; adding extra logging it's apparent that other PCI devices in the system can take more than 10ms to recover from D3cold as well.
This series add a wait into pci_power_up() specifically for D3cold exit and then drops the quirks that were previously used for the Ryzen XHCI controllers.
Mario Limonciello (5):
PCI: Use an enum for reset type in pci_dev_wait()
PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
PCI: Verify functions currently in D3cold have entered D0
PCI: Allow Ryzen XHCI controllers into D3cold and drop delays
PCI: Drop Radeon quirk for Macbook Pro 8.2
drivers/pci/pci-driver.c | 2 +- drivers/pci/pci.c | 70 +++++++++++++++++++++++++++---------- drivers/pci/pci.h | 13 ++++++- drivers/pci/pcie/dpc.c | 2 +- drivers/pci/quirks.c | 25 ------------- drivers/usb/host/xhci-pci.c | 11 ------ 6 files changed, 66 insertions(+), 57 deletions(-)
Signature · 1 line
2.43.0
PATCH v5 1/5 PCI: Use an enum for reset type in pci_dev_wait()
From: Mario Limonciello <[email protected]>
A string is passed to all callers of pci_dev_wait() which is utilized to demonstrate what kind of reset happened when there was a problem.
This doesn't allow making the behavior for different reset types conditional though. Lay some plumbing to allow making comparisons of reset types with integers instead. No functional changes.
---v4->v5:
* Add static assert and PCI_DEV_WAIT_MAXv3->v4:
* Use index-based array initialization format for pci_reset_types
* Fix LKP reported sparse issue
--- drivers/pci/pci-driver.c | 2 +- drivers/pci/pci.c | 30 ++++++++++++++++++++---------- drivers/pci/pci.h | 12 +++++++++++- drivers/pci/pcie/dpc.c | 2 +- 4 files changed, 33 insertions(+), 13 deletions(-)
drivers/pci/pci-driver.c +1 -1
@@ -572,7 +572,7 @@ static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev) {int ret; - ret =pci_bridge_wait_for_secondary_bus (pci_dev,"resume" ); + ret =pci_bridge_wait_for_secondary_bus (pci_dev,PCI_DEV_WAIT_RESUME );if (ret) {/* * The downstream link failed to come up, so mark the
drivers/pci/pci.c +20 -10
@@ -181,6 +181,16 @@ static int __init pcie_port_pm_setup(char *str) }__setup ("pcie_port_pm=" , pcie_port_pm_setup); +static const char *const pci_reset_types[] = { + [PCI_DEV_WAIT_FLR ] ="FLR" , + [PCI_DEV_WAIT_AF_FLR ] ="AF_FLR" , + [PCI_DEV_WAIT_D3HOT_D0 ] ="PM D3HOT->D0" , + [PCI_DEV_WAIT_BUS_RESET ] ="bus reset" , + [PCI_DEV_WAIT_RESUME ] ="resume" , + [PCI_DEV_WAIT_DPC ] ="DPC" , +}; +static_assert (ARRAY_SIZE (pci_reset_types) ==PCI_DEV_WAIT_MAX ); +/** * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * @bus: pointer to PCI bus structure to search
@@ -1279,7 +1289,7 @@ void pci_resume_bus(struct pci_bus *bus)pci_walk_bus (bus, pci_resume_one,NULL ); } -static int pci_dev_wait (struct pci_dev *dev,char *reset_type,int timeout) +static int pci_dev_wait (struct pci_dev *dev,enum pci_reset_type reset_type,int timeout) {int delay =1 ;bool retrain = false;
@@ -1317,7 +1327,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)if (delay > timeout) {pci_warn (dev,"not ready %dms after %s; giving up\n" , - delay -1 , reset_type); + delay -1 , pci_reset_types[reset_type]);return -ENOTTY ; }
@@ -1330,7 +1340,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) } }pci_info (dev,"not ready %dms after %s; waiting\n" , - delay -1 , reset_type); + delay -1 , pci_reset_types[reset_type]); }msleep (delay);
@@ -1339,10 +1349,10 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)if (delay >PCI_RESET_WAIT )pci_info (dev,"ready %dms after %s\n" , delay -1 , - reset_type); + pci_reset_types[reset_type]);else pci_dbg (dev,"ready %dms after %s\n" , delay -1 , - reset_type); + pci_reset_types[reset_type]);return 0 ; }
@@ -4536,7 +4546,7 @@ int pcie_flr(struct pci_dev *dev)*/ msleep (100 ); -return pci_dev_wait (dev,"FLR" ,PCIE_RESET_READY_POLL_MS ); +return pci_dev_wait (dev,PCI_DEV_WAIT_FLR ,PCIE_RESET_READY_POLL_MS ); }EXPORT_SYMBOL_GPL (pcie_flr);
@@ -4603,7 +4613,7 @@ static int pci_af_flr(struct pci_dev *dev, bool probe)*/ msleep (100 ); -return pci_dev_wait (dev,"AF_FLR" ,PCIE_RESET_READY_POLL_MS ); +return pci_dev_wait (dev,PCI_DEV_WAIT_AF_FLR ,PCIE_RESET_READY_POLL_MS ); }/**
@@ -4648,7 +4658,7 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)pci_write_config_word (dev, dev->pm_cap +PCI_PM_CTRL , csr);pci_dev_d3_sleep (dev); -return pci_dev_wait (dev,"PM D3hot->D0" ,PCIE_RESET_READY_POLL_MS ); +return pci_dev_wait (dev,PCI_DEV_WAIT_D3HOT_D0 ,PCIE_RESET_READY_POLL_MS ); }/**
@@ -4822,7 +4832,7 @@ static int pci_bus_max_d3cold_delay(const struct pci_bus *bus)* Return 0 on success or -ENOTTY if the first device on the secondary bus * failed to become accessible. */ -int pci_bridge_wait_for_secondary_bus (struct pci_dev *dev,char *reset_type) +int pci_bridge_wait_for_secondary_bus (struct pci_dev *dev,enum pci_reset_type reset_type) { struct pci_dev *child __free(pci_dev_put) = NULL;int delay;
@@ -4959,7 +4969,7 @@ int pci_bridge_secondary_bus_reset(struct pci_dev *dev) __builtin_return_address(0));pcibios_reset_secondary_bus (dev); -return pci_bridge_wait_for_secondary_bus (dev,"bus reset" ); +return pci_bridge_wait_for_secondary_bus (dev,PCI_DEV_WAIT_BUS_RESET ); }EXPORT_SYMBOL_GPL (pci_bridge_secondary_bus_reset);
drivers/pci/pci.h +11 -1
@@ -4,6 +4,16 @@#include <linux/pci.h> +enum pci_reset_type { +PCI_DEV_WAIT_FLR , +PCI_DEV_WAIT_AF_FLR , +PCI_DEV_WAIT_D3HOT_D0 , +PCI_DEV_WAIT_BUS_RESET , +PCI_DEV_WAIT_RESUME , +PCI_DEV_WAIT_DPC , +PCI_DEV_WAIT_MAX , +}; +/* Number of possible devfns: 0.0 to 1f.7 inclusive */ #define MAX_NR_DEVFNS 256
@@ -137,7 +147,7 @@ void pci_msi_init(struct pci_dev *dev);void pci_msix_init (struct pci_dev *dev);bool pci_bridge_d3_possible (struct pci_dev *dev);void pci_bridge_d3_update (struct pci_dev *dev); -int pci_bridge_wait_for_secondary_bus (struct pci_dev *dev,char *reset_type); +int pci_bridge_wait_for_secondary_bus (struct pci_dev *dev,enum pci_reset_type reset_type);static inline void pci_wakeup_event (struct pci_dev *dev) {
drivers/pci/pcie/dpc.c +1 -1
@@ -174,7 +174,7 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)pci_write_config_word (pdev, cap +PCI_EXP_DPC_STATUS ,PCI_EXP_DPC_STATUS_TRIGGER ); -if (pci_bridge_wait_for_secondary_bus (pdev,"DPC" )) { +if (pci_bridge_wait_for_secondary_bus (pdev,PCI_DEV_WAIT_DPC )) {clear_bit (PCI_DPC_RECOVERED , &pdev->priv_flags); ret =PCI_ERS_RESULT_DISCONNECT ; }else {
Signature · 1 line
2.43.0
PATCH v5 2/5 PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
In reply to Mario LimoncielloFrom: Mario Limonciello <[email protected]>
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
A device that has gone through a reset may return a value in PCI_COMMAND but that doesn't mean it's finished transitioning to D0. For evices that support power management explicitly check PCI_PM_CTRL on everything but system resume to ensure the transition happened.
Devices that don't support power management and system resume will continue to use PCI_COMMAND.
---v4->v5:
* Fix misleading indentation
* Amend commit message
--- drivers/pci/pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)
drivers/pci/pci.c +20 -8
@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int* the read (except when CRS SV is enabled and the read was for the * Vendor ID; in that case it synthesizes 0x0001 data). * -* Wait for the device to return a non-CRS completion. Read the -* Command register instead of Vendor ID so we don't have to -* contend with the CRS SV value. +* Wait for the device to return a non-CRS completion. On devices +* that support PM control and on waits that aren't part of system +* resume read the PM control register to ensure the device has +* transitioned to D0. On devices that don't support PM control, +* or during system resume read the command register to instead of +* Vendor ID so we don't have to contend with the CRS SV value. */ for (;;) { -u32 id; -if (pci_dev_is_disconnected (dev)) {pci_dbg (dev,"disconnected; not waiting\n" );return -ENOTTY ; } -pci_read_config_dword (dev,PCI_COMMAND , &id); -if (!PCI_POSSIBLE_ERROR (id)) -break ; +if (dev->pm_cap && reset_type !=PCI_DEV_WAIT_RESUME ) { +u16 pmcsr; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); +if (!PCI_POSSIBLE_ERROR (pmcsr) && + (pmcsr &PCI_PM_CTRL_STATE_MASK ) ==PCI_D0 ) +break ; + }else { +u32 id; + +pci_read_config_dword (dev,PCI_COMMAND , &id); +if (!PCI_POSSIBLE_ERROR (id)) +break ; + }if (delay > timeout) { pci_warn(dev, "not ready %dms after %s; giving up\n",
Signature · 1 line
2.43.0
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
[+cc Duc, Alex]
Quoted 4 lines · Mario Limonciello
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
I assume the USB device in question is in the dock that was hot-added? This patch suggests that pci_dev_wait() has waited for a read of PCI_COMMAND to respond with something other than ~0, but the device is still in D3cold. I suppose we got to pci_dev_wait() via pci_pm_bridge_power_up_actions() calling pci_bridge_wait_for_secondary_bus(), since I wouldn't expect a reset in the hot-add case.
Quoted 4 lines
A device that has gone through a reset may return a value in
PCI_COMMANDbut that doesn't mean it's finished transitioning to D0. For evices that support power management explicitly checkPCI_PM_CTRLon everything but system resume to ensure the transition happened.
s/evices/devices/
Quoted 2 lines
Devices that don't support power management and system resume will continue to use
PCI_COMMAND.
Is there a bugzilla or other report with more details that we can include here?
Quoted 42 lines
Signed-off-by Mario Limonciello <[email protected]>---
v4->v5:
* Fix misleading indentation
* Amend commit message--- drivers/pci/pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)drivers/pci/pci.c +10
-8@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int* the read (except when CRS SV is enabled and the read was for the * Vendor ID; in that case it synthesizes 0x0001 data). * -* Wait for the device to return a non-CRS completion. Read the -* Command register instead of Vendor ID so we don't have to -* contend with the CRS SV value. +* Wait for the device to return a non-CRS completion. On devices +* that support PM control and on waits that aren't part of system +* resume read the PM control register to ensure the device has +* transitioned to D0. On devices that don't support PM control, +* or during system resume read the command register to instead of +* Vendor ID so we don't have to contend with the CRS SV value. */ for (;;) { -u32 id; -if (pci_dev_is_disconnected (dev)) {pci_dbg (dev,"disconnected; not waiting\n" );return -ENOTTY ; } -pci_read_config_dword (dev,PCI_COMMAND , &id); -if (!PCI_POSSIBLE_ERROR (id)) -break ; +if (dev->pm_cap && reset_type !=PCI_DEV_WAIT_RESUME ) { +u16 pmcsr; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr);
drivers/pci/pci.c static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int · line 1338
Quoted 10 lines
drivers/pci/pci.c +10
-0+if (!PCI_POSSIBLE_ERROR (pmcsr) && + (pmcsr &PCI_PM_CTRL_STATE_MASK ) ==PCI_D0 ) +break ; + }else { +u32 id; + +pci_read_config_dword (dev,PCI_COMMAND , &id); +if (!PCI_POSSIBLE_ERROR (id)) +break ; + }
What is the rationale behind using PCI_PM_CTRL in some cases and PCI_COMMAND in others? Is there some spec language we can cite for this?
IIUC, pci_dev_wait() waits for a device to be ready after a reset (FLR, D3hot->D0 transition for devices where No_Soft_Reset is clear, DPC) and after power-up from D3cold (pci_pm_bridge_power_up_actions()). I think device readiness in all of these cases is covered by PCIe r6.0, sec 6.6.1.
If the Root Port above the device supports Configuration RRS Software Visibility, I think we probably should use that here instead of either PCI_COMMAND or PCI_PM_CTRL. SR-IOV VFs don't implement Vendor ID, which might complicate this a little. But it niggles in my mind that there may be some other problem beyond that. Maybe Alex remembers.
Anyway, if we meet the requirements of sec 6.6.1, the device should be ready to respond to config requests, and I assume that also means the device is in D0.
Quoted 5 lines
drivers/pci/pci.c +0
-0if (delay > timeout) { pci_warn(dev, "not ready %dms after %s; giving up\n",Signature · 1 line
2.43.0
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 9 lines · Bjorn Helgaas
[+cc Duc, Alex]
Quoted 4 lines · Mario Limonciello
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
I assume the USB device in question is in the dock that was hot-added?
No; it's actually the USB4 router that is malfunctioning. The CM (thunderbolt.ko) thinks the router is in D0 already, but when it attempts to do a register read it gets back all F's and it trusts that.
Quoted 6 lines
This patch suggests that
pci_dev_wait()has waited for a read ofPCI_COMMANDto respond with something other than ~0, but the device is still in D3cold. I suppose we got topci_dev_wait()viapci_pm_bridge_power_up_actions()callingpci_bridge_wait_for_secondary_bus(), since I wouldn't expect a reset in the hot-add case.
As I said it's the router (part of the SoC). The device never disappears. It's the action of plugging in/out the the dock that causes it to change power states.
We didn't try it, but I wouldn't be surprised if it could be reproduced with a script that turned on/off runtime PM on very tight timing around the autosuspend delay.
Quoted 7 lines
Quoted 5 lines
A device that has gone through a reset may return a value in
PCI_COMMANDbut that doesn't mean it's finished transitioning to D0. For evices that support power management explicitly checkPCI_PM_CTRLon everything but system resume to ensure the transition happened.s/evices/devices/
Thanks.
Quoted 6 lines
Quoted 3 lines
Devices that don't support power management and system resume will continue to use
PCI_COMMAND.Is there a bugzilla or other report with more details that we can include here?
No, unfortunately in this case it was only reported internally at AMD.
Gary who is on CC brought it to me though, and if you think there are some other specific details needed but are missing we can see what else can be added to the commit message.
Quoted 48 lines
Quoted 48 lines
Signed-off-by Mario Limonciello <[email protected]>---
v4->v5:
* Fix misleading indentation
* Amend commit message--- drivers/pci/pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)drivers/pci/pci.c +15
-8@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int* the read (except when CRS SV is enabled and the read was for the * Vendor ID; in that case it synthesizes 0x0001 data). * -* Wait for the device to return a non-CRS completion. Read the -* Command register instead of Vendor ID so we don't have to -* contend with the CRS SV value. +* Wait for the device to return a non-CRS completion. On devices +* that support PM control and on waits that aren't part of system +* resume read the PM control register to ensure the device has +* transitioned to D0. On devices that don't support PM control, +* or during system resume read the command register to instead of +* Vendor ID so we don't have to contend with the CRS SV value. */ for (;;) { -u32 id; -if (pci_dev_is_disconnected (dev)) {pci_dbg (dev,"disconnected; not waiting\n" );return -ENOTTY ; } -pci_read_config_dword (dev,PCI_COMMAND , &id); -if (!PCI_POSSIBLE_ERROR (id)) -break ; +if (dev->pm_cap && reset_type !=PCI_DEV_WAIT_RESUME ) { +u16 pmcsr; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); +if (!PCI_POSSIBLE_ERROR (pmcsr) && + (pmcsr &PCI_PM_CTRL_STATE_MASK ) ==PCI_D0 ) +break ; + }else { +u32 id;
Quoted 8 lines
drivers/pci/pci.c static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int · line 1338
Quoted 5 lines
drivers/pci/pci.c +5
-0+ +pci_read_config_dword (dev,PCI_COMMAND , &id); +if (!PCI_POSSIBLE_ERROR (id)) +break ; + }What is the rationale behind using
PCI_PM_CTRLin some cases andPCI_COMMANDin others?
We saw a deadlock during resume from suspend when PCI_PM_CTRL was used for all cases that supported dev->pm_cap.
Quoted 2 lines
Is there some spec language we can cite for
this?
Perhaps it being a "cold reset" during resume?
Quoted 6 lines
IIUC,
pci_dev_wait()waits for a device to be ready after a reset (FLR,D3hot->D0transition for devices whereNo_Soft_Resetis clear, DPC) and after power-up from D3cold (pci_pm_bridge_power_up_actions()). I think device readiness in all of these cases is covered by PCIe r6.0, sec 6.6.1.
Would it be helpful to you to get a dump_stack() call trace to pci_power_up() the specific call flow that needed this fix?
Gary is able to to reproduce this at will, I think he should be able to gather that using an unpatched kernel to help this conversation.
Quoted 4 lines
If the Root Port above the device supports Configuration RRS Software Visibility, I think we probably should use that here instead of either
PCI_COMMANDorPCI_PM_CTRL.
I did check and in this case the root port the USB4 routers are connected to support this.
How do you think this should be done instead?
Quoted 10 lines
SR-IOV VFs don't implement Vendor ID,
which might complicate this a little. But it niggles in my mind that there may be some other problem beyond that. Maybe Alex remembers.Anyway, if we meet the requirements of sec 6.6.1, the device should be ready to respond to config requests, and I assume that also means the device is in D0.
Within that section there is a quote to point out:
"
To allow components to perform internal initialization, system software must wait a specified minimum period following exit from a Conventional Reset of one or more devices before it is permitted to issue Configuration Requests to those devices
"
In pci_power_up() I don't really see any hardcoded delays specifically for this case of leaving D3cold. The PCI PM spec specifies that it will take "Full context restore or boot latency". I don't think it's reasonable to have NO delay.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 117 lines · Mario Limonciello
Quoted 9 lines · Bjorn Helgaas
[+cc Duc, Alex]
Quoted 4 lines · Mario Limonciello
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
I assume the USB device in question is in the dock that was hot-added?
No; it's actually the USB4 router that is malfunctioning. The CM (thunderbolt.ko) thinks the router is in D0 already, but when it attempts to do a register read it gets back all F's and it trusts that.
Quoted 6 lines
This patch suggests that
pci_dev_wait()has waited for a read ofPCI_COMMANDto respond with something other than ~0, but the device is still in D3cold. I suppose we got topci_dev_wait()viapci_pm_bridge_power_up_actions()callingpci_bridge_wait_for_secondary_bus(), since I wouldn't expect a reset in the hot-add case.As I said it's the router (part of the SoC). The device never disappears. It's the action of plugging in/out the the dock that causes it to change power states.
We didn't try it, but I wouldn't be surprised if it could be reproduced with a script that turned on/off runtime PM on very tight timing around the autosuspend delay.
Quoted 7 lines
Quoted 5 lines
A device that has gone through a reset may return a value in
PCI_COMMANDbut that doesn't mean it's finished transitioning to D0. For evices that support power management explicitly checkPCI_PM_CTRLon everything but system resume to ensure the transition happened.s/evices/devices/
Thanks.
Quoted 6 lines
Quoted 3 lines
Devices that don't support power management and system resume will continue to use
PCI_COMMAND.Is there a bugzilla or other report with more details that we can include here?
No, unfortunately in this case it was only reported internally at AMD.
Gary who is on CC brought it to me though, and if you think there are some other specific details needed but are missing we can see what else can be added to the commit message.
Quoted 49 lines
Quoted 49 lines
Signed-off-by Mario Limonciello <[email protected]>---
v4->v5:
* Fix misleading indentation
* Amend commit message
---
drivers/pci/pci.c| 28 ++++++++++++++++++++--------1 file changed, 20 insertions(+), 8 deletions(-)drivers/pci/pci.c +0
-0@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev,enum
pci_reset_typereset_type, int
* the read (except when CRS SV is enabled and the read was for the
* Vendor ID; in that case it synthesizes0x0001data). *
- * Wait for the device to return a non-CRS completion. Read the - * Command register instead of Vendor ID so we don't have to - * contend with the CRS SV value.
+ * Wait for the device to return a non-CRS completion. On devices + * that support PM control and on waits that aren't part of system + * resume read the PM control register to ensure the device has + * transitioned to D0. On devices that don't support PM control, + * or during system resume read the command register to instead of + * Vendor ID so we don't have to contend with the CRS SV value. */
for (;;) {
- u32 id;
-
if (pci_dev_is_disconnected(dev)) {
pci_dbg(dev, "disconnected; not waiting\n"); return-ENOTTY;
}
-pci_read_config_dword(dev, PCI_COMMAND, &id);
- if (!PCI_POSSIBLE_ERROR(id))
- break;
+ if (dev->pm_cap&&reset_type!=PCI_DEV_WAIT_RESUME) { + u16 pmcsr;
+
+pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ if (!PCI_POSSIBLE_ERROR(pmcsr) &&
+ (pmcsr &PCI_PM_CTRL_STATE_MASK) ==PCI_D0) + break;
+ } else {
+ u32 id;Quoted 8 lines
Quoted 5 lines
+
+pci_read_config_dword(dev, PCI_COMMAND, &id); + if (!PCI_POSSIBLE_ERROR(id))
+ break;
+ }What is the rationale behind using
PCI_PM_CTRLin some cases andPCI_COMMANDin others?We saw a deadlock during resume from suspend when
PCI_PM_CTRLwas used for all cases that supporteddev->pm_cap.Quoted 2 lines
Is there some spec language we can cite for
this?Perhaps it being a "cold reset" during resume?
Quoted 6 lines
IIUC,
pci_dev_wait()waits for a device to be ready after a reset (FLR,D3hot->D0transition for devices whereNo_Soft_Resetis clear, DPC) and after power-up from D3cold (pci_pm_bridge_power_up_actions()). I think device readiness in all of these cases is covered by PCIe r6.0, sec 6.6.1.
Quoted 3 lines
Would it be helpful to you to get a
dump_stack()call trace topci_power_up()the specific call flow that needed this fix?Gary is able to to reproduce this at will, I think he should be able to gather that using an unpatched kernel to help this conversation.
Here is the kernel trace with a dump_stack() and a printk of current inserted into pci_power_up() right before the failure occurs.
https://gist.github.com/superm1/cb407766ab15f42f12a6fe9d1196f6fc
Also the failure is visible right after.
Quoted 30 lines
Quoted 5 lines
If the Root Port above the device supports Configuration RRS Software Visibility, I think we probably should use that here instead of either
PCI_COMMANDorPCI_PM_CTRL.I did check and in this case the root port the USB4 routers are connected to support this.
How do you think this should be done instead?
Quoted 10 lines
SR-IOV VFs don't implement Vendor ID,
which might complicate this a little. But it niggles in my mind that there may be some other problem beyond that. Maybe Alex remembers.Anyway, if we meet the requirements of sec 6.6.1, the device should be ready to respond to config requests, and I assume that also means the device is in D0.
Within that section there is a quote to point out:
"
To allow components to perform internal initialization, system software must wait a specified minimum period following exit from a Conventional Reset of one or more devices before it is permitted to issue Configuration Requests to those devices
"In
pci_power_up()I don't really see any hardcoded delays specifically for this case of leaving D3cold. The PCI PM spec specifies that it will take "Full context restore or boot latency". I don't think it's reasonable to have NO delay.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
In reply to Mario Limonciello[+cc Rafael for ACPI power transition from D3cold to D0 delay]
Quoted 103 lines · Mario Limonciello
Quoted 5 lines · Bjorn Helgaas
Quoted 4 lines · Mario Limonciello
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
...
Quoted 5 lines
Quoted 5 lines
A device that has gone through a reset may return a value in
PCI_COMMANDbut that doesn't mean it's finished transitioning to D0. For devices that support power management explicitly checkPCI_PM_CTRLon everything but system resume to ensure the transition happened....
Quoted 38 lines
Quoted 38 lines
Devices that don't support power management and system resume will continue to use
PCI_COMMAND.drivers/pci/pci.c +15
-8@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int* the read (except when CRS SV is enabled and the read was for the * Vendor ID; in that case it synthesizes 0x0001 data). * -* Wait for the device to return a non-CRS completion. Read the -* Command register instead of Vendor ID so we don't have to -* contend with the CRS SV value. +* Wait for the device to return a non-CRS completion. On devices +* that support PM control and on waits that aren't part of system +* resume read the PM control register to ensure the device has +* transitioned to D0. On devices that don't support PM control, +* or during system resume read the command register to instead of +* Vendor ID so we don't have to contend with the CRS SV value. */ for (;;) { -u32 id; -if (pci_dev_is_disconnected (dev)) {pci_dbg (dev,"disconnected; not waiting\n" );return -ENOTTY ; } -pci_read_config_dword (dev,PCI_COMMAND , &id); -if (!PCI_POSSIBLE_ERROR (id)) -break ; +if (dev->pm_cap && reset_type !=PCI_DEV_WAIT_RESUME ) { +u16 pmcsr; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); +if (!PCI_POSSIBLE_ERROR (pmcsr) && + (pmcsr &PCI_PM_CTRL_STATE_MASK ) ==PCI_D0 ) +break ; + }else { +u32 id;Quoted 8 lines
drivers/pci/pci.c static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int · line 1338
Quoted 5 lines
drivers/pci/pci.c +5
-0+ +pci_read_config_dword (dev,PCI_COMMAND , &id); +if (!PCI_POSSIBLE_ERROR (id)) +break ; + }What is the rationale behind using
PCI_PM_CTRLin some cases andPCI_COMMANDin others?We saw a deadlock during resume from suspend when
PCI_PM_CTRLwas used for all cases that supporteddev->pm_cap.Quoted 2 lines
Is there some spec language we can cite for
this?Perhaps it being a "cold reset" during resume?
Quoted 5 lines
IIUC,
pci_dev_wait()waits for a device to be ready after a reset (FLR,D3hot->D0transition for devices whereNo_Soft_Resetis clear, DPC) and after power-up from D3cold (pci_pm_bridge_power_up_actions()). I think device readiness in all of these cases is covered by PCIe r6.0, sec 6.6.1....
Quoted 3 lines
If the Root Port above the device supports Configuration RRS Software Visibility, I think we probably should use that here instead of either
PCI_COMMANDorPCI_PM_CTRL.I did check and in this case the root port the USB4 routers are connected to support this.
How do you think this should be done instead?
Quoted 7 lines
SR-IOV VFs don't implement Vendor ID, which might complicate this a little. But it niggles in my mind that there may be some other problem beyond that. Maybe Alex remembers.
Anyway, if we meet the requirements of sec 6.6.1, the device should be ready to respond to config requests, and I assume that also means the device is in D0.
Within that section there is a quote to point out:
"
To allow components to perform internal initialization, system software must wait a specified minimum period following exit from a Conventional Reset of one or more devices before it is permitted to issue Configuration Requests to those devices
"
Quoted 4 lines
In
pci_power_up()I don't really see any hardcoded delays specifically for this case of leaving D3cold. The PCI PM spec specifies that it will take "Full context restore or boot latency". I don't think it's reasonable to have NO delay.
I agree, leaving D3cold means "applying power to the device", and PCIe r6.0, sec 6.6.1, says that's a Fundamental Reset:
A Fundamental Reset must occur following the application of power to the component. This is called a Cold Reset.
So we need a delay similar to what we do in pci_bridge_wait_for_secondary_bus(). I don't know whether that is supposed to happen somewhere on the ACPI side or in the PCI side, but my inclination would be the PCI side because the delay isn't really platform-specific, it's specified by the PCI specs, and the OS needs to manage the RRS Software Visibility retries and features like Readiness Notifications.
pci_set_low_power_state() contains corresponding delays for putting devices in D1, D2, and D3hot.
Maybe the D3cold -> D0 delays should be in platform_pci_set_power_state()? I think pci_power_up() is the only caller that sets the state to D0, and it assumes the device is Configuration Ready when platform_pci_set_power_state() returns:
pci_power_up
platform_pci_set_power_state
pci_read_config_word(PCI_PM_CTRL)
So I think we need basically the same delays and pci_dev_wait() stuff in this path.
Bjorn
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
In reply to Mario LimoncielloQuoted 7 lines · Mario Limonciello
From: Mario Limonciello <[email protected]>
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
Quoted 5 lines
A device that has gone through a reset may return a value in
PCI_COMMANDbut that doesn't mean it's finished transitioning to D0. For devices that support power management explicitly checkPCI_PM_CTRLon everything but system resume to ensure the transition happened.
Still trying to understand what's going on here.
I posted a change to pci_dev_wait() to read Vendor ID, look for Config RRS status, and wait for a successful completion (when RRS Software Visibility is enabled) [1].
You tested that and found that it didn't help with *this* issue [2]. I assume you tested something like v6.11-rc plus the patches from [1], i.e., without the PCI_PM_CTRL changes in this series.
1) Initially the device is in D0
2) We put it in D3cold (using some ACPI method) because the autosuspend delay expired (?)
3) Plugging in the dock wakes up the device, so we power up the device (via pci_power_up(), which again uses some ACPI method), and it should transition to D0uninitialized
4) The USB4 stack sees the device but thinks it's in D3cold (?)
If your testing only included [1], but did not include the pci_power_up() change from patch 3/5 "Verify functions currently in D3cold have entered D0", I don't think we would call pci_dev_wait(), so I wouldn't expect [1] to make any difference.
If you *did* include both [1] and patch 3/5, the implication would be that pci_dev_wait() successfully read the Vendor ID, meaning the device is not in D3cold when pci_power_up() returns.
Can you clarify what you see and possibly expand/correct my timeline above?
[1] https://lore.kernel.org/linux-pci/[email protected]/
[2] https://lore.kernel.org/linux-pci/[email protected]/
Quoted 61 lines
Devices that don't support power management and system resume will continue to use
PCI_COMMAND.Signed-off-by Mario Limonciello <[email protected]>---
v4->v5:
* Fix misleading indentation
* Amend commit message--- drivers/pci/pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)drivers/pci/pci.c +20
-8@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int* the read (except when CRS SV is enabled and the read was for the * Vendor ID; in that case it synthesizes 0x0001 data). * -* Wait for the device to return a non-CRS completion. Read the -* Command register instead of Vendor ID so we don't have to -* contend with the CRS SV value. +* Wait for the device to return a non-CRS completion. On devices +* that support PM control and on waits that aren't part of system +* resume read the PM control register to ensure the device has +* transitioned to D0. On devices that don't support PM control, +* or during system resume read the command register to instead of +* Vendor ID so we don't have to contend with the CRS SV value. */ for (;;) { -u32 id; -if (pci_dev_is_disconnected (dev)) {pci_dbg (dev,"disconnected; not waiting\n" );return -ENOTTY ; } -pci_read_config_dword (dev,PCI_COMMAND , &id); -if (!PCI_POSSIBLE_ERROR (id)) -break ; +if (dev->pm_cap && reset_type !=PCI_DEV_WAIT_RESUME ) { +u16 pmcsr; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); +if (!PCI_POSSIBLE_ERROR (pmcsr) && + (pmcsr &PCI_PM_CTRL_STATE_MASK ) ==PCI_D0 ) +break ; + }else { +u32 id; + +pci_read_config_dword (dev,PCI_COMMAND , &id); +if (!PCI_POSSIBLE_ERROR (id)) +break ; + }if (delay > timeout) { pci_warn(dev, "not ready %dms after %s; giving up\n",Signature · 1 line
2.43.0
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 35 lines · Bjorn Helgaas
Quoted 7 lines · Mario Limonciello
From: Mario Limonciello <[email protected]>
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
Quoted 5 lines
A device that has gone through a reset may return a value in
PCI_COMMANDbut that doesn't mean it's finished transitioning to D0. For devices that support power management explicitly checkPCI_PM_CTRLon everything but system resume to ensure the transition happened.Still trying to understand what's going on here.
I posted a change to
pci_dev_wait()to read Vendor ID, look for Config RRS status, and wait for a successful completion (when RRS Software Visibility is enabled) [1].You tested that and found that it didn't help with *this* issue [2]. I assume you tested something like v6.11-rc plus the patches from [1], i.e., without the
PCI_PM_CTRLchanges in this series.1) Initially the device is in D0
2) We put it in D3cold (using some ACPI method) because the autosuspend delay expired (?)
3) Plugging in the dock wakes up the device, so we power up the device (via
pci_power_up(), which again uses some ACPI method), and it should transition to D0uninitialized4) The USB4 stack sees the device but thinks it's in D3cold (?)
Quoted 8 lines
If your testing only included [1], but did not include the
pci_power_up()change from patch 3/5 "Verify functions currently in D3cold have entered D0", I don't think we would callpci_dev_wait(), so I wouldn't expect [1] to make any difference.If you *did* include both [1] and patch 3/5, the implication would be that
pci_dev_wait()successfully read the Vendor ID, meaning the device is not in D3cold whenpci_power_up()returns.
The testing here was from the LTS 6.6.y kernel with both [1] and patch 3/5 from this series.
I can get testing from 6.11-rc6 with a combination of patches if you would like.
Quoted 3 lines
Can you clarify what you see and possibly expand/correct my timeline above?
The timeline you shared is nearly correct. The USB4 stack *thinks* the device is in D0 because of the return of pci_power_up().
As by polling PCI_PM_CTRL we can see it's still in D3, so it hasn't made it to D0uninitialized yet.
I guess I reading between the lines you have an assumption that you can't read the vendor ID from D3; which doesn't appear to be the case from our testing.
Quoted 65 lines
[1] https://lore.kernel.org/linux-pci/[email protected]/
[2] https://lore.kernel.org/linux-pci/[email protected]/Quoted 61 lines
Devices that don't support power management and system resume will continue to use
PCI_COMMAND.Signed-off-by Mario Limonciello <[email protected]>---
v4->v5:
* Fix misleading indentation
* Amend commit message--- drivers/pci/pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)drivers/pci/pci.c +20
-8@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int* the read (except when CRS SV is enabled and the read was for the * Vendor ID; in that case it synthesizes 0x0001 data). * -* Wait for the device to return a non-CRS completion. Read the -* Command register instead of Vendor ID so we don't have to -* contend with the CRS SV value. +* Wait for the device to return a non-CRS completion. On devices +* that support PM control and on waits that aren't part of system +* resume read the PM control register to ensure the device has +* transitioned to D0. On devices that don't support PM control, +* or during system resume read the command register to instead of +* Vendor ID so we don't have to contend with the CRS SV value. */ for (;;) { -u32 id; -if (pci_dev_is_disconnected (dev)) {pci_dbg (dev,"disconnected; not waiting\n" );return -ENOTTY ; } -pci_read_config_dword (dev,PCI_COMMAND , &id); -if (!PCI_POSSIBLE_ERROR (id)) -break ; +if (dev->pm_cap && reset_type !=PCI_DEV_WAIT_RESUME ) { +u16 pmcsr; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); +if (!PCI_POSSIBLE_ERROR (pmcsr) && + (pmcsr &PCI_PM_CTRL_STATE_MASK ) ==PCI_D0 ) +break ; + }else { +u32 id; + +pci_read_config_dword (dev,PCI_COMMAND , &id); +if (!PCI_POSSIBLE_ERROR (id)) +break ; + }if (delay > timeout) { pci_warn(dev, "not ready %dms after %s; giving up\n",Signature · 1 line
2.43.0
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 50 lines · Mario Limonciello
Quoted 34 lines · Bjorn Helgaas
Quoted 7 lines · Mario Limonciello
From: Mario Limonciello <[email protected]>
If a dock is plugged in at the same time as autosuspend delay then this can cause malfunctions in the USB4 stack. This happens because the device is still in D3cold at the time that the PCI core handed control back to the USB4 stack.
Quoted 5 lines
A device that has gone through a reset may return a value in
PCI_COMMANDbut that doesn't mean it's finished transitioning to D0. For devices that support power management explicitly checkPCI_PM_CTRLon everything but system resume to ensure the transition happened.Still trying to understand what's going on here.
I posted a change to
pci_dev_wait()to read Vendor ID, look for Config RRS status, and wait for a successful completion (when RRS Software Visibility is enabled) [1].You tested that and found that it didn't help with *this* issue [2]. I assume you tested something like v6.11-rc plus the patches from [1], i.e., without the
PCI_PM_CTRLchanges in this series.1) Initially the device is in D0
2) We put it in D3cold (using some ACPI method) because the autosuspend delay expired (?)
3) Plugging in the dock wakes up the device, so we power up the device (via
pci_power_up(), which again uses some ACPI method), and it should transition to D0uninitialized4) The USB4 stack sees the device but thinks it's in D3cold (?)
...
Quoted 3 lines
If you *did* include both [1] and patch 3/5, the implication would be that
pci_dev_wait()successfully read the Vendor ID, meaning the device is not in D3cold whenpci_power_up()returns.The testing here was from the LTS 6.6.y kernel with both [1] and patch 3/5 from this series.
Quoted 2 lines
Can you clarify what you see and possibly expand/correct my timeline above?
The timeline you shared is nearly correct. The USB4 stack *thinks* the device is in D0 because of the return of
pci_power_up().
Quoted 6 lines
As by polling
PCI_PM_CTRLwe can see it's still in D3, so it hasn't made it to D0uninitialized yet.I guess I reading between the lines you have an assumption that you can't read the vendor ID from D3; which doesn't appear to be the case from our testing.
A Vendor ID read of a device in D3hot should definitely work. Obviously if the device were in D3cold, we'd get no response at all, so the requester should log a UR error and fabricate ~0 data.
But if the device starts out in D3cold and we power it up, it should not go through D3hot. The only legal transition from D3cold is to D0uninitialized (PCIe r6.0, sec 5.8).
OK, so with [1] and patch 3/5:
1) Initially the device is in D0
2) We put it in D3cold (using some ACPI method) because the autosuspend delay expired (?)
3) Plugging in the dock wakes up the device, so we power up the device (via pci_power_up(), which again uses some ACPI method), and it should transition to D0uninitialized
4) With patch 3/5, pci_power_up() calls pci_dev_wait() because dev->current_state == PCI_D3cold
5) I *assume* RRS SV is enabled (lspci -vv of Root Port would confirm this; maybe we should add a pci_dbg message about which register we're polling). If so, patch [1] means we should poll Vendor ID until successful completion.
6) pci_dbg log should confirm the device is ready with a "ready %dms after D3cold->D0" message, which would mean we got a successful completion when reading Vendor ID
7) For debugging purposes, it would be interesting to read and log the PCI_PM_CTRL value here. Per sec 2.3.1, the device is not allowed to return RRS at this point since we already got a successful completion.
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Quoted 63 lines
Quoted 62 lines
[1] https://lore.kernel.org/linux-pci/[email protected]/
[2] https://lore.kernel.org/linux-pci/[email protected]/Quoted 59 lines
Devices that don't support power management and system resume will continue to use
PCI_COMMAND.Signed-off-by Mario Limonciello <[email protected]>---
v4->v5:
* Fix misleading indentation
* Amend commit message--- drivers/pci/pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)drivers/pci/pci.c +20
-8@@ -1309,21 +1309,33 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_reset_type reset_type, int* the read (except when CRS SV is enabled and the read was for the * Vendor ID; in that case it synthesizes 0x0001 data). * -* Wait for the device to return a non-CRS completion. Read the -* Command register instead of Vendor ID so we don't have to -* contend with the CRS SV value. +* Wait for the device to return a non-CRS completion. On devices +* that support PM control and on waits that aren't part of system +* resume read the PM control register to ensure the device has +* transitioned to D0. On devices that don't support PM control, +* or during system resume read the command register to instead of +* Vendor ID so we don't have to contend with the CRS SV value. */ for (;;) { -u32 id; -if (pci_dev_is_disconnected (dev)) {pci_dbg (dev,"disconnected; not waiting\n" );return -ENOTTY ; } -pci_read_config_dword (dev,PCI_COMMAND , &id); -if (!PCI_POSSIBLE_ERROR (id)) -break ; +if (dev->pm_cap && reset_type !=PCI_DEV_WAIT_RESUME ) { +u16 pmcsr; + +pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); +if (!PCI_POSSIBLE_ERROR (pmcsr) && + (pmcsr &PCI_PM_CTRL_STATE_MASK ) ==PCI_D0 ) +break ; + }else { +u32 id; + +pci_read_config_dword (dev,PCI_COMMAND , &id); +if (!PCI_POSSIBLE_ERROR (id)) +break ; + }if (delay > timeout) { pci_warn(dev, "not ready %dms after %s; giving up\n",Signature · 1 line
2.43.0
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
On 9/3/2024 12:11, Bjorn Helgaas wrote:
<snip>
Quoted 5 lines
Quoted 4 lines
I guess I reading between the lines you have an assumption that you can't read the vendor ID from D3; which doesn't appear to be the case from our testing.
Quoted 7 lines
A Vendor ID read of a device in D3hot should definitely work. Obviously if the device were in D3cold, we'd get no response at all, so the requester should log a UR error and fabricate ~0 data.
But if the device starts out in D3cold and we power it up, it should not go through D3hot. The only legal transition from D3cold is to D0uninitialized (PCIe r6.0, sec 5.8).
Right. The issue is it didn't finish getting into D3 at the time that we attempted to go to D0 though. So all this extra time is basically waiting for the D0->D3 transition to finish followed by D3->D0uninitialized.
The best description I could offer is to call it an "aborted" D3.
Quoted 12 lines
OK, so with [1] and patch 3/5:
1) Initially the device is in D0
2) We put it in D3cold (using some ACPI method) because the autosuspend delay expired (?)
3) Plugging in the dock wakes up the device, so we power up the device (via
pci_power_up(), which again uses some ACPI method), and it should transition to D0uninitialized
Quoted 8 lines
4) With patch 3/5,
pci_power_up()callspci_dev_wait()becausedev->current_state==PCI_D3cold5) I *assume* RRS SV is enabled (lspci -vv of Root Port would confirm this; maybe we should add a
pci_dbgmessage about which register we're polling). If so, patch [1] means we should poll Vendor ID until successful completion.
Yup.
RootCap: CRSVisible+
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal-
PMEIntEna+ CRSVisible+
Quoted 9 lines
6)
pci_dbglog should confirm the device is ready with a "ready %dms afterD3cold->D0" message, which would mean we got a successful completion when reading Vendor ID7) For debugging purposes, it would be interesting to read and log the
PCI_PM_CTRLvalue here. Per sec 2.3.1, the device is not allowed to return RRS at this point since we already got a successful completion.
OK let me get a debug log with [1], 3/5, 6.11-rc6 and a message added about this value to share back.
Quoted 4 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Yes there is. From earlier in the thread I have a [log] I shared.
The message emitted is from ring_interrupt_active():
"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
[log] https://gist.github.com/superm1/cb407766ab15f42f12a6fe9d1196f6fc
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 7 lines · Mario Limonciello
On 9/3/2024 12:11, Bjorn Helgaas wrote:
...Quoted 3 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Quoted 5 lines
Yes there is. From earlier in the thread I have a [log] I shared.
The message emitted is from
ring_interrupt_active():"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
Right, that's in the cover letter, but I can't tell from this what the ioread32(ring->nhi->iobase + reg) returned. It looks like this is an MMIO read of BAR 0, not a config read.
Quoted 1 line
[log] https://gist.github.com/superm1/cb407766ab15f42f12a6fe9d1196f6fc
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Mario Limonciello
On 9/3/2024 12:11, Bjorn Helgaas wrote:
...Quoted 3 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Yes there is. From earlier in the thread I have a [log] I shared.
Quoted 8 lines
Quoted 3 lines
The message emitted is from
ring_interrupt_active():"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
Right, that's in the cover letter, but I can't tell from this what the
ioread32(ring->nhi->iobase + reg)returned. It looks like this is an MMIO read of BAR 0, not a config read.
Yeah. I suppose another way to approach this problem is to make something else in the call chain poll PCI_PM_CTRL.
Polling at the start of nhi_runtime_resume() should also work. For the "normal" scenario it would just be a single read to PCI_PM_CTRL.
Mika, thoughts?
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 19 lines · Mario Limonciello
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Mario Limonciello
On 9/3/2024 12:11, Bjorn Helgaas wrote:
...Quoted 3 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Yes there is. From earlier in the thread I have a [log] I shared.
Quoted 7 lines
Quoted 3 lines
The message emitted is from
ring_interrupt_active():"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
Right, that's in the cover letter, but I can't tell from this what the
ioread32(ring->nhi->iobase + reg)returned. It looks like this is an MMIO read of BAR 0, not a config read.
Quoted 5 lines
Yeah. I suppose another way to approach this problem is to make something else in the call chain poll
PCI_PM_CTRL.Polling at the start of
nhi_runtime_resume()should also work. For the "normal" scenario it would just be a single read toPCI_PM_CTRL.
It doesn't sound like this is anything specific to Thunderbolt, so there should be a generic solution.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
In reply to Mario LimoncielloHi,
Quoted 20 lines · Mario Limonciello
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Mario Limonciello
On 9/3/2024 12:11, Bjorn Helgaas wrote:
...Quoted 3 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Yes there is. From earlier in the thread I have a [log] I shared.
Quoted 8 lines
Quoted 3 lines
The message emitted is from
ring_interrupt_active():"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
Right, that's in the cover letter, but I can't tell from this what the
ioread32(ring->nhi->iobase + reg)returned. It looks like this is an MMIO read of BAR 0, not a config read.
Quoted 7 lines
Yeah. I suppose another way to approach this problem is to make something else in the call chain poll
PCI_PM_CTRL.Polling at the start of
nhi_runtime_resume()should also work. For the "normal" scenario it would just be a single read toPCI_PM_CTRL.Mika, thoughts?
I'm starting to wonder if we are looking at the correct place ;-) This reminds me that our PCIe SV people recently reported a couple of Linux related issues which they recommended to fix, and these are on my list but I'll share them because maybe they are related?
First problem, and actually a PCI spec violation, is that Linux does not clear Bus Master, MMIO and IO space enables when it programs the device to D3 on runtime suspend path. It does so on system sleep path though. Something like below (untested) should do that:
drivers/pci/pci-driver.c +1 -0
@@ -1332,6 +1332,7 @@ static int pci_pm_runtime_suspend(struct device *dev)if (!pci_dev->state_saved) {pci_save_state (pci_dev); +pci_pm_default_suspend (pci_dev);pci_finish_runtime_suspend (pci_dev); }
The second thing is that Thunderbolt driver, for historical reasons, leaves the MSI enabled when entering D3. This too might be related. I think we can unconditionally disable it so below hack should do that (untested as well). I wonder if you could try if any of these or both can help here? Both of these issues can result unwanted events during D3 entry as far as I understand.
drivers/thunderbolt/ctl.c +2 -3
@@ -659,12 +659,11 @@ struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int index, int timeout_msec,if (!ctl->frame_pool) goto err; - ctl->tx =tb_ring_alloc_tx (nhi,0 ,10 ,RING_FLAG_NO_SUSPEND ); + ctl->tx =tb_ring_alloc_tx (nhi,0 ,10 ,0 );if (!ctl->tx) goto err; - ctl->rx =tb_ring_alloc_rx (nhi,0 ,10 ,RING_FLAG_NO_SUSPEND ,0 ,0xffff , -0xffff ,NULL ,NULL ); + ctl->rx =tb_ring_alloc_rx (nhi,0 ,10 ,0 ,0 ,0xffff ,0xffff ,NULL ,NULL );if (!ctl->rx) goto err;
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 30 lines · Mika Westerberg
Hi,
Quoted 27 lines · Mario Limonciello
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Mario Limonciello
On 9/3/2024 12:11, Bjorn Helgaas wrote:
...Quoted 3 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Yes there is. From earlier in the thread I have a [log] I shared.
Quoted 8 lines
Quoted 3 lines
The message emitted is from
ring_interrupt_active():"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
Right, that's in the cover letter, but I can't tell from this what the
ioread32(ring->nhi->iobase + reg)returned. It looks like this is an MMIO read of BAR 0, not a config read.Yeah. I suppose another way to approach this problem is to make something else in the call chain poll
PCI_PM_CTRL.Polling at the start of
nhi_runtime_resume()should also work. For the "normal" scenario it would just be a single read toPCI_PM_CTRL.Mika, thoughts?
We did this experiment to throw code to poll PCI_PM_CTRL at the start of nhi_runtime_resume() but this also fails. From that I would hypothesize the device transitioned to D0uninitialized sometime in the middle of pci_pm_runtime_resume() before the call to pm->runtime_resume(dev);
Quoted 5 lines
I'm starting to wonder if we are looking at the correct place ;-) This reminds me that our PCIe SV people recently reported a couple of Linux related issues which they recommended to fix, and these are on my list but I'll share them because maybe they are related?
Thanks for sharing those. We had a try with them but sorry to say no improvements to the issue at hand.
Quoted 45 lines
First problem, and actually a PCI spec violation, is that Linux does not clear Bus Master, MMIO and IO space enables when it programs the device to D3 on runtime suspend path. It does so on system sleep path though. Something like below (untested) should do that:
drivers/pci/pci-driver.c +1
-0@@ -1332,6 +1332,7 @@ static int pci_pm_runtime_suspend(struct device *dev)if (!pci_dev->state_saved) {pci_save_state (pci_dev); +pci_pm_default_suspend (pci_dev);pci_finish_runtime_suspend (pci_dev); }The second thing is that Thunderbolt driver, for historical reasons, leaves the MSI enabled when entering D3. This too might be related. I think we can unconditionally disable it so below hack should do that (untested as well). I wonder if you could try if any of these or both can help here? Both of these issues can result unwanted events during D3 entry as far as I understand.
drivers/thunderbolt/ctl.c +2
-3@@ -659,12 +659,11 @@ struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int index, int timeout_msec,if (!ctl->frame_pool) goto err; - ctl->tx =tb_ring_alloc_tx (nhi,0 ,10 ,RING_FLAG_NO_SUSPEND ); + ctl->tx =tb_ring_alloc_tx (nhi,0 ,10 ,0 );if (!ctl->tx) goto err; - ctl->rx =tb_ring_alloc_rx (nhi,0 ,10 ,RING_FLAG_NO_SUSPEND ,0 ,0xffff , -0xffff ,NULL ,NULL ); + ctl->rx =tb_ring_alloc_rx (nhi,0 ,10 ,0 ,0 ,0xffff ,0xffff ,NULL ,NULL );if (!ctl->rx) goto err;
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Hi,
Quoted 38 lines · Mario Limonciello
Quoted 30 lines · Mika Westerberg
Hi,
Quoted 27 lines · Mario Limonciello
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Mario Limonciello
On 9/3/2024 12:11, Bjorn Helgaas wrote:
...Quoted 3 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Yes there is. From earlier in the thread I have a [log] I shared.
Quoted 8 lines
Quoted 3 lines
The message emitted is from
ring_interrupt_active():"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
Right, that's in the cover letter, but I can't tell from this what the
ioread32(ring->nhi->iobase + reg)returned. It looks like this is an MMIO read of BAR 0, not a config read.Yeah. I suppose another way to approach this problem is to make something else in the call chain poll
PCI_PM_CTRL.Polling at the start of
nhi_runtime_resume()should also work. For the "normal" scenario it would just be a single read toPCI_PM_CTRL.Mika, thoughts?
We did this experiment to throw code to poll
PCI_PM_CTRLat the start ofnhi_runtime_resume()but this also fails. From that I would hypothesize the device transitioned to D0uninitialized sometime in the middle ofpci_pm_runtime_resume()before the call topm->runtime_resume(dev);Quoted 1 line
Quoted 7 lines
Quoted 4 lines
I'm starting to wonder if we are looking at the correct place ;-) This reminds me that our PCIe SV people recently reported a couple of Linux related issues which they recommended to fix, and these are on my list but I'll share them because maybe they are related?
Thanks for sharing those. We had a try with them but sorry to say no improvements to the issue at hand.
Okay, thanks for checking.
Few additional side paths here, though. This is supposed to work so that once the host router sleep bit is set the driver is supposed to allow the domain to enter sleep (e.g it should not be waken up before it is fully transitioned). That's what we do:
1. All tunneled PCIe Root/Downstream ports are in D3.
2. All tunneled USB 3.x ports are in U3.
3. No DisplayPort is tunneled.
4. Thunderbolt driver enables wakes.
5. Thunderbolt driver writes sleep ready bit of the host router.
6. Thunderbolt driver runtime suspend is complete.
7. ACPI method is called (_PS3 or _PR3.OFF) that will trigger the "Sleep Event".
If between 5 and 7 there is device connected, it should not "abort" the sequence. Unfortunately this is not explict in the USB4 spec but the connection manager guide has similar note. Even if the connect happens there the "Sleep Event" should happen but after that it can trigger normal wakeup which will then bring everything back.
Would it be possible to enable tracing around these steps so that we could see if there is hotplug notification somewhere there that is not expected? Here are instructions how to get pretty accurate trace:
https://github.com/intel/tbtools?tab=readme-ov-file#tracing
Please also take full dmesg.
It is entirely possible that this has nothing to do with the issue but I think it is worth checking.
The second thing we could try is to check the wake status bits after this has happened, like:
# tbdump -r 0 -a <ADAPTER> -vv -N 1 PORT_CS_18
(where <ADAPTER> is the lane 0 adapter of the USB4 port the device was connected).
The third thing to try is to comment out TB_WAKE_ON_CONNECT in tb_switch_suspend(). This should result no wake even if the device is connected. This tells us that it is really the connect on USB4 port that triggered the wake.
These could (also) explain why the host router appears to be in D3 even if it should be in D0 already.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 71 lines · Mika Westerberg
Hi,
Quoted 38 lines · Mario Limonciello
Quoted 30 lines · Mika Westerberg
Hi,
Quoted 27 lines · Mario Limonciello
Quoted 10 lines · Bjorn Helgaas
Quoted 9 lines · Mario Limonciello
On 9/3/2024 12:11, Bjorn Helgaas wrote:
...Quoted 3 lines
8) The USB4 stack sees the device and assumes it is in D0, but it seems to still be in D3cold. What is this based on? Is there a config read that returns ~0 data when it shouldn't?
Yes there is. From earlier in the thread I have a [log] I shared.
Quoted 8 lines
Quoted 3 lines
The message emitted is from
ring_interrupt_active():"thunderbolt 0000:e5:00.5: interrupt for TX ring 0 is already enabled"
Right, that's in the cover letter, but I can't tell from this what the
ioread32(ring->nhi->iobase + reg)returned. It looks like this is an MMIO read of BAR 0, not a config read.Yeah. I suppose another way to approach this problem is to make something else in the call chain poll
PCI_PM_CTRL.Polling at the start of
nhi_runtime_resume()should also work. For the "normal" scenario it would just be a single read toPCI_PM_CTRL.Mika, thoughts?
We did this experiment to throw code to poll
PCI_PM_CTRLat the start ofnhi_runtime_resume()but this also fails. From that I would hypothesize the device transitioned to D0uninitialized sometime in the middle ofpci_pm_runtime_resume()before the call topm->runtime_resume(dev);Quoted 1 line
Quoted 7 lines
Quoted 4 lines
I'm starting to wonder if we are looking at the correct place ;-) This reminds me that our PCIe SV people recently reported a couple of Linux related issues which they recommended to fix, and these are on my list but I'll share them because maybe they are related?
Thanks for sharing those. We had a try with them but sorry to say no improvements to the issue at hand.
Okay, thanks for checking.
Few additional side paths here, though. This is supposed to work so that once the host router sleep bit is set the driver is supposed to allow the domain to enter sleep (e.g it should not be waken up before it is fully transitioned). That's what we do:
1. All tunneled PCIe Root/Downstream ports are in D3.
2. All tunneled USB 3.x ports are in U3.
3. No DisplayPort is tunneled.
4. Thunderbolt driver enables wakes.
5. Thunderbolt driver writes sleep ready bit of the host router.
6. Thunderbolt driver runtime suspend is complete.
7. ACPI method is called (_PS3or _PR3.OFF) that will trigger the "Sleep Event".If between 5 and 7 there is device connected, it should not "abort" the sequence. Unfortunately this is not explict in the USB4 spec but the connection manager guide has similar note. Even if the connect happens there the "Sleep Event" should happen but after that it can trigger normal wakeup which will then bring everything back.
Quoted 7 lines
Would it be possible to enable tracing around these steps so that we could see if there is hotplug notification somewhere there that is not expected? Here are instructions how to get pretty accurate trace:
https://github.com/intel/tbtools?tab=readme-ov-file#tracing
Please also take full dmesg.
Sure, here is the dmesg with tracing enabled:
https://gist.github.com/superm1/5186e0023c8a5d2ecd75c50fd2168308
Quoted 4 lines
It is entirely possible that this has nothing to do with the issue but I think it is worth checking.
Quoted 8 lines
The second thing we could try is to check the wake status bits after this has happened, like:
# tbdump -r 0 -a <ADAPTER> -vv -N 1 PORT_CS_18(where <ADAPTER> is the lane 0 adapter of the USB4 port the device was connected).
Unfortunately the adapter is in such a bad state at this time that tbdump doesn't work.
Quoted 4 lines
The third thing to try is to comment out
TB_WAKE_ON_CONNECTintb_switch_suspend(). This should result no wake even if the device is connected. This tells us that it is really the connect on USB4 port that triggered the wake.
Yup that's correct; there is no action on the hotplug with this change.
Quoted 3 lines
These could (also) explain why the host router appears to be in D3 even if it should be in D0 already.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Hi,
Quoted 24 lines · Mario Limonciello
Quoted 24 lines
Few additional side paths here, though. This is supposed to work so that once the host router sleep bit is set the driver is supposed to allow the domain to enter sleep (e.g it should not be waken up before it is fully transitioned). That's what we do:
1. All tunneled PCIe Root/Downstream ports are in D3.
2. All tunneled USB 3.x ports are in U3.
3. No DisplayPort is tunneled.
4. Thunderbolt driver enables wakes.
5. Thunderbolt driver writes sleep ready bit of the host router.
6. Thunderbolt driver runtime suspend is complete.
7. ACPI method is called (_PS3or _PR3.OFF) that will trigger the "Sleep Event".If between 5 and 7 there is device connected, it should not "abort" the sequence. Unfortunately this is not explict in the USB4 spec but the connection manager guide has similar note. Even if the connect happens there the "Sleep Event" should happen but after that it can trigger normal wakeup which will then bring everything back.
Would it be possible to enable tracing around these steps so that we could see if there is hotplug notification somewhere there that is not expected? Here are instructions how to get pretty accurate trace:
Quoted 7 lines
Quoted 3 lines
https://github.com/intel/tbtools?tab=readme-ov-file#tracing
Please also take full dmesg.
Sure, here is the dmesg with tracing enabled:
https://gist.github.com/superm1/5186e0023c8a5d2ecd75c50fd2168308
Thanks! I meant also enable control channel tracing as explained in the above linked page so we could maybe see the hotplug packet coming from the lane adapter too. Anyhow,
[ 560.789681] thunderbolt 0-2: device disconnected
[ 560.789771] thunderbolt 0000:e5:00.5: bandwidth consumption changed, re-calculating estimated bandwidth
[ 560.789775] thunderbolt 0000:e5:00.5: bandwidth re-calculation done
[ 560.789778] thunderbolt 0000:e5:00.5: looking for DP IN <-> DP OUT pairs:
[ 560.789800] thunderbolt 0000:e5:00.5: 0:6: DP IN available
[ 560.789803] thunderbolt 0000:e5:00.5: 0:6: no suitable DP OUT adapter available, not tunneling
[ 560.790484] thunderbolt 0000:e5:00.5: 0:7: DP IN available
[ 560.790487] thunderbolt 0000:e5:00.5: 0:7: no suitable DP OUT adapter available, not tunneling
...
[ 578.677640] thunderbolt 0000:e5:00.5: nhi_runtime_suspend() - enter, pdev->current_state = 0
[ 578.677648] thunderbolt 0000:e5:00.5: 0: suspending switch
[ 578.677653] thunderbolt 0000:e5:00.5: 0: enabling wakeup: 0x3f
[ 578.678248] thunderbolt 0000:e5:00.5: stopping RX ring 0
[ 578.678256] thunderbolt 0000:e5:00.5: disabling interrupt at register 0x38200 bit 3 (0x9 -> 0x1)
[ 578.678272] thunderbolt 0000:e5:00.5: stopping TX ring 0
[ 578.678277] thunderbolt 0000:e5:00.5: disabling interrupt at register 0x38200 bit 0 (0x1 -> 0x0)
[ 578.678287] thunderbolt 0000:e5:00.5: control channel stopped
...
pci_pm_runtime_resume()
pci_pm_default_resume_early(pci_dev);
pci_pm_power_up_and_verify_state(pci_dev);
pci_power_up(pci_dev);
platform_pci_set_power_state(dev, PCI_D0);
// here we should see acpi_pci_set_power_state() printing "xxx: power
// state changed by ACPI to D0" but we don't.
//
// also pdev->current_state is set to PCI_D0
pci_update_current_state(pci_dev, PCI_D0);
// this one reads it back, it should be 0..
pm->runtime_resume(dev);
nhi_runtime_resume(dev)
[ 578.773503] thunderbolt 0000:e5:00.5: nhi_runtime_resume() - enter, pdev->current_state = 3// .. but it is not. It seems to be powered off, D3cold.
[ 578.773516] thunderbolt 0000:e5:00.5: control channel starting... [ 578.773518] thunderbolt 0000:e5:00.5: starting TX ring 0 [ 578.773524] thunderbolt 0000:e5:00.5: enabling interrupt at register 0x38200 bit 0 (0xffffffff -> 0xffffffff)
// As here too.
It would be interesting to see what ACPI does here, I mean enabling dynamic debugging of acpi_device_set_power() and friends. One suspect is that when the runtime suspends happens, the power resource or _PS3() gets called to put the device into D3cold and it has some sort of Sleep() inside. This allows the OS to relese the CPU to do other things too according to ACPI spec (and Linux does this) so now when you plug in the device the GPE triggers wake and Linux starts processing that one. We see the above runtime resume but then the Sleep() in the _PS3() completes and cuts the power from the NHI while we are in the middle of resuming it already (or something along those lines).
We saw similar "context switch" happening when PCIe L2 failed, BIOS implemented the timeout using Sleep() that allowed Linux to process other things which resulted unexpected wake (not the same as here though).
So one thing to check too is how the ACPI methods get called and especially if they somehow end up messing with each other.
Quoted 6 lines
Quoted 6 lines
It is entirely possible that this has nothing to do with the issue but I think it is worth checking.
The second thing we could try is to check the wake status bits after this has happened, like:
Quoted 8 lines
Quoted 5 lines
# tbdump -r 0 -a <ADAPTER> -vv -N 1 PORT_CS_18(where <ADAPTER> is the lane 0 adapter of the USB4 port the device was connected).
Unfortunately the adapter is in such a bad state at this time that tbdump doesn't work.
Oh, indeed it is.
Quoted 6 lines
Quoted 4 lines
The third thing to try is to comment out
TB_WAKE_ON_CONNECTintb_switch_suspend(). This should result no wake even if the device is connected. This tells us that it is really the connect on USB4 port that triggered the wake.Yup that's correct; there is no action on the hotplug with this change.
Okay thanks for checking.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 74 lines · Mika Westerberg
Hi,
Quoted 24 lines · Mario Limonciello
Quoted 24 lines
Few additional side paths here, though. This is supposed to work so that once the host router sleep bit is set the driver is supposed to allow the domain to enter sleep (e.g it should not be waken up before it is fully transitioned). That's what we do:
1. All tunneled PCIe Root/Downstream ports are in D3.
2. All tunneled USB 3.x ports are in U3.
3. No DisplayPort is tunneled.
4. Thunderbolt driver enables wakes.
5. Thunderbolt driver writes sleep ready bit of the host router.
6. Thunderbolt driver runtime suspend is complete.
7. ACPI method is called (_PS3or _PR3.OFF) that will trigger the "Sleep Event".If between 5 and 7 there is device connected, it should not "abort" the sequence. Unfortunately this is not explict in the USB4 spec but the connection manager guide has similar note. Even if the connect happens there the "Sleep Event" should happen but after that it can trigger normal wakeup which will then bring everything back.
Would it be possible to enable tracing around these steps so that we could see if there is hotplug notification somewhere there that is not expected? Here are instructions how to get pretty accurate trace:
Quoted 7 lines
Quoted 3 lines
https://github.com/intel/tbtools?tab=readme-ov-file#tracing
Please also take full dmesg.
Sure, here is the dmesg with tracing enabled:
https://gist.github.com/superm1/5186e0023c8a5d2ecd75c50fd2168308
Thanks! I meant also enable control channel tracing as explained in the above linked page so we could maybe see the hotplug packet coming from the lane adapter too. Anyhow,
[ 560.789681] thunderbolt 0-2: device disconnected [ 560.789771] thunderbolt 0000:e5:00.5: bandwidth consumption changed, re-calculating estimated bandwidth [ 560.789775] thunderbolt 0000:e5:00.5: bandwidth re-calculation done [ 560.789778] thunderbolt 0000:e5:00.5: looking for DP IN <-> DP OUT pairs: [ 560.789800] thunderbolt 0000:e5:00.5: 0:6: DP IN available [ 560.789803] thunderbolt 0000:e5:00.5: 0:6: no suitable DP OUT adapter available, not tunneling [ 560.790484] thunderbolt 0000:e5:00.5: 0:7: DP IN available [ 560.790487] thunderbolt 0000:e5:00.5: 0:7: no suitable DP OUT adapter available, not tunneling ... [ 578.677640] thunderbolt 0000:e5:00.5: nhi_runtime_suspend() - enter, pdev->current_state = 0 [ 578.677648] thunderbolt 0000:e5:00.5: 0: suspending switch [ 578.677653] thunderbolt 0000:e5:00.5: 0: enabling wakeup: 0x3f [ 578.678248] thunderbolt 0000:e5:00.5: stopping RX ring 0 [ 578.678256] thunderbolt 0000:e5:00.5: disabling interrupt at register 0x38200 bit 3 (0x9 -> 0x1) [ 578.678272] thunderbolt 0000:e5:00.5: stopping TX ring 0 [ 578.678277] thunderbolt 0000:e5:00.5: disabling interrupt at register 0x38200 bit 0 (0x1 -> 0x0) [ 578.678287] thunderbolt 0000:e5:00.5: control channel stopped ... pci_pm_runtime_resume() pci_pm_default_resume_early(pci_dev); pci_pm_power_up_and_verify_state(pci_dev); pci_power_up(pci_dev); platform_pci_set_power_state(dev, PCI_D0); // here we should see acpi_pci_set_power_state() printing "xxx: power // state changed by ACPI to D0" but we don't. // // also pdev->current_state is set to PCI_D0 pci_update_current_state(pci_dev, PCI_D0); // this one reads it back, it should be 0.. pm->runtime_resume(dev); nhi_runtime_resume(dev) [ 578.773503] thunderbolt 0000:e5:00.5: nhi_runtime_resume() - enter, pdev->current_state = 3// .. but it is not. It seems to be powered off, D3cold.
Quoted 8 lines
[ 578.773516] thunderbolt 0000:e5:00.5: control channel starting... [ 578.773518] thunderbolt 0000:e5:00.5: starting TX ring 0 [ 578.773524] thunderbolt 0000:e5:00.5: enabling interrupt at register 0x38200 bit 0 (0xffffffff -> 0xffffffff)// As here too.
It would be interesting to see what ACPI does here, I mean enabling dynamic debugging of
acpi_device_set_power()and friends.
Here is a log with dyndbg turned up.
https://gist.github.com/superm1/2f7ca6123431365d11e9bc3cc9329c14
You can see firmware node \_SB_.PCI0.BUSC.NHI0 is physical device 0000:e5:00.5.
Quoted 10 lines
One suspect is
that when the runtime suspends happens, the power resource or_PS3()gets called to put the device into D3cold and it has some sort ofSleep()inside. This allows the OS to relese the CPU to do other things too according to ACPI spec (and Linux does this) so now when you plug in the device the GPE triggers wake and Linux starts processing that one. We see the above runtime resume but then theSleep()in the_PS3()completes and cuts the power from the NHI while we are in the middle of resuming it already (or something along those lines).
Quoted 7 lines
We saw similar "context switch" happening when PCIe L2 failed, BIOS implemented the timeout using
Sleep()that allowed Linux to process other things which resulted unexpected wake (not the same as here though).So one thing to check too is how the ACPI methods get called and especially if they somehow end up messing with each other.
At least to me it looks pretty straightforward that each D0 sequence is going through and nothing looked out of order:
acpi_pci_set_power_state()
->acpi_device_set_power()
->->acpi_dev_pm_explicit_set()
There is a Sleep() call in M232() which is a SMI used in both _PS0 and _PS3, but as far as I can tell it's not actually called as the case always has zero as an argument.
Here's some snippets of ASL from the NHI0 device to see.
https://gist.github.com/superm1/32ef1f822a6220a41b19574024717f79
I feel your theory is right about it being an aborted D3cold request, but I don't believe it's from concurrency issue of _PS3. I feel there isn't any guard rails either in Linux or the AML for ensuring that the transition actually finished.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Hi,
Quoted 81 lines · Mario Limonciello
Quoted 80 lines · Mika Westerberg
Hi,
Quoted 24 lines · Mario Limonciello
Quoted 24 lines
Few additional side paths here, though. This is supposed to work so that once the host router sleep bit is set the driver is supposed to allow the domain to enter sleep (e.g it should not be waken up before it is fully transitioned). That's what we do:
1. All tunneled PCIe Root/Downstream ports are in D3.
2. All tunneled USB 3.x ports are in U3.
3. No DisplayPort is tunneled.
4. Thunderbolt driver enables wakes.
5. Thunderbolt driver writes sleep ready bit of the host router.
6. Thunderbolt driver runtime suspend is complete.
7. ACPI method is called (_PS3or _PR3.OFF) that will trigger the "Sleep Event".If between 5 and 7 there is device connected, it should not "abort" the sequence. Unfortunately this is not explict in the USB4 spec but the connection manager guide has similar note. Even if the connect happens there the "Sleep Event" should happen but after that it can trigger normal wakeup which will then bring everything back.
Would it be possible to enable tracing around these steps so that we could see if there is hotplug notification somewhere there that is not expected? Here are instructions how to get pretty accurate trace:
Quoted 7 lines
Quoted 3 lines
https://github.com/intel/tbtools?tab=readme-ov-file#tracing
Please also take full dmesg.
Sure, here is the dmesg with tracing enabled:
https://gist.github.com/superm1/5186e0023c8a5d2ecd75c50fd2168308
Thanks! I meant also enable control channel tracing as explained in the above linked page so we could maybe see the hotplug packet coming from the lane adapter too. Anyhow,
[ 560.789681] thunderbolt 0-2: device disconnected [ 560.789771] thunderbolt 0000:e5:00.5: bandwidth consumption changed, re-calculating estimated bandwidth [ 560.789775] thunderbolt 0000:e5:00.5: bandwidth re-calculation done [ 560.789778] thunderbolt 0000:e5:00.5: looking for DP IN <-> DP OUT pairs: [ 560.789800] thunderbolt 0000:e5:00.5: 0:6: DP IN available [ 560.789803] thunderbolt 0000:e5:00.5: 0:6: no suitable DP OUT adapter available, not tunneling [ 560.790484] thunderbolt 0000:e5:00.5: 0:7: DP IN available [ 560.790487] thunderbolt 0000:e5:00.5: 0:7: no suitable DP OUT adapter available, not tunneling ... [ 578.677640] thunderbolt 0000:e5:00.5: nhi_runtime_suspend() - enter, pdev->current_state = 0 [ 578.677648] thunderbolt 0000:e5:00.5: 0: suspending switch [ 578.677653] thunderbolt 0000:e5:00.5: 0: enabling wakeup: 0x3f [ 578.678248] thunderbolt 0000:e5:00.5: stopping RX ring 0 [ 578.678256] thunderbolt 0000:e5:00.5: disabling interrupt at register 0x38200 bit 3 (0x9 -> 0x1) [ 578.678272] thunderbolt 0000:e5:00.5: stopping TX ring 0 [ 578.678277] thunderbolt 0000:e5:00.5: disabling interrupt at register 0x38200 bit 0 (0x1 -> 0x0) [ 578.678287] thunderbolt 0000:e5:00.5: control channel stopped ... pci_pm_runtime_resume() pci_pm_default_resume_early(pci_dev); pci_pm_power_up_and_verify_state(pci_dev); pci_power_up(pci_dev); platform_pci_set_power_state(dev, PCI_D0); // here we should see acpi_pci_set_power_state() printing "xxx: power // state changed by ACPI to D0" but we don't. // // also pdev->current_state is set to PCI_D0 pci_update_current_state(pci_dev, PCI_D0); // this one reads it back, it should be 0.. pm->runtime_resume(dev); nhi_runtime_resume(dev) [ 578.773503] thunderbolt 0000:e5:00.5: nhi_runtime_resume() - enter, pdev->current_state = 3// .. but it is not. It seems to be powered off, D3cold.
[ 578.773516] thunderbolt 0000:e5:00.5: control channel starting... [ 578.773518] thunderbolt 0000:e5:00.5: starting TX ring 0 [ 578.773524] thunderbolt 0000:e5:00.5: enabling interrupt at register 0x38200 bit 0 (0xffffffff -> 0xffffffff)// As here too.
Quoted 8 lines
Quoted 2 lines
It would be interesting to see what ACPI does here, I mean enabling dynamic debugging of
acpi_device_set_power()and friends.Here is a log with dyndbg turned up.
https://gist.github.com/superm1/2f7ca6123431365d11e9bc3cc9329c14You can see firmware node \_SB_.PCI0.BUSC.NHI0 is physical device 0000:e5:00.5.
Thanks!
Quoted 30 lines
Quoted 10 lines
One suspect is
that when the runtime suspends happens, the power resource or_PS3()gets called to put the device into D3cold and it has some sort ofSleep()inside. This allows the OS to relese the CPU to do other things too according to ACPI spec (and Linux does this) so now when you plug in the device the GPE triggers wake and Linux starts processing that one. We see the above runtime resume but then theSleep()in the_PS3()completes and cuts the power from the NHI while we are in the middle of resuming it already (or something along those lines).Quoted 7 lines
We saw similar "context switch" happening when PCIe L2 failed, BIOS implemented the timeout using
Sleep()that allowed Linux to process other things which resulted unexpected wake (not the same as here though).So one thing to check too is how the ACPI methods get called and especially if they somehow end up messing with each other.
At least to me it looks pretty straightforward that each D0 sequence is going through and nothing looked out of order:
acpi_pci_set_power_state()
->acpi_device_set_power()
->->acpi_dev_pm_explicit_set()There is a
Sleep()call inM232()which is a SMI used in both_PS0and_PS3, but as far as I can tell it's not actually called as the case always has zero as an argument.
Quoted 7 lines
Here's some snippets of ASL from the NHI0 device to see.
https://gist.github.com/superm1/32ef1f822a6220a41b19574024717f79I feel your theory is right about it being an aborted D3cold request, but I don't believe it's from concurrency issue of
_PS3. I feel there isn't any guard rails either in Linux or the AML for ensuring that
the transition actually finished.
Yeah, I agree now. It does not look like the methods are messing each other here. We don't see the GPE handler being run but I don't think it matters here. For some reason the device just is not yet ready when it is supposed to be in D0.
Sorry for wasting your time with these suspects.
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Hi again,
Quoted 6 lines · Mika Westerberg
Yeah, I agree now. It does not look like the methods are messing each other here. We don't see the GPE handler being run but I don't think it matters here. For some reason the device just is not yet ready when it is supposed to be in D0.
Sorry for wasting your time with these suspects.
One more suggestion though ;-) I realized that my hack patch to disable I/O and MMIO did not actually do that because it looks like we don't clear those bits ever. I wonder if you could still check if the below changes anything? At least it should now "disable" the device to follow the spec.
drivers/pci/pci-driver.c +1 -0
@@ -1332,6 +1332,7 @@ static int pci_pm_runtime_suspend(struct device *dev)if (!pci_dev->state_saved) {pci_save_state (pci_dev); +pci_pm_default_suspend (pci_dev);pci_finish_runtime_suspend (pci_dev); }
drivers/pci/pci.c +7 -0
@@ -2218,6 +2218,13 @@ static void do_pci_disable_device(struct pci_dev *dev) pci_command &= ~PCI_COMMAND_MASTER ;pci_write_config_word (dev,PCI_COMMAND , pci_command); } +/* +* PCI PM 1.2 sec 8.2.2 says that when a function is put into D3 +* the OS needs to disable I/O and MMIO space in addition to bus +* mastering so do that here. +*/ + pci_command &= ~(PCI_COMMAND_IO |PCI_COMMAND_MEMORY ); +pci_write_config_word (dev,PCI_COMMAND , pci_command);pcibios_disable_device (dev); }
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Quoted 9 lines · Mika Westerberg
Hi again,
Quoted 6 lines · Mika Westerberg
Yeah, I agree now. It does not look like the methods are messing each other here. We don't see the GPE handler being run but I don't think it matters here. For some reason the device just is not yet ready when it is supposed to be in D0.
Sorry for wasting your time with these suspects.
Don't worry about it. It validates that we're coming to the right conclusions about where the problem is.
Quoted 6 lines
One more suggestion though ;-) I realized that my hack patch to disable I/O and MMIO did not actually do that because it looks like we don't clear those bits ever. I wonder if you could still check if the below changes anything? At least it should now "disable" the device to follow the spec.
This actually causes the system to fail to boot. I guess some deadlock from other callers to pci_disable_device().
We also double checked putting the PCI_COMMAND writes just into the runtime suspend call backs instead (to narrow down if that is part of the issue here). Putting it there fixed the boot hang, but no change to the actual issue behavior.
Bjorn,
Considering this finding, are you more amenable to the polling approach?
Quoted 31 lines
drivers/pci/pci-driver.c +1
-0@@ -1332,6 +1332,7 @@ static int pci_pm_runtime_suspend(struct device *dev)if (!pci_dev->state_saved) {pci_save_state (pci_dev); +pci_pm_default_suspend (pci_dev);pci_finish_runtime_suspend (pci_dev); }drivers/pci/pci.c +7
-0@@ -2218,6 +2218,13 @@ static void do_pci_disable_device(struct pci_dev *dev) pci_command &= ~PCI_COMMAND_MASTER ;pci_write_config_word (dev,PCI_COMMAND , pci_command); } +/* +* PCI PM 1.2 sec 8.2.2 says that when a function is put into D3 +* the OS needs to disable I/O and MMIO space in addition to bus +* mastering so do that here. +*/ + pci_command &= ~(PCI_COMMAND_IO |PCI_COMMAND_MEMORY ); +pci_write_config_word (dev,PCI_COMMAND , pci_command);pcibios_disable_device (dev); }
Re: [PATCH v5 2/5] PCI: Check PCI_PM_CTRL instead of PCI_COMMAND in pci_dev_wait()
Hi,
Quoted 6 lines · Mario Limonciello
Quoted 5 lines
One more suggestion though ;-) I realized that my hack patch to disable I/O and MMIO did not actually do that because it looks like we don't clear those bits ever. I wonder if you could still check if the below changes anything? At least it should now "disable" the device to follow the spec.
Quoted 7 lines
This actually causes the system to fail to boot. I guess some deadlock from other callers to
pci_disable_device().We also double checked putting the
PCI_COMMANDwrites just into the runtime suspend call backs instead (to narrow down if that is part of the issue here). Putting it there fixed the boot hang, but no change to the actual issue behavior.
Okay, thanks again for checking!
PATCH v5 3/5 PCI: Verify functions currently in D3cold have entered D0
In reply to Mario LimoncielloFrom: Mario Limonciello <[email protected]>
It is reported that USB4 routers and downstream devices may behave incorrectly if a dock cable is plugged in at approximately the time that the autosuspend_delay is configured. In this situation the device has attempted to enter D3cold, but didn't finish D3cold entry when the PCI core tried to transition it back to D0.
Empirically measuring this situation an "aborted" D3cold exit takes ~60ms and a "normal" D3cold exit takes ~6ms.
The PCI-PM 1.2 spec specifies that the restore time for functions in D3cold is either 'Full context restore or boot latency'.
As PCIe r6.0 sec 5.8 specifies that the device will have gone through a conventional reset, it may take some time for the device to be ready.
Wait up to 1 sec as specified in PCIe r6.0 sec 6.6.1 for a device in D3cold to return to D0.
---v4->v5:
* Add missing string for new pci_reset_type
--- drivers/pci/pci.c | 12 ++++++++++++ drivers/pci/pci.h | 1 + 2 files changed, 13 insertions(+)
drivers/pci/pci.c +12 -0
@@ -188,6 +188,7 @@ static const char * const pci_reset_types[] = { [PCI_DEV_WAIT_BUS_RESET] = "bus reset", [PCI_DEV_WAIT_RESUME] = "resume", [PCI_DEV_WAIT_DPC] = "DPC", + [PCI_DEV_WAIT_D3COLD_D0 ] ="D3cold->D0" , };static_assert (ARRAY_SIZE (pci_reset_types) ==PCI_DEV_WAIT_MAX );
@@ -1426,6 +1427,17 @@ int pci_power_up(struct pci_dev *dev)else if (state ==PCI_D2 )udelay (PCI_PM_D2_DELAY ); +/* +* D3cold -> D0 will have gone through a conventional reset and may need +* time to be ready. +*/ +if (dev->current_state == PCI_D3cold) { +int ret; + + ret =pci_dev_wait (dev,PCI_DEV_WAIT_D3COLD_D0 ,PCI_RESET_WAIT ); +if (ret) +return ret; + } end: dev->current_state =PCI_D0 ;if (need_restore)
drivers/pci/pci.h +1 -0
@@ -11,6 +11,7 @@ enum pci_reset_type {PCI_DEV_WAIT_BUS_RESET ,PCI_DEV_WAIT_RESUME ,PCI_DEV_WAIT_DPC , +PCI_DEV_WAIT_D3COLD_D0 , PCI_DEV_WAIT_MAX, };
Signature · 1 line
2.43.0
PATCH v5 4/5 PCI: Allow Ryzen XHCI controllers into D3cold and drop delays
In reply to Mario LimoncielloFrom: Mario Limonciello <[email protected]>
As the PCI core now has a delay after D3cold exit, the Ryzen XHCI controllers that were quirked to not use D3cold and to add a delay on D3hot no longer need these quirks.
Drop both the PCI and XHCI sets of quirks.
--- drivers/pci/quirks.c | 17 ----------------- drivers/usb/host/xhci-pci.c | 11 ----------- 2 files changed, 28 deletions(-)
drivers/pci/quirks.c +0 -17
@@ -2059,23 +2059,6 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,PCI_CLASS_MULTIMEDIA_HD_AUDIO ,8 , quirk_nvidia_hda_pm); -/* -* Ryzen5/7 XHCI controllers fail upon resume from runtime suspend or s2idle. -* https://bugzilla.kernel.org/show_bug.cgi?id=205587 -* -* The kernel attempts to transition these devices to D3cold, but that seems -* to be ineffective on the platforms in question; the PCI device appears to -* remain on in D3hot state. The D3hot-to-D0 transition then requires an -* extended delay in order to succeed. -*/ -static void quirk_ryzen_xhci_d3hot (struct pci_dev *dev) -{ -quirk_d3hot_delay (dev,20 ); -} -DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AMD ,0x15e0 , quirk_ryzen_xhci_d3hot); -DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AMD ,0x15e1 , quirk_ryzen_xhci_d3hot); -DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_AMD ,0x1639 , quirk_ryzen_xhci_d3hot); -#ifdef CONFIG_X86_IO_APIC static int dmi_disable_ioapicreroute (const struct dmi_system_id *d) {
drivers/usb/host/xhci-pci.c +0 -11
@@ -316,10 +316,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1))) xhci->quirks |= XHCI_U2_DISABLE_WAKE; -if (pdev->vendor ==PCI_VENDOR_ID_AMD && - pdev->device ==PCI_DEVICE_ID_AMD_RENOIR_XHCI ) - xhci->quirks |=XHCI_BROKEN_D3COLD_S2I ; -if (pdev->vendor ==PCI_VENDOR_ID_INTEL ) { xhci->quirks |=XHCI_LPM_SUPPORT ; xhci->quirks |=XHCI_INTEL_HOST ;
@@ -752,13 +748,6 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)if (xhci->quirks &XHCI_COMP_MODE_QUIRK )pci_d3cold_disable (pdev); -#ifdef CONFIG_SUSPEND -/* d3cold is broken, but only when s2idle is used */ -if (pm_suspend_target_state ==PM_SUSPEND_TO_IDLE && - xhci->quirks & (XHCI_BROKEN_D3COLD_S2I )) -pci_d3cold_disable (pdev); -#endif -if (xhci->quirks &XHCI_PME_STUCK_QUIRK )xhci_pme_quirk (hcd);
Signature · 1 line
2.43.0
PATCH v5 5/5 PCI: Drop Radeon quirk for Macbook Pro 8.2
In reply to Mario LimoncielloFrom: Mario Limonciello <[email protected]>
commit 5938628c51a7 ("drm/radeon: make MacBook Pro d3_delay quirk more generic") introduced a generic quirk for Macbook Pro 8.2s that contain Radeon graphics to ensure that enough time had past when the device was powered on.
As the PCI core now verifies the device is in D0 during power on this extra artificial delay is no longer necessary.
--- drivers/pci/quirks.c | 8 -------- 1 file changed, 8 deletions(-)
drivers/pci/quirks.c +0 -8
@@ -2038,14 +2038,6 @@ static void quirk_d3hot_delay(struct pci_dev *dev, unsigned int delay) dev->d3hot_delay); } -static void quirk_radeon_pm (struct pci_dev *dev) -{ -if (dev->subsystem_vendor ==PCI_VENDOR_ID_APPLE && - dev->subsystem_device ==0x00e2 ) -quirk_d3hot_delay (dev,20 ); -} -DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_ATI ,0x6741 , quirk_radeon_pm); -/* * NVIDIA Ampere-based HDA controllers can wedge the whole device if a bus * reset is performed too soon after transition to D0, extend d3hot_delay
Signature · 1 line
2.43.0
Quoted 35 lines · Mario Limonciello
From: Mario Limonciello <[email protected]>
Gary has reported that when a dock is plugged into a system at the same time the autosuspend delay has tripped that the USB4 stack malfunctions.
Messages show up like this:
``` thunderbolt 0000:e5:00.6: ring_interrupt_active: interrupt for TX ring 0 is already enabled ```Furthermore the USB4 router is non-functional at this point.
Those messages happen because the device is still in D3cold at the time that the PCI core handed control back to the USB4 connection manager (thunderbolt).
The issue is that it takes time for a device to enter D3cold and do a conventional reset, and then more time for it to exit D3cold.
This appears not to be a new problem; previously there were very similar reports from Ryzen XHCI controllers. Quirks were added for those. Furthermore; adding extra logging it's apparent that other PCI devices in the system can take more than 10ms to recover from D3cold as well.
This series add a wait into
pci_power_up()specifically for D3cold exit and then drops the quirks that were previously used for the Ryzen XHCI controllers.Mario Limonciello (5):
PCI: Use an enum for reset type inpci_dev_wait()
PCI: CheckPCI_PM_CTRLinstead ofPCI_COMMANDinpci_dev_wait()
PCI: Verify functions currently in D3cold have entered D0
PCI: Allow Ryzen XHCI controllers into D3cold and drop delays
PCI: Drop Radeon quirk for Macbook Pro 8.2
Quoted 8 lines
drivers/pci/pci-driver.c | 2 +- drivers/pci/pci.c | 70 +++++++++++++++++++++++++++---------- drivers/pci/pci.h | 13 ++++++- drivers/pci/pcie/dpc.c | 2 +- drivers/pci/quirks.c | 25 ------------- drivers/usb/host/xhci-pci.c | 11 ------ 6 files changed, 66 insertions(+), 57 deletions(-)
Bjorn,
This series has stalled a while.
Mika and I went back and forth and I think are generally in agreement so I think it's waiting on your feedback.
Can you take another look?
The alternative is to add some more piles of quirks, but I'm hoping that we can go this direction and drop a bunch of the old ones instead.
LMK if you want me to rebase it on 6.13-rc1 and resend a v6.
Quoted 51 lines · Mario Limonciello
Quoted 35 lines · Mario Limonciello
From: Mario Limonciello <[email protected]>
Gary has reported that when a dock is plugged into a system at the same time the autosuspend delay has tripped that the USB4 stack malfunctions.
Messages show up like this:
``` thunderbolt 0000:e5:00.6: ring_interrupt_active: interrupt for TX ring 0 is already enabled ```Furthermore the USB4 router is non-functional at this point.
Those messages happen because the device is still in D3cold at the time that the PCI core handed control back to the USB4 connection manager (thunderbolt).
The issue is that it takes time for a device to enter D3cold and do a conventional reset, and then more time for it to exit D3cold.
This appears not to be a new problem; previously there were very similar reports from Ryzen XHCI controllers. Quirks were added for those. Furthermore; adding extra logging it's apparent that other PCI devices in the system can take more than 10ms to recover from D3cold as well.
This series add a wait into
pci_power_up()specifically for D3cold exit and then drops the quirks that were previously used for the Ryzen XHCI controllers.Mario Limonciello (5):
PCI: Use an enum for reset type inpci_dev_wait()
PCI: CheckPCI_PM_CTRLinstead ofPCI_COMMANDinpci_dev_wait()
PCI: Verify functions currently in D3cold have entered D0
PCI: Allow Ryzen XHCI controllers into D3cold and drop delays
PCI: Drop Radeon quirk for Macbook Pro 8.2Quoted 7 lines
drivers/pci/pci-driver.c | 2 +- drivers/pci/pci.c | 70 +++++++++++++++++++++++++++---------- drivers/pci/pci.h | 13 ++++++- drivers/pci/pcie/dpc.c | 2 +- drivers/pci/quirks.c | 25 ------------- drivers/usb/host/xhci-pci.c | 11 ------ 6 files changed, 66 insertions(+), 57 deletions(-)Bjorn,
This series has stalled a while.
Mika and I went back and forth and I think are generally in agreement so I think it's waiting on your feedback.
Quoted 6 lines
Can you take another look?
The alternative is to add some more piles of quirks, but I'm hoping that we can go this direction and drop a bunch of the old ones instead.
LMK if you want me to rebase it on 6.13-rc1 and resend a v6.
I'm still stuck on patch 2/5 because I'm not aware of any spec language about polling PCI_PM_CTRL to wait for a power state transition, so it seems really ad hoc.
If you do rebase to v6.13-rc1, in the 2/5 commit log, s/evices/devices/.
I guess that whole patch and commit log needs updating since the RRS code was added to pci_dev_wait() in the interim, so the "device that has gone through a reset may return a value in PCI_COMMAND but that doesn't mean it's finished transitioning to D0" doesn't directly apply anymore.
Bjorn
Quoted 54 lines · Bjorn Helgaas
Quoted 53 lines · Mario Limonciello
Quoted 35 lines · Mario Limonciello
From: Mario Limonciello <[email protected]>
Gary has reported that when a dock is plugged into a system at the same time the autosuspend delay has tripped that the USB4 stack malfunctions.
Messages show up like this:
``` thunderbolt 0000:e5:00.6: ring_interrupt_active: interrupt for TX ring 0 is already enabled ```Furthermore the USB4 router is non-functional at this point.
Those messages happen because the device is still in D3cold at the time that the PCI core handed control back to the USB4 connection manager (thunderbolt).
The issue is that it takes time for a device to enter D3cold and do a conventional reset, and then more time for it to exit D3cold.
This appears not to be a new problem; previously there were very similar reports from Ryzen XHCI controllers. Quirks were added for those. Furthermore; adding extra logging it's apparent that other PCI devices in the system can take more than 10ms to recover from D3cold as well.
This series add a wait into
pci_power_up()specifically for D3cold exit and then drops the quirks that were previously used for the Ryzen XHCI controllers.Mario Limonciello (5):
PCI: Use an enum for reset type inpci_dev_wait()
PCI: CheckPCI_PM_CTRLinstead ofPCI_COMMANDinpci_dev_wait()
PCI: Verify functions currently in D3cold have entered D0
PCI: Allow Ryzen XHCI controllers into D3cold and drop delays
PCI: Drop Radeon quirk for Macbook Pro 8.2Quoted 7 lines
drivers/pci/pci-driver.c | 2 +- drivers/pci/pci.c | 70 +++++++++++++++++++++++++++---------- drivers/pci/pci.h | 13 ++++++- drivers/pci/pcie/dpc.c | 2 +- drivers/pci/quirks.c | 25 ------------- drivers/usb/host/xhci-pci.c | 11 ------ 6 files changed, 66 insertions(+), 57 deletions(-)Bjorn,
This series has stalled a while.
Mika and I went back and forth and I think are generally in agreement so I think it's waiting on your feedback.
Can you take another look?
Quoted 8 lines
Quoted 4 lines
The alternative is to add some more piles of quirks, but I'm hoping that we can go this direction and drop a bunch of the old ones instead.
LMK if you want me to rebase it on 6.13-rc1 and resend a v6.
I'm still stuck on patch 2/5 because I'm not aware of any spec language about polling
PCI_PM_CTRLto wait for a power state transition, so it seems really ad hoc.
I'm not really sure how to overcome this. If I rebase everything I'll give specs another read through in case I missed anything, but I suspect you know these specs better than anyoe on this list.
Is it worth raising this to PCI-SIG to discuss?
Did you perhaps already do that?
Quoted 11 lines
If you do rebase to v6.13-rc1, in the 2/5 commit log, s/evices/devices/.
I guess that whole patch and commit log needs updating since the RRS code was added to
pci_dev_wait()in the interim, so the "device that has gone through a reset may return a value inPCI_COMMANDbut that doesn't mean it's finished transitioning to D0" doesn't directly apply anymore.Bjorn
Quoted 64 lines · Mario Limonciello
Quoted 54 lines · Bjorn Helgaas
Quoted 53 lines · Mario Limonciello
Quoted 35 lines · Mario Limonciello
From: Mario Limonciello <[email protected]>
Gary has reported that when a dock is plugged into a system at the same time the autosuspend delay has tripped that the USB4 stack malfunctions.
Messages show up like this:
``` thunderbolt 0000:e5:00.6: ring_interrupt_active: interrupt for TX ring 0 is already enabled ```Furthermore the USB4 router is non-functional at this point.
Those messages happen because the device is still in D3cold at the time that the PCI core handed control back to the USB4 connection manager (thunderbolt).
The issue is that it takes time for a device to enter D3cold and do a conventional reset, and then more time for it to exit D3cold.
This appears not to be a new problem; previously there were very similar reports from Ryzen XHCI controllers. Quirks were added for those. Furthermore; adding extra logging it's apparent that other PCI devices in the system can take more than 10ms to recover from D3cold as well.
This series add a wait into
pci_power_up()specifically for D3cold exit and then drops the quirks that were previously used for the Ryzen XHCI controllers.Mario Limonciello (5):
PCI: Use an enum for reset type inpci_dev_wait()
PCI: CheckPCI_PM_CTRLinstead ofPCI_COMMANDinpci_dev_wait()
PCI: Verify functions currently in D3cold have entered D0
PCI: Allow Ryzen XHCI controllers into D3cold and drop delays
PCI: Drop Radeon quirk for Macbook Pro 8.2Quoted 7 lines
drivers/pci/pci-driver.c | 2 +- drivers/pci/pci.c | 70 +++++++++++++++++++++++++++---------- drivers/pci/pci.h | 13 ++++++- drivers/pci/pcie/dpc.c | 2 +- drivers/pci/quirks.c | 25 ------------- drivers/usb/host/xhci-pci.c | 11 ------ 6 files changed, 66 insertions(+), 57 deletions(-)Bjorn,
This series has stalled a while.
Mika and I went back and forth and I think are generally in agreement so I think it's waiting on your feedback.
Can you take another look?
Quoted 8 lines
Quoted 4 lines
The alternative is to add some more piles of quirks, but I'm hoping that we can go this direction and drop a bunch of the old ones instead.
LMK if you want me to rebase it on 6.13-rc1 and resend a v6.
I'm still stuck on patch 2/5 because I'm not aware of any spec language about polling
PCI_PM_CTRLto wait for a power state transition, so it seems really ad hoc.
Quoted 6 lines
I'm not really sure how to overcome this. If I rebase everything I'll give specs another read through in case I missed anything, but I suspect you know these specs better than anyoe on this list.
Is it worth raising this to PCI-SIG to discuss?
Did you perhaps already do that?
I haven't, but it seems like that might be appropriate. Can we formulate a question in terms of PCIe concepts?
I guess some of the pieces are:
- ACPI puts device in D3cold
- ACPI restores device to D0
- Device is not yet in D0 when ACPI method has completed
- OS read from device causes UR or RRS, so OS reads ~0
It's much more complicated if ACPI is involved because then we have question of whether the ACPI method should have waited.
Patch 3/5 mentions "Full context restore or boot latency" language in PCI PM r1.2, but I couldn't find section. I don't know how a generic spec could constrain D0->D3cold or D3cold->D0 transition time because that depends on platform-specific power management hardware.
Bjorn