diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index b0e4506f2cae126dde8bf3cfef255f66caa61add..ee8b7cac11f3dbadb9763d1ca0e99ed3c39da992 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -290,6 +290,9 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data, mutex_unlock(&dbs_data->mutex); if (dbs_sw_coordinated_cpus(cpu_cdbs)) { + /* Initiate timer time stamp */ + cpu_cdbs->time_stamp = ktime_get(); + for_each_cpu(j, policy->cpus) { struct cpu_dbs_common_info *j_cdbs; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 5bf6fb8023efde98ff83c7aa367e564c546b5439..aaf073daa9fb30eb9db14921a2d53917ac29ab4e 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -82,6 +82,7 @@ struct cpu_dbs_common_info { * the governor or limits. */ struct mutex timer_mutex; + ktime_t time_stamp; }; struct od_cpu_dbs_info_s { diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 93bb56d14cfaf2c4e8ecc8f7e52dd02664a62b67..13ceb3c69b64760703e64ddfbc7403a3f43a4c36 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -216,23 +216,23 @@ static void od_check_cpu(int cpu, unsigned int load_freq) } } -static void od_dbs_timer(struct work_struct *work) +static void od_timer_update(struct od_cpu_dbs_info_s *dbs_info, bool sample, + struct delayed_work *dw) { - struct od_cpu_dbs_info_s *dbs_info = - container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work); unsigned int cpu = dbs_info->cdbs.cpu; int delay, sample_type = dbs_info->sample_type; - mutex_lock(&dbs_info->cdbs.timer_mutex); - /* Common NORMAL_SAMPLE setup */ dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { delay = dbs_info->freq_lo_jiffies; - __cpufreq_driver_target(dbs_info->cdbs.cur_policy, - dbs_info->freq_lo, CPUFREQ_RELATION_H); + if (sample) + __cpufreq_driver_target(dbs_info->cdbs.cur_policy, + dbs_info->freq_lo, + CPUFREQ_RELATION_H); } else { - dbs_check_cpu(&od_dbs_data, cpu); + if (sample) + dbs_check_cpu(&od_dbs_data, cpu); if (dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ dbs_info->sample_type = OD_SUB_SAMPLE; @@ -243,11 +243,49 @@ static void od_dbs_timer(struct work_struct *work) } } - schedule_delayed_work_on(smp_processor_id(), &dbs_info->cdbs.work, - delay); + schedule_delayed_work_on(smp_processor_id(), dw, delay); +} + +static void od_timer_coordinated(struct od_cpu_dbs_info_s *dbs_info_local, + struct delayed_work *dw) +{ + struct od_cpu_dbs_info_s *dbs_info; + ktime_t time_now; + s64 delta_us; + bool sample = true; + + /* use leader CPU's dbs_info */ + dbs_info = &per_cpu(od_cpu_dbs_info, dbs_info_local->cdbs.cpu); + mutex_lock(&dbs_info->cdbs.timer_mutex); + + time_now = ktime_get(); + delta_us = ktime_us_delta(time_now, dbs_info->cdbs.time_stamp); + + /* Do nothing if we recently have sampled */ + if (delta_us < (s64)(od_tuners.sampling_rate / 2)) + sample = false; + else + dbs_info->cdbs.time_stamp = time_now; + + od_timer_update(dbs_info, sample, dw); mutex_unlock(&dbs_info->cdbs.timer_mutex); } +static void od_dbs_timer(struct work_struct *work) +{ + struct delayed_work *dw = to_delayed_work(work); + struct od_cpu_dbs_info_s *dbs_info = + container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work); + + if (dbs_sw_coordinated_cpus(&dbs_info->cdbs)) { + od_timer_coordinated(dbs_info, dw); + } else { + mutex_lock(&dbs_info->cdbs.timer_mutex); + od_timer_update(dbs_info, true, dw); + mutex_unlock(&dbs_info->cdbs.timer_mutex); + } +} + /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_min(struct kobject *kobj,