Merge branches 'acpica', 'acpi-video' and 'acpi-fan'
[linux-2.6-block.git] / drivers / cpufreq / intel_pstate.c
index 98fb8821382d8fc145c6bf9227b62236fdabedb1..cd83d477e32d412394da574e8e02adb6dd7be832 100644 (file)
@@ -66,6 +66,7 @@ static inline int ceiling_fp(int32_t x)
 
 struct sample {
        int32_t core_pct_busy;
+       int32_t busy_scaled;
        u64 aperf;
        u64 mperf;
        u64 tsc;
@@ -112,6 +113,7 @@ struct cpudata {
        u64     prev_aperf;
        u64     prev_mperf;
        u64     prev_tsc;
+       u64     prev_cummulative_iowait;
        struct sample sample;
 };
 
@@ -133,6 +135,7 @@ struct pstate_funcs {
        int (*get_scaling)(void);
        void (*set)(struct cpudata*, int pstate);
        void (*get_vid)(struct cpudata *);
+       int32_t (*get_target_pstate)(struct cpudata *);
 };
 
 struct cpu_defaults {
@@ -140,6 +143,9 @@ struct cpu_defaults {
        struct pstate_funcs funcs;
 };
 
+static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu);
+static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu);
+
 static struct pstate_adjust_policy pid_params;
 static struct pstate_funcs pstate_funcs;
 static int hwp_active;
@@ -738,6 +744,7 @@ static struct cpu_defaults core_params = {
                .get_turbo = core_get_turbo_pstate,
                .get_scaling = core_get_scaling,
                .set = core_set_pstate,
+               .get_target_pstate = get_target_pstate_use_performance,
        },
 };
 
@@ -758,6 +765,7 @@ static struct cpu_defaults silvermont_params = {
                .set = atom_set_pstate,
                .get_scaling = silvermont_get_scaling,
                .get_vid = atom_get_vid,
+               .get_target_pstate = get_target_pstate_use_cpu_load,
        },
 };
 
@@ -778,6 +786,7 @@ static struct cpu_defaults airmont_params = {
                .set = atom_set_pstate,
                .get_scaling = airmont_get_scaling,
                .get_vid = atom_get_vid,
+               .get_target_pstate = get_target_pstate_use_cpu_load,
        },
 };
 
@@ -797,6 +806,7 @@ static struct cpu_defaults knl_params = {
                .get_turbo = knl_get_turbo_pstate,
                .get_scaling = core_get_scaling,
                .set = core_set_pstate,
+               .get_target_pstate = get_target_pstate_use_performance,
        },
 };
 
@@ -882,12 +892,11 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
        local_irq_save(flags);
        rdmsrl(MSR_IA32_APERF, aperf);
        rdmsrl(MSR_IA32_MPERF, mperf);
-       if (cpu->prev_mperf == mperf) {
+       tsc = rdtsc();
+       if ((cpu->prev_mperf == mperf) || (cpu->prev_tsc == tsc)) {
                local_irq_restore(flags);
                return;
        }
-
-       tsc = rdtsc();
        local_irq_restore(flags);
 
        cpu->last_sample_time = cpu->sample.time;
@@ -922,7 +931,43 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
        mod_timer_pinned(&cpu->timer, jiffies + delay);
 }
 
-static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
+static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
+{
+       struct sample *sample = &cpu->sample;
+       u64 cummulative_iowait, delta_iowait_us;
+       u64 delta_iowait_mperf;
+       u64 mperf, now;
+       int32_t cpu_load;
+
+       cummulative_iowait = get_cpu_iowait_time_us(cpu->cpu, &now);
+
+       /*
+        * Convert iowait time into number of IO cycles spent at max_freq.
+        * IO is considered as busy only for the cpu_load algorithm. For
+        * performance this is not needed since we always try to reach the
+        * maximum P-State, so we are already boosting the IOs.
+        */
+       delta_iowait_us = cummulative_iowait - cpu->prev_cummulative_iowait;
+       delta_iowait_mperf = div64_u64(delta_iowait_us * cpu->pstate.scaling *
+               cpu->pstate.max_pstate, MSEC_PER_SEC);
+
+       mperf = cpu->sample.mperf + delta_iowait_mperf;
+       cpu->prev_cummulative_iowait = cummulative_iowait;
+
+
+       /*
+        * The load can be estimated as the ratio of the mperf counter
+        * running at a constant frequency during active periods
+        * (C0) and the time stamp counter running at the same frequency
+        * also during C-states.
+        */
+       cpu_load = div64_u64(int_tofp(100) * mperf, sample->tsc);
+       cpu->sample.busy_scaled = cpu_load;
+
+       return cpu->pstate.current_pstate - pid_calc(&cpu->pid, cpu_load);
+}
+
+static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
 {
        int32_t core_busy, max_pstate, current_pstate, sample_ratio;
        s64 duration_us;
@@ -960,30 +1005,24 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
                core_busy = mul_fp(core_busy, sample_ratio);
        }
 
-       return core_busy;
+       cpu->sample.busy_scaled = core_busy;
+       return cpu->pstate.current_pstate - pid_calc(&cpu->pid, core_busy);
 }
 
 static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
 {
-       int32_t busy_scaled;
-       struct _pid *pid;
-       signed int ctl;
-       int from;
+       int from, target_pstate;
        struct sample *sample;
 
        from = cpu->pstate.current_pstate;
 
-       pid = &cpu->pid;
-       busy_scaled = intel_pstate_get_scaled_busy(cpu);
+       target_pstate = pstate_funcs.get_target_pstate(cpu);
 
-       ctl = pid_calc(pid, busy_scaled);
-
-       /* Negative values of ctl increase the pstate and vice versa */
-       intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl, true);
+       intel_pstate_set_pstate(cpu, target_pstate, true);
 
        sample = &cpu->sample;
        trace_pstate_sample(fp_toint(sample->core_pct_busy),
-               fp_toint(busy_scaled),
+               fp_toint(sample->busy_scaled),
                from,
                cpu->pstate.current_pstate,
                sample->mperf,
@@ -1237,6 +1276,8 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
        pstate_funcs.get_scaling = funcs->get_scaling;
        pstate_funcs.set       = funcs->set;
        pstate_funcs.get_vid   = funcs->get_vid;
+       pstate_funcs.get_target_pstate = funcs->get_target_pstate;
+
 }
 
 #if IS_ENABLED(CONFIG_ACPI)