Re: [PATCH] PCI: also apply D3 delay when leaving D3cold

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Monday, October 14, 2019 8:18:06 AM CEST Daniel Drake wrote:
> On Fri, Oct 11, 2019 at 6:14 PM Rafael J. Wysocki <rjw@xxxxxxxxxxxxx> wrote:
> > So I think that we can use pci_restore_standard_config() in the system resume
> > patch too, which should address the issue as well.
> >
> > Basically, there is no reason for the PM-runtime and system-wide resume code
> > paths to be different in that respect.
> 
> Your patch works without modification when combined with
> https://patchwork.kernel.org/patch/11187815/

Great, thanks for the confirmation!

> Can you push this directly or would it be helpful if I update the
> commit message and submit it by email?

It would be prudent if I submitted it properly with a changelog etc.

However, I noticed that it might cause the ACPI power state to get out of sync
during resume from suspend-to-RAM in some (arguably theoretical only) cases.

Specifically, that may happen if the kernel puts a device into D3hot on
suspend and the platform firmware powers it up during system wakeup, because in
that case the pci_update_current_state() in pci_restore_standard_config() will
notice D0 and the pci_set_power_state() in there will not be called, so the
ACPI layer will still hold on to the stale D3hot power state value.

While I still think that both the system resume and runtime resume code paths
should be as similar as reasonably possible, the above needs to be taken into
account IMO, so it is better to retain pci_pm_default_resume_early(), but make
it do a conditional "ACPI power state refresh" and then call
pci_restore_standard_config().

So something like the patch below (can you please test it too?).

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

Index: linux-pm/drivers/pci/pci-driver.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-driver.c
+++ linux-pm/drivers/pci/pci-driver.c
@@ -523,9 +523,10 @@ static int pci_restore_standard_config(s
 
 static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
 {
-	pci_power_up(pci_dev);
-	pci_restore_state(pci_dev);
-	pci_pme_restore(pci_dev);
+	if (pm_resume_via_firmware())
+		pci_refresh_power_state(pci_dev);
+
+	pci_restore_standard_config(pci_dev);
 }
 
 /*
@@ -713,6 +714,7 @@ static void pci_pm_complete(struct devic
 		pci_power_t pre_sleep_state = pci_dev->current_state;
 
 		pci_refresh_power_state(pci_dev);
+		pci_update_current_state(pci_dev, pci_dev->current_state);
 		/*
 		 * On platforms with ACPI this check may also trigger for
 		 * devices sharing power resources if one of those power
Index: linux-pm/drivers/pci/pci.c
===================================================================
--- linux-pm.orig/drivers/pci/pci.c
+++ linux-pm/drivers/pci/pci.c
@@ -954,21 +954,6 @@ void pci_refresh_power_state(struct pci_
 {
 	if (platform_pci_power_manageable(dev))
 		platform_pci_refresh_power_state(dev);
-
-	pci_update_current_state(dev, dev->current_state);
-}
-
-/**
- * pci_power_up - Put the given device into D0 forcibly
- * @dev: PCI device to power up
- */
-void pci_power_up(struct pci_dev *dev)
-{
-	if (platform_pci_power_manageable(dev))
-		platform_pci_set_power_state(dev, PCI_D0);
-
-	pci_raw_set_power_state(dev, PCI_D0);
-	pci_update_current_state(dev, PCI_D0);
 }
 
 /**
Index: linux-pm/drivers/pci/pci.h
===================================================================
--- linux-pm.orig/drivers/pci/pci.h
+++ linux-pm/drivers/pci/pci.h
@@ -85,7 +85,6 @@ struct pci_platform_pm_ops {
 int pci_set_platform_pm(const struct pci_platform_pm_ops *ops);
 void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
 void pci_refresh_power_state(struct pci_dev *dev);
-void pci_power_up(struct pci_dev *dev);
 void pci_disable_enabled_device(struct pci_dev *dev);
 int pci_finish_runtime_suspend(struct pci_dev *dev);
 void pcie_clear_root_pme_status(struct pci_dev *dev);






[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux