Devfreq cooling needs to now the correct status of the device in order
to operate. Do not rely on Devfreq last_status which might be a stale data
and get more up-to-date values of load and frequency.

In addition this patch adds normalization function, which also makes sure
that whatever data comes from the device, it is in a sane range.

Signed-off-by: Lukasz Luba <lukasz.l...@arm.com>
---
 drivers/thermal/devfreq_cooling.c | 38 +++++++++++++++++++++++++++----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/thermal/devfreq_cooling.c 
b/drivers/thermal/devfreq_cooling.c
index 52694d4bd819..396f16bb6566 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -235,6 +235,24 @@ static inline unsigned long get_total_power(struct 
devfreq_cooling_device *dfc,
                                                               voltage);
 }
 
+static void _normalize_load(struct devfreq_dev_status *status)
+{
+       /* Make some space if needed */
+       if (status->busy_time > 0xffff) {
+               status->busy_time >>= 10;
+               status->total_time >>= 10;
+       }
+
+       if (status->busy_time > status->total_time)
+               status->busy_time = status->total_time;
+
+       status->busy_time *= 100;
+       status->busy_time /= status->total_time ? : 1;
+
+       /* Avoid division by 0 */
+       status->busy_time = status->busy_time ? : 1;
+       status->total_time = 100;
+}
 
 static int devfreq_cooling_get_requested_power(struct thermal_cooling_device 
*cdev,
                                               struct thermal_zone_device *tz,
@@ -242,14 +260,22 @@ static int devfreq_cooling_get_requested_power(struct 
thermal_cooling_device *cd
 {
        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);
+       res = df->profile->get_dev_status(df->dev.parent, &status);
+       mutex_unlock(&df->lock);
+       if (res)
+               return res;
+
+       freq = status.current_frequency;
+
        state = freq_get_state(dfc, freq);
        if (state == THERMAL_CSTATE_INVALID) {
                res = -EAGAIN;
@@ -277,16 +303,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 /= status.total_time;
                /* 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:
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to