These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / acpi / power.c
index e0bcfb6..fcd4ce6 100644 (file)
@@ -1,8 +1,10 @@
 /*
- *  acpi_power.c - ACPI Bus Power Management ($Revision: 39 $)
+ * drivers/acpi/power.c - ACPI Power Resources management.
  *
- *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
- *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2001 - 2015 Intel Corp.
+ * Author: Andy Grover <andrew.grover@intel.com>
+ * Author: Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  *  General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
  * ACPI power-managed devices may be controlled in two ways:
  * 1. via "Device Specific (D-State) Control"
  * 2. via "Power Resource Control".
- * This module is used to manage devices relying on Power Resource Control.
+ * The code below deals with ACPI Power Resources control.
  * 
- * An ACPI "power resource object" describes a software controllable power
- * plane, clock plane, or other resource used by a power managed device.
+ * An ACPI "power resource object" represents a software controllable power
+ * plane, clock plane, or other resource depended on by a device.
+ *
  * A device may rely on multiple power resources, and a power resource
  * may be shared by multiple devices.
  */
@@ -684,7 +683,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
                }
        }
 
-       *state = ACPI_STATE_D3_COLD;
+       *state = device->power.states[ACPI_STATE_D3_COLD].flags.valid ?
+               ACPI_STATE_D3_COLD : ACPI_STATE_D3_HOT;
        return 0;
 }
 
@@ -710,8 +710,6 @@ int acpi_power_transition(struct acpi_device *device, int state)
            || (device->power.state > ACPI_STATE_D3_COLD))
                return -ENODEV;
 
-       /* TBD: Resources must be ordered. */
-
        /*
         * First we reference all power resources required in the target list
         * (e.g. so the device doesn't lose power while transitioning).  Then,
@@ -761,6 +759,25 @@ static void acpi_power_sysfs_remove(struct acpi_device *device)
        device_remove_file(&device->dev, &dev_attr_resource_in_use);
 }
 
+static void acpi_power_add_resource_to_list(struct acpi_power_resource *resource)
+{
+       mutex_lock(&power_resource_list_lock);
+
+       if (!list_empty(&acpi_power_resource_list)) {
+               struct acpi_power_resource *r;
+
+               list_for_each_entry(r, &acpi_power_resource_list, list_node)
+                       if (r->order > resource->order) {
+                               list_add_tail(&resource->list_node, &r->list_node);
+                               goto out;
+                       }
+       }
+       list_add_tail(&resource->list_node, &acpi_power_resource_list);
+
+ out:
+       mutex_unlock(&power_resource_list_lock);
+}
+
 int acpi_add_power_resource(acpi_handle handle)
 {
        struct acpi_power_resource *resource;
@@ -811,9 +828,7 @@ int acpi_add_power_resource(acpi_handle handle)
        if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
                device->remove = acpi_power_sysfs_remove;
 
-       mutex_lock(&power_resource_list_lock);
-       list_add(&resource->list_node, &acpi_power_resource_list);
-       mutex_unlock(&power_resource_list_lock);
+       acpi_power_add_resource_to_list(resource);
        acpi_device_add_finalize(device);
        return 0;
 
@@ -844,7 +859,22 @@ void acpi_resume_power_resources(void)
                    && resource->ref_count) {
                        dev_info(&resource->device.dev, "Turning ON\n");
                        __acpi_power_on(resource);
-               } else if (state == ACPI_POWER_RESOURCE_STATE_ON
+               }
+
+               mutex_unlock(&resource->resource_lock);
+       }
+       list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
+               int result, state;
+
+               mutex_lock(&resource->resource_lock);
+
+               result = acpi_power_get_state(resource->device.handle, &state);
+               if (result) {
+                       mutex_unlock(&resource->resource_lock);
+                       continue;
+               }
+
+               if (state == ACPI_POWER_RESOURCE_STATE_ON
                    && !resource->ref_count) {
                        dev_info(&resource->device.dev, "Turning OFF\n");
                        __acpi_power_off(resource);