linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: Bjorn Helgaas <bhelgaas@google.com>,
	"Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Qipeng Zha <qipeng.zha@intel.com>, Qi Zheng <qi.zheng@intel.com>,
	Dave Airlie <airlied@gmail.com>,
	Mathias Nyman <mathias.nyman@intel.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	linux-pci@vger.kernel.org, linux-pm@vger.kernel.org
Subject: [PATCH v2 4/4] PCI: Add runtime PM support for PCIe ports
Date: Fri,  8 Apr 2016 13:36:30 +0300	[thread overview]
Message-ID: <1460111790-92836-5-git-send-email-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <1460111790-92836-1-git-send-email-mika.westerberg@linux.intel.com>

Add back runtime PM support for PCIe ports that was removed in
commit fe9a743a2601 ("PCI/PM: Drop unused runtime PM support code for
PCIe ports").

First of all we cannot enable it automatically for all ports since there
has been problems previously as can be seen in [1]. In summary suspended
PCIe ports were not able to deal with hotplug reliably. One reason why this
might happen is the fact that when a PCIe port is powered down, config
space access to the devices behind the port is not possible. If the BIOS
hotplug SMI handler assumes the port is always in D0 it will not be able to
find the hotplugged devices. To be on the safe side only enable runtime PM
if the port does not claim to be hotplug capable.

Furthermore we need to check that the PCI core thinks the port can go to D3
in the first place. The PCI core sets 'bridge_d3' in that case. If both
conditions are met we enable and allow runtime PM for the PCIe port. Since
'bridge_d3' can be changed anytime we check this in driver ->runtime_idle()
and ->runtime_suspend() and only allow runtime suspend if the flag is still
set. The actual power transition to D3 and back is handled in the PCI core.

Idea to automatically unblock (allow) runtime PM for PCIe ports came from
Dave Airlie.

[1] https://bugzilla.kernel.org/show_bug.cgi?id=53811

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/pci/pcie/portdrv_pci.c | 85 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 6c6bb03392ea..bbe86527788c 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -58,6 +58,10 @@ __setup("pcie_ports=", pcie_port_setup);
 
 /* global data */
 
+struct pcie_port_data {
+	bool runtime_pm_enabled;
+};
+
 /**
  * pcie_clear_root_pme_status - Clear root port PME interrupt status.
  * @dev: PCIe root port or event collector.
@@ -93,6 +97,58 @@ static int pcie_port_resume_noirq(struct device *dev)
 	return 0;
 }
 
+static int pcie_port_runtime_suspend(struct device *dev)
+{
+	return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
+}
+
+static int pcie_port_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+static int pcie_port_runtime_idle(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	/*
+	 * Rely the PCI core has set bridge_d3 whenever it thinks the port
+	 * should be good to go to D3. Everything else, including moving
+	 * the port to D3, is handled by the PCI core.
+	 */
+	if (pdev->bridge_d3) {
+		pm_schedule_suspend(dev, 10);
+		return 0;
+	}
+	return -EBUSY;
+}
+
+static bool pcie_port_runtime_pm_possible(struct pci_dev *pdev)
+{
+	/*
+	 * Only enable runtime PM if the PCI core agrees that this port can
+	 * even go to D3.
+	 */
+	if (!pdev->bridge_d3)
+		return false;
+
+	/*
+	 * Prevent runtime PM if the port is hotplug capable. Otherwise the
+	 * hotplug SMI code might not be able to enumerate devices behind
+	 * this port properly (the port is powered down preventing all
+	 * config space accesses to the subordinate devices).
+	 */
+	if (pcie_caps_reg(pdev) & PCI_EXP_FLAGS_SLOT) {
+		u32 sltcap;
+
+		pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &sltcap);
+		if (sltcap & (PCI_EXP_SLTCAP_HPC | PCI_EXP_SLTCAP_HPS))
+			return false;
+	}
+
+	return true;
+}
+
 static const struct dev_pm_ops pcie_portdrv_pm_ops = {
 	.suspend	= pcie_port_device_suspend,
 	.resume		= pcie_port_device_resume,
@@ -101,12 +157,20 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
 	.poweroff	= pcie_port_device_suspend,
 	.restore	= pcie_port_device_resume,
 	.resume_noirq	= pcie_port_resume_noirq,
+	.runtime_suspend = pcie_port_runtime_suspend,
+	.runtime_resume	= pcie_port_runtime_resume,
+	.runtime_idle	= pcie_port_runtime_idle,
 };
 
 #define PCIE_PORTDRV_PM_OPS	(&pcie_portdrv_pm_ops)
 
 #else /* !PM */
 
+static inline bool pcie_port_runtime_pm_possible(struct pci_dev *pdev)
+{
+	return false;
+}
+
 #define PCIE_PORTDRV_PM_OPS	NULL
 #endif /* !PM */
 
@@ -121,6 +185,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
 static int pcie_portdrv_probe(struct pci_dev *dev,
 					const struct pci_device_id *id)
 {
+	struct pcie_port_data *pdata;
 	int status;
 
 	if (!pci_is_pcie(dev) ||
@@ -134,11 +199,31 @@ static int pcie_portdrv_probe(struct pci_dev *dev,
 		return status;
 
 	pci_save_state(dev);
+
+	pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	pci_set_drvdata(dev, pdata);
+	if (pcie_port_runtime_pm_possible(dev)) {
+		pm_runtime_put_noidle(&dev->dev);
+		pm_runtime_allow(&dev->dev);
+
+		pdata->runtime_pm_enabled = true;
+	}
+
 	return 0;
 }
 
 static void pcie_portdrv_remove(struct pci_dev *dev)
 {
+	const struct pcie_port_data *pdata = pci_get_drvdata(dev);
+
+	if (pdata->runtime_pm_enabled) {
+		pm_runtime_forbid(&dev->dev);
+		pm_runtime_get_noresume(&dev->dev);
+	}
+
 	pcie_port_device_remove(dev);
 }
 
-- 
2.8.0.rc3

  parent reply	other threads:[~2016-04-08 10:36 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-08 10:36 [PATCH v2 0/4] PCI: Add support for suspending (including runtime) of PCIe ports Mika Westerberg
2016-04-08 10:36 ` [PATCH v2 1/4] PCI: No need to set d3cold_allowed to " Mika Westerberg
2016-04-08 10:36 ` [PATCH v2 2/4] PCI: Move PCIe ports to D3 during suspend Mika Westerberg
2016-04-08 15:07   ` Greg Kroah-Hartman
2016-04-11  8:47     ` Mika Westerberg
2016-04-11  3:36   ` Zheng, Qi
2016-04-11  8:56     ` Mika Westerberg
2016-04-11 13:38       ` Rafael J. Wysocki
2016-04-12  6:51         ` Mika Westerberg
2016-04-12 17:45   ` Lukas Wunner
2016-04-13  8:34     ` Mika Westerberg
2016-04-08 10:36 ` [PATCH v2 3/4] ACPI / hotplug / PCI: Runtime resume bridge before rescan Mika Westerberg
2016-04-08 10:36 ` Mika Westerberg [this message]
2016-04-12 17:52   ` [PATCH v2 4/4] PCI: Add runtime PM support for PCIe ports Lukas Wunner
2016-04-13  8:33     ` Mika Westerberg
2016-04-13  9:08       ` Andreas Noever
2016-04-13  9:16         ` Mika Westerberg
2016-04-18 14:38       ` Lukas Wunner
2016-04-19 12:31         ` Mika Westerberg
2016-04-20 19:22           ` Lukas Wunner
2016-04-20 20:23             ` Rafael J. Wysocki
2016-04-21 13:12               ` Mika Westerberg
2016-04-21 19:19                 ` Rafael J. Wysocki
2016-04-21 23:25                   ` Andreas Noever
2016-04-22  0:26                     ` Rafael J. Wysocki
2016-04-22  9:10                       ` Mika Westerberg
2016-04-22 12:37                         ` Rafael J. Wysocki
2016-04-21 13:10             ` Mika Westerberg
2016-04-24 16:13               ` Lukas Wunner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1460111790-92836-5-git-send-email-mika.westerberg@linux.intel.com \
    --to=mika.westerberg@linux.intel.com \
    --cc=airlied@gmail.com \
    --cc=bhelgaas@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=qi.zheng@intel.com \
    --cc=qipeng.zha@intel.com \
    --cc=rjw@rjwysocki.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).