Merge branch 'pci/pm'

- Reduce wait time for secondary bus to be ready to speed up resume (Mika
  Westerberg)

- Avoid putting EloPOS E2/S2/H2 (as well as Elo i2) PCIe Ports in D3cold
  (Ondrej Zary)

- Call _REG when transitioning D-states so AML that uses the PCI config
  space OpRegion works, which fixes some ASMedia GPIO controllers (Mario
  Limonciello)

* pci/pm:
  PCI/ACPI: Call _REG when transitioning D-states
  PCI/ACPI: Validate acpi_pci_set_power_state() parameter
  PCI/PM: Avoid putting EloPOS E2/S2/H2 PCIe Ports in D3cold
  PCI/PM: Shorten pci_bridge_wait_for_secondary_bus() wait time for slow links
This commit is contained in:
Bjorn Helgaas 2023-06-26 12:59:56 -05:00
commit 7e229f0e05
3 changed files with 82 additions and 37 deletions

View File

@ -1043,6 +1043,16 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev)
return false;
}
static void acpi_pci_config_space_access(struct pci_dev *dev, bool enable)
{
int val = enable ? ACPI_REG_CONNECT : ACPI_REG_DISCONNECT;
int ret = acpi_evaluate_reg(ACPI_HANDLE(&dev->dev),
ACPI_ADR_SPACE_PCI_CONFIG, val);
if (ret)
pci_dbg(dev, "ACPI _REG %s evaluation failed (%d)\n",
enable ? "connect" : "disconnect", ret);
}
int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
@ -1053,32 +1063,49 @@ int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
[PCI_D3hot] = ACPI_STATE_D3_HOT,
[PCI_D3cold] = ACPI_STATE_D3_COLD,
};
int error = -EINVAL;
int error;
/* If the ACPI device has _EJ0, ignore the device */
if (!adev || acpi_has_method(adev->handle, "_EJ0"))
return -ENODEV;
switch (state) {
case PCI_D3cold:
if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
PM_QOS_FLAGS_ALL) {
error = -EBUSY;
break;
}
fallthrough;
case PCI_D0:
case PCI_D1:
case PCI_D2:
case PCI_D3hot:
error = acpi_device_set_power(adev, state_conv[state]);
case PCI_D3cold:
break;
default:
return -EINVAL;
}
if (!error)
pci_dbg(dev, "power state changed by ACPI to %s\n",
acpi_power_state_string(adev->power.state));
if (state == PCI_D3cold) {
if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) ==
PM_QOS_FLAGS_ALL)
return -EBUSY;
return error;
/* Notify AML lack of PCI config space availability */
acpi_pci_config_space_access(dev, false);
}
error = acpi_device_set_power(adev, state_conv[state]);
if (error)
return error;
pci_dbg(dev, "power state changed by ACPI to %s\n",
acpi_power_state_string(adev->power.state));
/*
* Notify AML of PCI config space availability. Config space is
* accessible in all states except D3cold; the only transitions
* that change availability are transitions to D3cold and from
* D3cold to D0.
*/
if (state == PCI_D0)
acpi_pci_config_space_access(dev, true);
return 0;
}
pci_power_t acpi_pci_get_power_state(struct pci_dev *dev)

View File

@ -64,6 +64,13 @@ struct pci_pme_device {
#define PME_TIMEOUT 1000 /* How long between PME checks */
/*
* Following exit from Conventional Reset, devices must be ready within 1 sec
* (PCIe r6.0 sec 6.6.1). A D3cold to D0 transition implies a Conventional
* Reset (PCIe r6.0 sec 5.8).
*/
#define PCI_RESET_WAIT 1000 /* msec */
/*
* Devices may extend the 1 sec period through Request Retry Status
* completions (PCIe r6.0 sec 2.3.1). The spec does not provide an upper
@ -2968,13 +2975,13 @@ static const struct dmi_system_id bridge_d3_blacklist[] = {
{
/*
* Downstream device is not accessible after putting a root port
* into D3cold and back into D0 on Elo i2.
* into D3cold and back into D0 on Elo Continental Z2 board
*/
.ident = "Elo i2",
.ident = "Elo Continental Z2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Elo Touch Solutions"),
DMI_MATCH(DMI_PRODUCT_NAME, "Elo i2"),
DMI_MATCH(DMI_PRODUCT_VERSION, "RevB"),
DMI_MATCH(DMI_BOARD_VENDOR, "Elo Touch Solutions"),
DMI_MATCH(DMI_BOARD_NAME, "Geminilake"),
DMI_MATCH(DMI_BOARD_VERSION, "Continental Z2"),
},
},
#endif
@ -5102,11 +5109,9 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type)
*
* However, 100 ms is the minimum and the PCIe spec says the
* software must allow at least 1s before it can determine that the
* device that did not respond is a broken device. There is
* evidence that 100 ms is not always enough, for example certain
* Titan Ridge xHCI controller does not always respond to
* configuration requests if we only wait for 100 ms (see
* https://bugzilla.kernel.org/show_bug.cgi?id=203885).
* device that did not respond is a broken device. Also device can
* take longer than that to respond if it indicates so through Request
* Retry Status completions.
*
* Therefore we wait for 100 ms and check for the device presence
* until the timeout expires.
@ -5115,16 +5120,36 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type)
return 0;
if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) {
u16 status;
pci_dbg(dev, "waiting %d ms for downstream link\n", delay);
msleep(delay);
} else {
pci_dbg(dev, "waiting %d ms for downstream link, after activation\n",
delay);
if (!pcie_wait_for_link_delay(dev, true, delay)) {
/* Did not train, no need to wait any further */
pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
if (!pci_dev_wait(child, reset_type, PCI_RESET_WAIT - delay))
return 0;
/*
* If the port supports active link reporting we now check
* whether the link is active and if not bail out early with
* the assumption that the device is not present anymore.
*/
if (!dev->link_active_reporting)
return -ENOTTY;
}
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &status);
if (!(status & PCI_EXP_LNKSTA_DLLLA))
return -ENOTTY;
return pci_dev_wait(child, reset_type,
PCIE_RESET_READY_POLL_MS - PCI_RESET_WAIT);
}
pci_dbg(dev, "waiting %d ms for downstream link, after activation\n",
delay);
if (!pcie_wait_for_link_delay(dev, true, delay)) {
/* Did not train, no need to wait any further */
pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
return -ENOTTY;
}
return pci_dev_wait(child, reset_type,

View File

@ -66,13 +66,6 @@ struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev,
#define PCI_PM_D3HOT_WAIT 10 /* msec */
#define PCI_PM_D3COLD_WAIT 100 /* msec */
/*
* Following exit from Conventional Reset, devices must be ready within 1 sec
* (PCIe r6.0 sec 6.6.1). A D3cold to D0 transition implies a Conventional
* Reset (PCIe r6.0 sec 5.8).
*/
#define PCI_RESET_WAIT 1000 /* msec */
void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
void pci_refresh_power_state(struct pci_dev *dev);
int pci_power_up(struct pci_dev *dev);