Loading drivers/acpi/device_pm.c +19 −0 Original line number Diff line number Diff line Loading @@ -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); Loading drivers/pci/pci-acpi.c +31 −14 Original line number Diff line number Diff line Loading @@ -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)) 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; /* Loading @@ -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; /* Loading @@ -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; Loading include/acpi/acpi_bus.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/acpi/device_pm.c +19 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
drivers/pci/pci-acpi.c +31 −14 Original line number Diff line number Diff line Loading @@ -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)) 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; /* Loading @@ -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; /* Loading @@ -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; Loading
include/acpi/acpi_bus.h +1 −0 Original line number Diff line number Diff line Loading @@ -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