[PATCH v7 10/15] thermal: devfreq_cooling: get device load and frequency directly
From: Lukasz Luba
Date: Mon May 11 2020 - 07:21:25 EST
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.luba@xxxxxxx>
---
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