Commit 0acf5676 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pm-5.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management fix from Rafael Wysocki:
 "Revert a recent PCI power management change that caused problems to
  occur on multiple systems (Mika Westerberg)"

* tag 'pm-5.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  Revert "PCI: Add missing link delays required by the PCIe spec"
parents e577dc15 0617bded
...@@ -1025,10 +1025,15 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) ...@@ -1025,10 +1025,15 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state)
if (state == PCI_D0) { if (state == PCI_D0) {
pci_platform_power_transition(dev, PCI_D0); pci_platform_power_transition(dev, PCI_D0);
/* /*
* Mandatory power management transition delays are * Mandatory power management transition delays, see
* handled in the PCIe portdrv resume hooks. * PCI Express Base Specification Revision 2.0 Section
* 6.6.1: Conventional Reset. Do not delay for
* devices powered on/off by corresponding bridge,
* because have already delayed for the bridge.
*/ */
if (dev->runtime_d3cold) { if (dev->runtime_d3cold) {
if (dev->d3cold_delay && !dev->imm_ready)
msleep(dev->d3cold_delay);
/* /*
* When powering on a bridge from D3cold, the * When powering on a bridge from D3cold, the
* whole hierarchy may be powered on into * whole hierarchy may be powered on into
...@@ -4602,16 +4607,14 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) ...@@ -4602,16 +4607,14 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS); return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
} }
/** /**
* pcie_wait_for_link_delay - Wait until link is active or inactive * pcie_wait_for_link - Wait until link is active or inactive
* @pdev: Bridge device * @pdev: Bridge device
* @active: waiting for active or inactive? * @active: waiting for active or inactive?
* @delay: Delay to wait after link has become active (in ms)
* *
* Use this to wait till link becomes active or inactive. * Use this to wait till link becomes active or inactive.
*/ */
bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay) bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
{ {
int timeout = 1000; int timeout = 1000;
bool ret; bool ret;
...@@ -4648,25 +4651,13 @@ bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay) ...@@ -4648,25 +4651,13 @@ bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay)
timeout -= 10; timeout -= 10;
} }
if (active && ret) if (active && ret)
msleep(delay); msleep(100);
else if (ret != active) else if (ret != active)
pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n", pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
active ? "set" : "cleared"); active ? "set" : "cleared");
return ret == active; return ret == active;
} }
/**
* pcie_wait_for_link - Wait until link is active or inactive
* @pdev: Bridge device
* @active: waiting for active or inactive?
*
* Use this to wait till link becomes active or inactive.
*/
bool pcie_wait_for_link(struct pci_dev *pdev, bool active)
{
return pcie_wait_for_link_delay(pdev, active, 100);
}
void pci_reset_secondary_bus(struct pci_dev *dev) void pci_reset_secondary_bus(struct pci_dev *dev)
{ {
u16 ctrl; u16 ctrl;
......
...@@ -497,7 +497,6 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev) ...@@ -497,7 +497,6 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
u32 service); u32 service);
bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay);
bool pcie_wait_for_link(struct pci_dev *pdev, bool active); bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
#ifdef CONFIG_PCIEASPM #ifdef CONFIG_PCIEASPM
void pcie_aspm_init_link_state(struct pci_dev *pdev); void pcie_aspm_init_link_state(struct pci_dev *pdev);
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -379,67 +378,6 @@ static int pm_iter(struct device *dev, void *data) ...@@ -379,67 +378,6 @@ static int pm_iter(struct device *dev, void *data)
return 0; return 0;
} }
static int get_downstream_delay(struct pci_bus *bus)
{
struct pci_dev *pdev;
int min_delay = 100;
int max_delay = 0;
list_for_each_entry(pdev, &bus->devices, bus_list) {
if (!pdev->imm_ready)
min_delay = 0;
else if (pdev->d3cold_delay < min_delay)
min_delay = pdev->d3cold_delay;
if (pdev->d3cold_delay > max_delay)
max_delay = pdev->d3cold_delay;
}
return max(min_delay, max_delay);
}
/*
* wait_for_downstream_link - Wait for downstream link to establish
* @pdev: PCIe port whose downstream link is waited
*
* Handle delays according to PCIe 4.0 section 6.6.1 before configuration
* access to the downstream component is permitted.
*
* This blocks PCI core resume of the hierarchy below this port until the
* link is trained. Should be called before resuming port services to
* prevent pciehp from starting to tear-down the hierarchy too soon.
*/
static void wait_for_downstream_link(struct pci_dev *pdev)
{
int delay;
if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM)
return;
if (pci_dev_is_disconnected(pdev))
return;
if (!pdev->subordinate || list_empty(&pdev->subordinate->devices) ||
!pdev->bridge_d3)
return;
delay = get_downstream_delay(pdev->subordinate);
if (!delay)
return;
dev_dbg(&pdev->dev, "waiting downstream link for %d ms\n", delay);
/*
* If downstream port does not support speeds greater than 5 GT/s
* need to wait 100ms. For higher speeds (gen3) we need to wait
* first for the data link layer to become active.
*/
if (pcie_get_speed_cap(pdev) <= PCIE_SPEED_5_0GT)
msleep(delay);
else
pcie_wait_for_link_delay(pdev, true, delay);
}
/** /**
* pcie_port_device_suspend - suspend port services associated with a PCIe port * pcie_port_device_suspend - suspend port services associated with a PCIe port
* @dev: PCI Express port to handle * @dev: PCI Express port to handle
...@@ -453,8 +391,6 @@ int pcie_port_device_suspend(struct device *dev) ...@@ -453,8 +391,6 @@ int pcie_port_device_suspend(struct device *dev)
int pcie_port_device_resume_noirq(struct device *dev) int pcie_port_device_resume_noirq(struct device *dev)
{ {
size_t off = offsetof(struct pcie_port_service_driver, resume_noirq); size_t off = offsetof(struct pcie_port_service_driver, resume_noirq);
wait_for_downstream_link(to_pci_dev(dev));
return device_for_each_child(dev, &off, pm_iter); return device_for_each_child(dev, &off, pm_iter);
} }
...@@ -485,8 +421,6 @@ int pcie_port_device_runtime_suspend(struct device *dev) ...@@ -485,8 +421,6 @@ int pcie_port_device_runtime_suspend(struct device *dev)
int pcie_port_device_runtime_resume(struct device *dev) int pcie_port_device_runtime_resume(struct device *dev)
{ {
size_t off = offsetof(struct pcie_port_service_driver, runtime_resume); size_t off = offsetof(struct pcie_port_service_driver, runtime_resume);
wait_for_downstream_link(to_pci_dev(dev));
return device_for_each_child(dev, &off, pm_iter); return device_for_each_child(dev, &off, pm_iter);
} }
#endif /* PM */ #endif /* PM */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment