summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLukas Wunner <lukas@wunner.de>2018-07-19 17:27:56 -0500
committerBjorn Helgaas <bhelgaas@google.com>2018-07-31 11:09:36 -0500
commit8350307454240abeebe52ff5a73810d9ba93dd60 (patch)
treec55c3669332a93cd63e5547c962a9efd79e0b047 /drivers
parent6b08c3854cfdc5d13165880e2b54642c47edc405 (diff)
downloadlinux-8350307454240abeebe52ff5a73810d9ba93dd60.tar.bz2
PCI: pciehp: Resume to D0 on enable/disable
pciehp's IRQ thread ensures accessibility of the port by runtime resuming its parent to D0. However when the slot is enabled/disabled, the port itself needs to be in D0 because its secondary bus is accessed in: pciehp_check_link_status(), pciehp_configure_device() (both called from board_added()) and pciehp_unconfigure_device() (called from remove_board()). Thus, acquire a runtime PM ref on enable/disablement of the slot. Yinghai Lu additionally discovered that some SkyLake servers feature a Power Controller for their PCIe hotplug ports (PCIe r3.1, sec 6.7.1.8) which requires the port to be in D0 when invoking pciehp_power_on_slot() (likewise called from board_added()). If slot power is turned on while in D3hot, link training later fails: https://lkml.kernel.org/r/20170205073454.GA253@wunner.de The spec is silent about such a requirement, but it seems prudent to assume that any hotplug port with a Power Controller may need this. The present commit holds a runtime PM ref whenever slot power is turned on and off, but it doesn't keep the port in D0 as long as slot power is on. If vendors determine that's necessary, they need to amend pciehp to acquire a runtime PM ref in pciehp_power_on_slot() and release one in pciehp_power_off_slot(). Signed-off-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Cc: Mika Westerberg <mika.westerberg@linux.intel.com> Cc: Ashok Raj <ashok.raj@intel.com> Cc: Keith Busch <keith.busch@intel.com> Cc: Yinghai Lu <yinghai@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 811019902ada..6855933ab372 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <linux/pci.h>
#include "../pci.h"
#include "pciehp.h"
@@ -310,9 +311,11 @@ static int pciehp_enable_slot(struct slot *slot)
struct controller *ctrl = slot->ctrl;
int ret;
+ pm_runtime_get_sync(&ctrl->pcie->port->dev);
ret = __pciehp_enable_slot(slot);
if (ret && ATTN_BUTTN(ctrl))
pciehp_green_led_off(slot); /* may be blinking */
+ pm_runtime_put(&ctrl->pcie->port->dev);
mutex_lock(&slot->lock);
slot->state = ret ? OFF_STATE : ON_STATE;
@@ -341,9 +344,12 @@ static int __pciehp_disable_slot(struct slot *p_slot)
static int pciehp_disable_slot(struct slot *slot)
{
+ struct controller *ctrl = slot->ctrl;
int ret;
+ pm_runtime_get_sync(&ctrl->pcie->port->dev);
ret = __pciehp_disable_slot(slot);
+ pm_runtime_put(&ctrl->pcie->port->dev);
mutex_lock(&slot->lock);
slot->state = OFF_STATE;