#include "sched.h"
 
+#include <linux/sched/cpufreq.h>
 #include <trace/events/power.h>
 
 struct sugov_tunables {
        unsigned int freq = arch_scale_freq_invariant() ?
                                policy->cpuinfo.max_freq : policy->cur;
 
-       freq = (freq + (freq >> 2)) * util / max;
+       freq = map_util_freq(util, freq, max);
 
        if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update)
                return sg_policy->next_freq;
  * based on the task model parameters and gives the minimal utilization
  * required to meet deadlines.
  */
-static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu)
+unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs,
+                                 unsigned long max, enum schedutil_type type)
 {
-       struct rq *rq = cpu_rq(sg_cpu->cpu);
-       unsigned long util, irq, max;
+       unsigned long dl_util, util, irq;
+       struct rq *rq = cpu_rq(cpu);
 
-       sg_cpu->max = max = arch_scale_cpu_capacity(NULL, sg_cpu->cpu);
-       sg_cpu->bw_dl = cpu_bw_dl(rq);
-
-       if (rt_rq_is_runnable(&rq->rt))
+       if (type == FREQUENCY_UTIL && rt_rq_is_runnable(&rq->rt))
                return max;
 
        /*
         * utilization (PELT windows are synchronized) we can directly add them
         * to obtain the CPU's actual utilization.
         */
-       util = cpu_util_cfs(rq);
+       util = util_cfs;
        util += cpu_util_rt(rq);
 
+       dl_util = cpu_util_dl(rq);
+
        /*
-        * We do not make cpu_util_dl() a permanent part of this sum because we
-        * want to use cpu_bw_dl() later on, but we need to check if the
-        * CFS+RT+DL sum is saturated (ie. no idle time) such that we select
-        * f_max when there is no idle time.
+        * For frequency selection we do not make cpu_util_dl() a permanent part
+        * of this sum because we want to use cpu_bw_dl() later on, but we need
+        * to check if the CFS+RT+DL sum is saturated (ie. no idle time) such
+        * that we select f_max when there is no idle time.
         *
         * NOTE: numerical errors or stop class might cause us to not quite hit
         * saturation when we should -- something for later.
         */
-       if ((util + cpu_util_dl(rq)) >= max)
+       if (util + dl_util >= max)
                return max;
 
+       /*
+        * OTOH, for energy computation we need the estimated running time, so
+        * include util_dl and ignore dl_bw.
+        */
+       if (type == ENERGY_UTIL)
+               util += dl_util;
+
        /*
         * There is still idle time; further improve the number by using the
         * irq metric. Because IRQ/steal time is hidden from the task clock we
         * bw_dl as requested freq. However, cpufreq is not yet ready for such
         * an interface. So, we only do the latter for now.
         */
-       return min(max, util + sg_cpu->bw_dl);
+       if (type == FREQUENCY_UTIL)
+               util += cpu_bw_dl(rq);
+
+       return min(max, util);
+}
+
+static unsigned long sugov_get_util(struct sugov_cpu *sg_cpu)
+{
+       struct rq *rq = cpu_rq(sg_cpu->cpu);
+       unsigned long util = cpu_util_cfs(rq);
+       unsigned long max = arch_scale_cpu_capacity(NULL, sg_cpu->cpu);
+
+       sg_cpu->max = max;
+       sg_cpu->bw_dl = cpu_bw_dl(rq);
+
+       return schedutil_freq_util(sg_cpu->cpu, util, max, FREQUENCY_UTIL);
 }
 
 /**
 
 #endif
 
 #ifdef CONFIG_CPU_FREQ_GOV_SCHEDUTIL
+/**
+ * enum schedutil_type - CPU utilization type
+ * @FREQUENCY_UTIL:    Utilization used to select frequency
+ * @ENERGY_UTIL:       Utilization used during energy calculation
+ *
+ * The utilization signals of all scheduling classes (CFS/RT/DL) and IRQ time
+ * need to be aggregated differently depending on the usage made of them. This
+ * enum is used within schedutil_freq_util() to differentiate the types of
+ * utilization expected by the callers, and adjust the aggregation accordingly.
+ */
+enum schedutil_type {
+       FREQUENCY_UTIL,
+       ENERGY_UTIL,
+};
+
+unsigned long schedutil_freq_util(int cpu, unsigned long util_cfs,
+                                 unsigned long max, enum schedutil_type type);
+
+static inline unsigned long schedutil_energy_util(int cpu, unsigned long cfs)
+{
+       unsigned long max = arch_scale_cpu_capacity(NULL, cpu);
+
+       return schedutil_freq_util(cpu, cfs, max, ENERGY_UTIL);
+}
+
 static inline unsigned long cpu_bw_dl(struct rq *rq)
 {
        return (rq->dl.running_bw * SCHED_CAPACITY_SCALE) >> BW_SHIFT;
 {
        return READ_ONCE(rq->avg_rt.util_avg);
 }
+#else /* CONFIG_CPU_FREQ_GOV_SCHEDUTIL */
+static inline unsigned long schedutil_energy_util(int cpu, unsigned long cfs)
+{
+       return cfs;
+}
 #endif
 
 #ifdef CONFIG_HAVE_SCHED_AVG_IRQ