Merge branch 'pci/pm'
- Account for _S0W when deciding whether to put bridges in D3 to avoid missing hotplug events (Rafael J. Wysocki) * pci/pm: PCI/ACPI: Account for _S0W of the target bridge in acpi_pci_bridge_d3()
This commit is contained in:
commit
08a67024a0
|
@ -484,6 +484,25 @@ void acpi_dev_power_up_children_with_adr(struct acpi_device *adev)
|
|||
acpi_dev_for_each_child(adev, acpi_power_up_if_adr_present, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_dev_power_state_for_wake - Deepest power state for wakeup signaling
|
||||
* @adev: ACPI companion of the target device.
|
||||
*
|
||||
* Evaluate _S0W for @adev and return the value produced by it or return
|
||||
* ACPI_STATE_UNKNOWN on errors (including _S0W not present).
|
||||
*/
|
||||
u8 acpi_dev_power_state_for_wake(struct acpi_device *adev)
|
||||
{
|
||||
unsigned long long state;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state);
|
||||
if (ACPI_FAILURE(status))
|
||||
return ACPI_STATE_UNKNOWN;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static DEFINE_MUTEX(acpi_pm_notifier_lock);
|
||||
static DEFINE_MUTEX(acpi_pm_notifier_install_lock);
|
||||
|
|
|
@ -976,24 +976,41 @@ bool acpi_pci_power_manageable(struct pci_dev *dev)
|
|||
bool acpi_pci_bridge_d3(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *rpdev;
|
||||
struct acpi_device *adev;
|
||||
acpi_status status;
|
||||
unsigned long long state;
|
||||
struct acpi_device *adev, *rpadev;
|
||||
const union acpi_object *obj;
|
||||
|
||||
if (acpi_pci_disabled || !dev->is_hotplug_bridge)
|
||||
return false;
|
||||
|
||||
/* Assume D3 support if the bridge is power-manageable by ACPI. */
|
||||
if (acpi_pci_power_manageable(dev))
|
||||
return true;
|
||||
adev = ACPI_COMPANION(&dev->dev);
|
||||
if (adev) {
|
||||
/*
|
||||
* If the bridge has _S0W, whether or not it can go into D3
|
||||
* depends on what is returned by that object. In particular,
|
||||
* if the power state returned by _S0W is D2 or shallower,
|
||||
* entering D3 should not be allowed.
|
||||
*/
|
||||
if (acpi_dev_power_state_for_wake(adev) <= ACPI_STATE_D2)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Otherwise, assume that the bridge can enter D3 so long as it
|
||||
* is power-manageable via ACPI.
|
||||
*/
|
||||
if (acpi_device_power_manageable(adev))
|
||||
return true;
|
||||
}
|
||||
|
||||
rpdev = pcie_find_root_port(dev);
|
||||
if (!rpdev)
|
||||
return false;
|
||||
|
||||
adev = ACPI_COMPANION(&rpdev->dev);
|
||||
if (!adev)
|
||||
if (rpdev == dev)
|
||||
rpadev = adev;
|
||||
else
|
||||
rpadev = ACPI_COMPANION(&rpdev->dev);
|
||||
|
||||
if (!rpadev)
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -1001,15 +1018,15 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev)
|
|||
* doesn't supply a wakeup GPE via _PRW, it cannot signal hotplug
|
||||
* events from low-power states including D3hot and D3cold.
|
||||
*/
|
||||
if (!adev->wakeup.flags.valid)
|
||||
if (!rpadev->wakeup.flags.valid)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If the Root Port cannot wake itself from D3hot or D3cold, we
|
||||
* can't use D3.
|
||||
* In the bridge-below-a-Root-Port case, evaluate _S0W for the Root Port
|
||||
* to verify whether or not it can signal wakeup from D3.
|
||||
*/
|
||||
status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state);
|
||||
if (ACPI_SUCCESS(status) && state < ACPI_STATE_D3_HOT)
|
||||
if (rpadev != adev &&
|
||||
acpi_dev_power_state_for_wake(rpadev) <= ACPI_STATE_D2)
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -1018,7 +1035,7 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev)
|
|||
* bridges *below* that Root Port can also signal hotplug events
|
||||
* while in D3.
|
||||
*/
|
||||
if (!acpi_dev_get_property(adev, "HotPlugSupportInD3",
|
||||
if (!acpi_dev_get_property(rpadev, "HotPlugSupportInD3",
|
||||
ACPI_TYPE_INTEGER, &obj) &&
|
||||
obj->integer.value == 1)
|
||||
return true;
|
||||
|
|
|
@ -533,6 +533,7 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p);
|
|||
int acpi_device_update_power(struct acpi_device *device, int *state_p);
|
||||
bool acpi_bus_power_manageable(acpi_handle handle);
|
||||
void acpi_dev_power_up_children_with_adr(struct acpi_device *adev);
|
||||
u8 acpi_dev_power_state_for_wake(struct acpi_device *adev);
|
||||
int acpi_device_power_add_dependent(struct acpi_device *adev,
|
||||
struct device *dev);
|
||||
void acpi_device_power_remove_dependent(struct acpi_device *adev,
|
||||
|
|
Loading…
Reference in New Issue