return 0;
}
-static int set_power(struct _cooling_instance *inst, struct _thermal_zone *zone,
+static int _set_power(struct _cooling_instance *inst, struct _thermal_zone *zone,
u32 power)
{
int ret;
return ret;
}
-static int get_requested_power(struct _cooling_instance *inst,
+static int _get_requested_power(struct _cooling_instance *inst,
struct _thermal_zone *zone, u32 *power)
{
struct thermal_cooling_device *cdev;
return cdev->ops->get_requested_power(cdev, tz, power);
}
+static int _get_max_power(struct _cooling_instance *inst,
+ struct _thermal_zone *zone, u32 *power)
+{
+ struct thermal_cooling_device *cdev;
+ struct thermal_zone_device *tz = zone->tz;
+
+ cdev = inst->cooling->cdev;
+ return cdev->ops->state2power(cdev, tz, MAX_POWER_STATE_ID, power);
+}
+
static int share_power_budget(struct _thermal_zone *zone, u32 power_budget)
{
struct _cooling_instance *inst;
- u32 *power;
+ struct power_info *power, *p;
u64 sum_power = 0;
+ u64 extra_power = 0;
+ u64 wish_power = 0;
+ u64 total_weight = 0;
+ u64 left_power_budget = power_budget;
int i = 0;
+ int ret;
- power = kzalloc(sizeof(u32) * zone->num_cooling, GFP_KERNEL);
+ power = kzalloc(sizeof(struct power_info) * zone->num_cooling,
+ GFP_KERNEL);
if (!power)
return -ENOMEM;
/* The calculation two-loops split is needed due to taking
zone->lock only for protecting 'weights'. */
list_for_each_entry(inst, &zone->cooling_list, node) {
- get_requested_power(inst, zone, &power[i]);
+ p = &power[i];
+ ret = _get_requested_power(inst, zone, &p->requested);
+ ret = _get_max_power(inst, zone, &p->max_possible);
+ /* pr_info("req=%u\n", p->requested); */
i++;
}
/* estimate cooling dev's power and total power */
i = 0;
list_for_each_entry(inst, &zone->cooling_list, node) {
- power[i] = (inst->weight * power[i]) >> 10;
- sum_power += power[i];
+ p = &power[i];
+ p->requested = (inst->weight * p->requested) >> 10;
+ sum_power += p->requested;
+ total_weight += inst->weight;
+ /* pr_info("req=%u\n", p->requested); */
i++;
}
mutex_unlock(&zone->lock);
/* split power budget to cooling devices */
i = 0;
list_for_each_entry(inst, &zone->cooling_list, node) {
- power[i] = (power[i] * power_budget) / sum_power;
+ p = &power[i];
+ p->requested = (p->requested * power_budget) / sum_power;
+ /* pr_info("req=%u max=%u\n", p->requested, p->max_possible); */
+ if (p->requested > p->max_possible) {
+ extra_power += p->requested - p->max_possible;
+ p->requested = p->max_possible;
+ }
+ wish_power += p->max_possible - p->requested;
+ left_power_budget -= p->requested;
i++;
}
- /* clamp max possible power for devices and re-share the rest */
+ /* re-share the rest extra power to devices according to their wish and
+ * weight*/
+ if ((extra_power || left_power_budget) && wish_power) {
+ u32 headroom;
+ extra_power = max(left_power_budget, extra_power);
+ extra_power = min(wish_power, extra_power);
+
+ i = 0;
+ list_for_each_entry(inst, &zone->cooling_list, node) {
+ p = &power[i];
+ headroom = p->max_possible - p->requested;
+ /* headroom *= inst->weight; */
+ /* headroom /= total_weight; */
+ p->requested += (headroom * extra_power) / wish_power;
+ /* pr_info("req=%u\n", p->requested); */
+ i++;
+ }
+ }
+
/* set the new state for cooling device based on its granted power */
i = 0;
list_for_each_entry(inst, &zone->cooling_list, node) {
- set_power(inst, zone, power[i]);
+ p = &power[i];
+ _set_power(inst, zone, p->requested);
i++;
}