aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/device_pm.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-17 08:11:05 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-17 08:11:05 -0500
commitbc9b6407bd6df3ab7189e5622816bbc11ae9d2d8 (patch)
tree8f44ae6c9750b271eb423787e19db1288b53c42e /drivers/acpi/device_pm.c
parent6a8dd80821c215bc49bf6b108e85c1738c82bf43 (diff)
ACPI / PM: Rework the handling of devices depending on power resources
Commit 0090def6 (ACPI: Add interface to register/unregister device to/from power resources) made it possible to indicate to the ACPI core that if the given device depends on any power resources, then it should be resumed as soon as all of the power resources required by it to transition to the D0 power state have been turned on. Unfortunately, however, this was a mistake, because all devices depending on power resources should be treated this way (i.e. they should be resumed when all power resources required by their D0 state have been turned on) and for the majority of those devices the ACPI core can figure out by itself which (physical) devices depend on what power resources. For this reason, replace the code added by commit 0090def6 with a new, much more straightforward, mechanism that will be used internally by the ACPI core and remove all references to that code from kernel subsystems using ACPI. For the cases when there are (physical) devices that should be resumed whenever a not directly related ACPI device node goes into D0 as a result of power resources configuration changes, like in the SATA case, add two new routines, acpi_dev_pm_add_dependent() and acpi_dev_pm_remove_dependent(), allowing subsystems to manage such dependencies. Convert the SATA subsystem to use the new functions accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r--drivers/acpi/device_pm.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 995019063f64..8be4b29e38aa 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -665,3 +665,59 @@ void acpi_dev_pm_detach(struct device *dev, bool power_off)
665 } 665 }
666} 666}
667EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); 667EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);
668
669/**
670 * acpi_dev_pm_add_dependent - Add physical device depending for PM.
671 * @handle: Handle of ACPI device node.
672 * @depdev: Device depending on that node for PM.
673 */
674void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev)
675{
676 struct acpi_device_physical_node *dep;
677 struct acpi_device *adev;
678
679 if (!depdev || acpi_bus_get_device(handle, &adev))
680 return;
681
682 mutex_lock(&adev->physical_node_lock);
683
684 list_for_each_entry(dep, &adev->power_dependent, node)
685 if (dep->dev == depdev)
686 goto out;
687
688 dep = kzalloc(sizeof(*dep), GFP_KERNEL);
689 if (dep) {
690 dep->dev = depdev;
691 list_add_tail(&dep->node, &adev->power_dependent);
692 }
693
694 out:
695 mutex_unlock(&adev->physical_node_lock);
696}
697EXPORT_SYMBOL_GPL(acpi_dev_pm_add_dependent);
698
699/**
700 * acpi_dev_pm_remove_dependent - Remove physical device depending for PM.
701 * @handle: Handle of ACPI device node.
702 * @depdev: Device depending on that node for PM.
703 */
704void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
705{
706 struct acpi_device_physical_node *dep;
707 struct acpi_device *adev;
708
709 if (!depdev || acpi_bus_get_device(handle, &adev))
710 return;
711
712 mutex_lock(&adev->physical_node_lock);
713
714 list_for_each_entry(dep, &adev->power_dependent, node)
715 if (dep->dev == depdev) {
716 list_del(&dep->node);
717 kfree(dep);
718 break;
719 }
720
721 mutex_unlock(&adev->physical_node_lock);
722}
723EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);