cpufreq: interactive: Round up timer_rate to match jiffy
[firefly-linux-kernel-4.4.55.git] / drivers / cpufreq / cpufreq_interactive.c
index a0a7c3aef859a4ac003dd8a91ace0fb96ab21169..6bbcc905bb3e71561cd6d22ea4fd61a7558e5871 100644 (file)
@@ -105,6 +105,7 @@ struct cpufreq_interactive_tunables {
        int boostpulse_duration_val;
        /* End time of boost pulse in ktime converted to usecs */
        u64 boostpulse_endtime;
+       bool boosted;
        /*
         * Max additional time to wait in idle, beyond timer_rate, at speeds
         * above minimum before wakeup to reduce speed, or -1 if unnecessary.
@@ -344,7 +345,6 @@ static void cpufreq_interactive_timer(unsigned long data)
        unsigned int loadadjfreq;
        unsigned int index;
        unsigned long flags;
-       bool boosted;
 
        if (!down_read_trylock(&pcpu->enable_sem))
                return;
@@ -364,9 +364,9 @@ static void cpufreq_interactive_timer(unsigned long data)
        do_div(cputime_speedadj, delta_time);
        loadadjfreq = (unsigned int)cputime_speedadj * 100;
        cpu_load = loadadjfreq / pcpu->target_freq;
-       boosted = tunables->boost_val || now < tunables->boostpulse_endtime;
+       tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime;
 
-       if (cpu_load >= tunables->go_hispeed_load || boosted) {
+       if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) {
                if (pcpu->target_freq < tunables->hispeed_freq) {
                        new_freq = tunables->hispeed_freq;
                } else {
@@ -427,12 +427,13 @@ static void cpufreq_interactive_timer(unsigned long data)
         * (or the indefinite boost is turned off).
         */
 
-       if (!boosted || new_freq > tunables->hispeed_freq) {
+       if (!tunables->boosted || new_freq > tunables->hispeed_freq) {
                pcpu->floor_freq = new_freq;
                pcpu->floor_validate_time = now;
        }
 
-       if (pcpu->target_freq == new_freq) {
+       if (pcpu->target_freq == new_freq &&
+                       pcpu->target_freq <= pcpu->policy->cur) {
                trace_cpufreq_interactive_already(
                        data, cpu_load, pcpu->target_freq,
                        pcpu->policy->cur, new_freq);
@@ -584,19 +585,21 @@ static int cpufreq_interactive_speedchange_task(void *data)
        return 0;
 }
 
-static void cpufreq_interactive_boost(void)
+static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunables)
 {
        int i;
        int anyboost = 0;
        unsigned long flags[2];
        struct cpufreq_interactive_cpuinfo *pcpu;
-       struct cpufreq_interactive_tunables *tunables;
+
+       tunables->boosted = true;
 
        spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]);
 
        for_each_online_cpu(i) {
                pcpu = &per_cpu(cpuinfo, i);
-               tunables = pcpu->policy->governor_data;
+               if (tunables != pcpu->policy->governor_data)
+                       continue;
 
                spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]);
                if (pcpu->target_freq < tunables->hispeed_freq) {
@@ -606,14 +609,6 @@ static void cpufreq_interactive_boost(void)
                                ktime_to_us(ktime_get());
                        anyboost = 1;
                }
-
-               /*
-                * Set floor freq and (re)start timer for when last
-                * validated.
-                */
-
-               pcpu->floor_freq = tunables->hispeed_freq;
-               pcpu->floor_validate_time = ktime_to_us(ktime_get());
                spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]);
        }
 
@@ -860,12 +855,18 @@ static ssize_t store_timer_rate(struct cpufreq_interactive_tunables *tunables,
                const char *buf, size_t count)
 {
        int ret;
-       unsigned long val;
+       unsigned long val, val_round;
 
        ret = strict_strtoul(buf, 0, &val);
        if (ret < 0)
                return ret;
-       tunables->timer_rate = val;
+
+       val_round = jiffies_to_usecs(usecs_to_jiffies(val));
+       if (val != val_round)
+               pr_warn("timer_rate not aligned to jiffy. Rounded up to %lu\n",
+                       val_round);
+
+       tunables->timer_rate = val_round;
        return count;
 }
 
@@ -909,7 +910,8 @@ static ssize_t store_boost(struct cpufreq_interactive_tunables *tunables,
 
        if (tunables->boost_val) {
                trace_cpufreq_interactive_boost("on");
-               cpufreq_interactive_boost();
+               if (!tunables->boosted)
+                       cpufreq_interactive_boost(tunables);
        } else {
                tunables->boostpulse_endtime = ktime_to_us(ktime_get());
                trace_cpufreq_interactive_unboost("off");
@@ -931,7 +933,8 @@ static ssize_t store_boostpulse(struct cpufreq_interactive_tunables *tunables,
        tunables->boostpulse_endtime = ktime_to_us(ktime_get()) +
                tunables->boostpulse_duration_val;
        trace_cpufreq_interactive_boost("pulse");
-       cpufreq_interactive_boost();
+       if (!tunables->boosted)
+               cpufreq_interactive_boost(tunables);
        return count;
 }
 
@@ -1180,8 +1183,10 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
                if (rc) {
                        kfree(tunables);
                        policy->governor_data = NULL;
-                       if (!have_governor_per_policy())
+                       if (!have_governor_per_policy()) {
                                common_tunables = NULL;
+                               cpufreq_put_global_kobject();
+                       }
                        return rc;
                }