From 8350307454240abeebe52ff5a73810d9ba93dd60 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 19 Jul 2018 17:27:56 -0500 Subject: [PATCH] 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 Signed-off-by: Bjorn Helgaas Cc: Rafael J. Wysocki Cc: Mika Westerberg Cc: Ashok Raj Cc: Keith Busch Cc: Yinghai Lu --- drivers/pci/hotplug/pciehp_ctrl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 8110199..6855933 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #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; -- 2.7.4