thermal: power_allocator: relax the requirement of two passive trip points
[deliverable/linux.git] / drivers / thermal / power_allocator.c
index 51473473f15481eba0e08a01cd992cb32a8100d9..ea57759eb095c5b4f6a75cc6eff463862516936e 100644 (file)
@@ -24,6 +24,8 @@
 
 #include "thermal_core.h"
 
+#define INVALID_TRIP -1
+
 #define FRAC_BITS 10
 #define int_to_frac(x) ((x) << FRAC_BITS)
 #define frac_to_int(x) ((x) >> FRAC_BITS)
@@ -61,6 +63,8 @@ static inline s64 div_frac(s64 x, s64 y)
  *             Used to calculate the derivative term.
  * @trip_switch_on:    first passive trip point of the thermal zone.  The
  *                     governor switches on when this trip point is crossed.
+ *                     If the thermal zone only has one passive trip point,
+ *                     @trip_switch_on should be INVALID_TRIP.
  * @trip_max_desired_temperature:      last passive trip point of the thermal
  *                                     zone.  The temperature we are
  *                                     controlling for.
@@ -432,43 +436,66 @@ unlock:
        return ret;
 }
 
-static int get_governor_trips(struct thermal_zone_device *tz,
-                             struct power_allocator_params *params)
+/**
+ * get_governor_trips() - get the number of the two trip points that are key for this governor
+ * @tz:        thermal zone to operate on
+ * @params:    pointer to private data for this governor
+ *
+ * The power allocator governor works optimally with two trips points:
+ * a "switch on" trip point and a "maximum desired temperature".  These
+ * are defined as the first and last passive trip points.
+ *
+ * If there is only one trip point, then that's considered to be the
+ * "maximum desired temperature" trip point and the governor is always
+ * on.  If there are no passive or active trip points, then the
+ * governor won't do anything.  In fact, its throttle function
+ * won't be called at all.
+ */
+static void get_governor_trips(struct thermal_zone_device *tz,
+                              struct power_allocator_params *params)
 {
-       int i, ret, last_passive;
+       int i, last_active, last_passive;
        bool found_first_passive;
 
        found_first_passive = false;
-       last_passive = -1;
-       ret = -EINVAL;
+       last_active = INVALID_TRIP;
+       last_passive = INVALID_TRIP;
 
        for (i = 0; i < tz->trips; i++) {
                enum thermal_trip_type type;
+               int ret;
 
                ret = tz->ops->get_trip_type(tz, i, &type);
-               if (ret)
-                       return ret;
+               if (ret) {
+                       dev_warn(&tz->device,
+                                "Failed to get trip point %d type: %d\n", i,
+                                ret);
+                       continue;
+               }
 
-               if (!found_first_passive) {
-                       if (type == THERMAL_TRIP_PASSIVE) {
+               if (type == THERMAL_TRIP_PASSIVE) {
+                       if (!found_first_passive) {
                                params->trip_switch_on = i;
                                found_first_passive = true;
+                       } else  {
+                               last_passive = i;
                        }
-               } else if (type == THERMAL_TRIP_PASSIVE) {
-                       last_passive = i;
+               } else if (type == THERMAL_TRIP_ACTIVE) {
+                       last_active = i;
                } else {
                        break;
                }
        }
 
-       if (last_passive != -1) {
+       if (last_passive != INVALID_TRIP) {
                params->trip_max_desired_temperature = last_passive;
-               ret = 0;
+       } else if (found_first_passive) {
+               params->trip_max_desired_temperature = params->trip_switch_on;
+               params->trip_switch_on = INVALID_TRIP;
        } else {
-               ret = -EINVAL;
+               params->trip_switch_on = INVALID_TRIP;
+               params->trip_max_desired_temperature = last_active;
        }
-
-       return ret;
 }
 
 static void reset_pid_controller(struct power_allocator_params *params)
@@ -497,11 +524,10 @@ static void allow_maximum_power(struct thermal_zone_device *tz)
  * power_allocator_bind() - bind the power_allocator governor to a thermal zone
  * @tz:        thermal zone to bind it to
  *
- * Check that the thermal zone is valid for this governor, that is, it
- * has two thermal trips.  If so, initialize the PID controller
- * parameters and bind it to the thermal zone.
+ * Initialize the PID controller parameters and bind it to the thermal
+ * zone.
  *
- * Return: 0 on success, -EINVAL if the trips were invalid or -ENOMEM
+ * Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM
  * if we ran out of memory.
  */
 static int power_allocator_bind(struct thermal_zone_device *tz)
@@ -520,30 +546,23 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
        if (!tz->tzp->sustainable_power)
                dev_warn(&tz->device, "power_allocator: sustainable_power will be estimated\n");
 
-       ret = get_governor_trips(tz, params);
-       if (ret) {
-               dev_err(&tz->device,
-                       "thermal zone %s has wrong trip setup for power allocator\n",
-                       tz->type);
-               goto free;
-       }
+       get_governor_trips(tz, params);
 
-       ret = tz->ops->get_trip_temp(tz, params->trip_max_desired_temperature,
-                                    &control_temp);
-       if (ret)
-               goto free;
+       if (tz->trips > 0) {
+               ret = tz->ops->get_trip_temp(tz,
+                                       params->trip_max_desired_temperature,
+                                       &control_temp);
+               if (!ret)
+                       estimate_pid_constants(tz, tz->tzp->sustainable_power,
+                                              params->trip_switch_on,
+                                              control_temp, false);
+       }
 
-       estimate_pid_constants(tz, tz->tzp->sustainable_power,
-                              params->trip_switch_on, control_temp, false);
        reset_pid_controller(params);
 
        tz->governor_data = params;
 
        return 0;
-
-free:
-       kfree(params);
-       return ret;
 }
 
 static void power_allocator_unbind(struct thermal_zone_device *tz)
@@ -574,13 +593,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
 
        ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
                                     &switch_on_temp);
-       if (ret) {
-               dev_warn(&tz->device,
-                        "Failed to get switch on temperature: %d\n", ret);
-               return ret;
-       }
-
-       if (current_temp < switch_on_temp) {
+       if (!ret && (current_temp < switch_on_temp)) {
                tz->passive = 0;
                reset_pid_controller(params);
                allow_maximum_power(tz);
This page took 0.029921 seconds and 5 git commands to generate.