--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sched_power
+
+#if !defined(_TRACE_SCHED_POWER_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SCHED_POWER_H
+
+#include <linux/tracepoint.h>
+
+
+TRACE_EVENT(sched_power_set_power,
+ TP_PROTO(int id, int cid, u32 weight, u32 power, unsigned long target,
+ unsigned long state, int ret),
+ TP_ARGS(id, cid, weight, power, target, state, ret),
+ TP_STRUCT__entry(
+ __field(int, id )
+ __field(int, cid )
+ __field(u32, weight )
+ __field(u32, power )
+ __field(unsigned long, target )
+ __field(unsigned long, state )
+ __field(int, ret )
+ ),
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->cid = cid;
+ __entry->weight = weight;
+ __entry->power = power;
+ __entry->target = target;
+ __entry->state = state;
+ __entry->ret = ret;
+ ),
+
+ TP_printk("zone_id=%d cool_id=%d weight=%u power=%u target=%lu state=%lu ret=%d",
+ __entry->id, __entry->cid, __entry->weight,
+ __entry->power, __entry->target, __entry->state, __entry->ret)
+);
+
+TRACE_EVENT(sched_power_calc_budget,
+ TP_PROTO(int id, int temp, s64 power),
+ TP_ARGS(id, temp, power),
+ TP_STRUCT__entry(
+ __field(int, id)
+ __field(int, temp)
+ __field(s32, power)
+ ),
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->temp = temp;
+ __entry->power = power;
+ ),
+
+ TP_printk("zone_id=%d temp=%d power=%d",
+ __entry->id, __entry->temp, __entry->power)
+);
+
+#endif /* _TRACE_SCHED_POWER_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
#include <linux/thermal_core.h>
#include <linux/idle_inject.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/sched_power.h>
+
#include "power.h"
#define THERMAL_REQUEST_KFIFO_SIZE (64 * sizeof(struct power_request))
decay = zone->trip_ctrl_alg.integral >> 3;
zone->trip_ctrl_alg.integral -= decay;
+ trace_sched_power_calc_budget(zone->tz->id, tz->temperature,
+ power_budget);
+
return power_budget;
}
}
static int _set_power(struct _cooling_instance *inst, struct _thermal_zone *zone,
- u32 power)
+ u32 power, unsigned long *state)
{
int ret;
- unsigned long state = 0, target;
+ unsigned long target;
struct thermal_cooling_device *cdev;
struct thermal_zone_device *tz = zone->tz;
ret = cdev->ops->power2state(cdev, tz, power, &target);
if (!ret) {
ret = cooling_dev_set_state(zone, inst->cooling, target,
- &state);
- if (!ret)
- pr_info("inst_weight=%u, set_power=%u, target=%lu, state=%lu, temp=%d\n",
- inst->weight, power, target, state,
- tz->temperature);
- else
- pr_info("_set_power: ret=%d\n, target=%lu, state=%lu\n",
- ret, target, state);
+ state);
+
+ trace_sched_power_set_power(zone->tz->id, cdev->id,
+ inst->weight, power, target, *state,
+ ret);
}
return ret;
return cdev->ops->state2power(cdev, tz, MAX_POWER_STATE_ID, power);
}
+static int _get_power_for_state(struct _cooling_instance *inst,
+ struct _thermal_zone *zone, u32 *power,
+ unsigned long state)
+{
+ struct thermal_cooling_device *cdev;
+ struct thermal_zone_device *tz = zone->tz;
+
+ cdev = inst->cooling->cdev;
+ return cdev->ops->state2power(cdev, tz, state, power);
+}
+
static int share_power_budget(struct _thermal_zone *zone, u32 power_budget)
{
struct _cooling_instance *inst;
u64 left_power_budget = power_budget;
int i = 0;
int ret;
+ unsigned long state = 0;
+ int rebalance = 0;
power = kzalloc(sizeof(struct power_info) * zone->num_cooling,
GFP_KERNEL);
if (!power)
return -ENOMEM;
+try_balance:
+ if (rebalance > MAX_REBALANCE_TRIES_POWER_BUDGET)
+ goto balanced;
/* 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) {
p = &power[i];
ret = _get_requested_power(inst, zone, &p->requested);
- ret = _get_max_power(inst, zone, &p->max_possible);
+ if (!rebalance)
+ ret = _get_max_power(inst, zone, &p->max_possible);
/* pr_info("req=%u\n", p->requested); */
i++;
}
i = 0;
list_for_each_entry(inst, &zone->cooling_list, node) {
p = &power[i];
- ret = _set_power(inst, zone, p->requested);
+ ret = _set_power(inst, zone, p->requested, &state);
if (ret) {
/* TODO: collect power which cannot be used for other
* devices */
+ rebalance++;
extra_power += p->requested;
p->requested = 0;
+ ret = _get_power_for_state(inst, zone, &p->max_possible,
+ state);
}
i++;
}
+ if (rebalance)
+ goto try_balance;
+
+balanced:
kfree(power);
return 0;