#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
+#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/platform_device.h>
+#include "../pci-host-common.h"
#include "../../pci.h"
#include "pcie-designware.h"
int dw_pcie_suspend_noirq(struct dw_pcie *pci)
{
- u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ bool pme_capable = false;
int ret = 0;
u32 val;
if (!dw_pcie_link_up(pci))
goto stop_link;
- /*
- * If L1SS is supported, then do not put the link into L2 as some
- * devices such as NVMe expect low resume latency.
- */
- if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & PCI_EXP_LNKCTL_ASPM_L1)
+ if (!pci_host_common_d3cold_possible(pci->pp.bridge, &pme_capable))
return 0;
if (pci->pp.ops->pme_turn_off) {
udelay(1);
stop_link:
+ /*
+ * TODO: "pme_capable" means some downstream device is wakeup-
+ * enabled and is capable of generating PME from D3cold, which
+ * requires auxiliary power. Instead of always skipping power off
+ * if PME is supported from D3cold, query the pwrctrl core and skip
+ * power off only if device supports PME from D3cold and Vaux is
+ * not supported.
+ */
+ pci->pp.skip_pwrctrl_off = pme_capable;
dw_pcie_stop_link(pci);
if (pci->pp.ops->deinit)
pci->pp.ops->deinit(&pci->pp);
if (!pci->suspended)
return 0;
- pci->suspended = false;
-
if (pci->pp.ops->init) {
ret = pci->pp.ops->init(&pci->pp);
if (ret) {
if (pci->pp.ops->post_init)
pci->pp.ops->post_init(&pci->pp);
+ pci->suspended = false;
+
return 0;
err_stop_link: