#include "pci-host-common.h"
+#define PCI_HOST_D3COLD_ALLOWED BIT(0)
+#define PCI_HOST_PME_D3COLD_CAPABLE BIT(1)
+
static void gen_pci_unmap_cfg(void *ptr)
{
pci_ecam_free((struct pci_config_window *)ptr);
}
EXPORT_SYMBOL_GPL(pci_host_common_remove);
+static int __pci_host_common_d3cold_possible(struct pci_dev *pdev,
+ void *userdata)
+{
+ u32 *flags = userdata;
+
+ if (!pdev->dev.driver && !pci_is_enabled(pdev))
+ return 0;
+
+ if (pdev->current_state != PCI_D3hot)
+ goto exit;
+
+ if (device_may_wakeup(&pdev->dev)) {
+ if (!pci_pme_capable(pdev, PCI_D3cold))
+ goto exit;
+ else
+ *flags |= PCI_HOST_PME_D3COLD_CAPABLE;
+ }
+
+ return 0;
+
+exit:
+ *flags &= ~PCI_HOST_D3COLD_ALLOWED;
+
+ return -EOPNOTSUPP;
+}
+
+/**
+ * pci_host_common_d3cold_possible - Determine whether the host bridge can
+ * transition the devices into D3cold.
+ *
+ * @bridge: PCI host bridge to check
+ * @pme_capable: Pointer to update if there is any device capable of generating
+ * PME from D3cold.
+ *
+ * Walk downstream PCIe endpoint devices and determine whether the host bridge
+ * is permitted to transition the devices into D3cold.
+ *
+ * Devices under host bridge can enter D3cold only if all active PCIe
+ * endpoints are in PCI_D3hot and any wakeup-enabled endpoint is capable of
+ * generating PME from D3cold. Inactive endpoints are ignored.
+ *
+ * The @pme_capable output allows PCIe controller drivers to apply
+ * platform-specific handling to preserve wakeup functionality.
+ *
+ * Return: %true if the host bridge may enter D3cold, otherwise %false.
+ */
+bool pci_host_common_d3cold_possible(struct pci_host_bridge *bridge,
+ bool *pme_capable)
+{
+ u32 flags = PCI_HOST_D3COLD_ALLOWED;
+
+ pci_walk_bus(bridge->bus, __pci_host_common_d3cold_possible, &flags);
+
+ *pme_capable = !!(flags & PCI_HOST_PME_D3COLD_CAPABLE);
+
+ return !!(flags & PCI_HOST_D3COLD_ALLOWED);
+}
+EXPORT_SYMBOL_GPL(pci_host_common_d3cold_possible);
+
MODULE_DESCRIPTION("Common library for PCI host controller drivers");
MODULE_LICENSE("GPL v2");