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)
+{
+       /*
+        * Assume 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.
+        */
+       return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
+}
+
 static const struct dev_pm_ops pcie_portdrv_pm_ops = {
        .suspend        = pcie_port_device_suspend,
        .resume         = pcie_port_device_resume,
        .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)
                return status;
 
        pci_save_state(dev);
+
+       /*
+        * Prevent runtime PM if the port is advertising support for PCIe
+        * hotplug.  Otherwise the BIOS 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).  We can't be sure for native PCIe hotplug
+        * either so prevent that as well.
+        */
+       if (!dev->is_hotplug_bridge) {
+               /*
+                * Keep the port resumed 100ms to make sure things like
+                * config space accesses from userspace (lspci) will not
+                * cause the port to repeatedly suspend and resume.
+                */
+               pm_runtime_set_autosuspend_delay(&dev->dev, 100);
+               pm_runtime_use_autosuspend(&dev->dev);
+               pm_runtime_mark_last_busy(&dev->dev);
+               pm_runtime_put_autosuspend(&dev->dev);
+               pm_runtime_allow(&dev->dev);
+       }
+
        return 0;
 }
 
 static void pcie_portdrv_remove(struct pci_dev *dev)
 {
+       if (!dev->is_hotplug_bridge) {
+               pm_runtime_forbid(&dev->dev);
+               pm_runtime_get_noresume(&dev->dev);
+               pm_runtime_dont_use_autosuspend(&dev->dev);
+       }
+
        pcie_port_device_remove(dev);
 }