thermal: devfreq_cooling: use a copy of device status
[sfrench/cifs-2.6.git] / drivers / thermal / devfreq_cooling.c
index 659c0143c9f0a1943c3cda1e034a35d8ea497e72..afcebadbad242d698fc75f686e07ed2c21256cac 100644 (file)
@@ -227,20 +227,39 @@ static inline unsigned long get_total_power(struct devfreq_cooling_device *dfc,
                                                               voltage);
 }
 
+static void _normalize_load(struct devfreq_dev_status *status)
+{
+       if (status->total_time > 0xfffff) {
+               status->total_time >>= 10;
+               status->busy_time >>= 10;
+       }
+
+       status->busy_time <<= 10;
+       status->busy_time /= status->total_time ? : 1;
+
+       status->busy_time = status->busy_time ? : 1;
+       status->total_time = 1024;
+}
 
 static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev,
                                               u32 *power)
 {
        struct devfreq_cooling_device *dfc = cdev->devdata;
        struct devfreq *df = dfc->devfreq;
-       struct devfreq_dev_status *status = &df->last_status;
+       struct devfreq_dev_status status;
        unsigned long state;
-       unsigned long freq = status->current_frequency;
+       unsigned long freq;
        unsigned long voltage;
        u32 dyn_power = 0;
        u32 static_power = 0;
        int res;
 
+       mutex_lock(&df->lock);
+       status = df->last_status;
+       mutex_unlock(&df->lock);
+
+       freq = status.current_frequency;
+
        state = freq_get_state(dfc, freq);
        if (state == THERMAL_CSTATE_INVALID) {
                res = -EAGAIN;
@@ -268,16 +287,18 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd
        } else {
                dyn_power = dfc->power_table[state];
 
+               _normalize_load(&status);
+
                /* Scale dynamic power for utilization */
-               dyn_power *= status->busy_time;
-               dyn_power /= status->total_time;
+               dyn_power *= status.busy_time;
+               dyn_power >>= 10;
                /* Get static power */
                static_power = get_static_power(dfc, freq);
 
                *power = dyn_power + static_power;
        }
 
-       trace_thermal_power_devfreq_get_power(cdev, status, freq, *power);
+       trace_thermal_power_devfreq_get_power(cdev, &status, freq, *power);
 
        return 0;
 fail:
@@ -309,14 +330,19 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
 {
        struct devfreq_cooling_device *dfc = cdev->devdata;
        struct devfreq *df = dfc->devfreq;
-       struct devfreq_dev_status *status = &df->last_status;
-       unsigned long freq = status->current_frequency;
-       unsigned long busy_time;
+       struct devfreq_dev_status status;
+       unsigned long freq;
        s32 dyn_power;
        u32 static_power;
        s32 est_power;
        int i;
 
+       mutex_lock(&df->lock);
+       status = df->last_status;
+       mutex_unlock(&df->lock);
+
+       freq = status.current_frequency;
+
        if (dfc->power_ops->get_real_power) {
                /* Scale for resource utilization */
                est_power = power * dfc->res_util;
@@ -328,8 +354,9 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
                dyn_power = dyn_power > 0 ? dyn_power : 0;
 
                /* Scale dynamic power for utilization */
-               busy_time = status->busy_time ?: 1;
-               est_power = (dyn_power * status->total_time) / busy_time;
+               _normalize_load(&status);
+               dyn_power <<= 10;
+               est_power = dyn_power / status.busy_time;
        }
 
        /*