diff options
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/Kconfig | 2 | ||||
-rw-r--r-- | drivers/cpufreq/Kconfig.arm | 15 | ||||
-rw-r--r-- | drivers/cpufreq/arm_big_little.c | 7 | ||||
-rw-r--r-- | drivers/cpufreq/arm_big_little.h | 5 | ||||
-rw-r--r-- | drivers/cpufreq/arm_big_little_dt.c | 9 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-cpu0.c | 27 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 10 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_governor.c | 11 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_governor.h | 1 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_ondemand.c | 1 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_stats.c | 7 | ||||
-rw-r--r-- | drivers/cpufreq/intel_pstate.c | 122 | ||||
-rw-r--r-- | drivers/cpufreq/kirkwood-cpufreq.c | 4 |
13 files changed, 77 insertions, 144 deletions
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index a1488f58f6ca..534fcb825153 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -47,7 +47,7 @@ config CPU_FREQ_STAT_DETAILS choice prompt "Default CPUFreq governor" - default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 + default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ default CPU_FREQ_DEFAULT_GOV_PERFORMANCE help This option sets which CPUFreq governor shall be loaded at diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index f3af18b9acc5..6e57543fe0b9 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -3,16 +3,17 @@ # config ARM_BIG_LITTLE_CPUFREQ - tristate - depends on ARM_CPU_TOPOLOGY + tristate "Generic ARM big LITTLE CPUfreq driver" + depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK + help + This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. config ARM_DT_BL_CPUFREQ - tristate "Generic ARM big LITTLE CPUfreq driver probed via DT" - select ARM_BIG_LITTLE_CPUFREQ - depends on OF && HAVE_CLK + tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver" + depends on ARM_BIG_LITTLE_CPUFREQ && OF help - This enables the Generic CPUfreq driver for ARM big.LITTLE platform. - This gets frequency tables from DT. + This enables probing via DT for Generic CPUfreq driver for ARM + big.LITTLE platform. This gets frequency tables from DT. config ARM_EXYNOS_CPUFREQ bool "SAMSUNG EXYNOS SoCs" diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index dbdf677d2f36..5d7f53fcd6f5 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -40,11 +40,6 @@ static struct clk *clk[MAX_CLUSTERS]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS]; static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)}; -static int cpu_to_cluster(int cpu) -{ - return topology_physical_package_id(cpu); -} - static unsigned int bL_cpufreq_get(unsigned int cpu) { u32 cur_cluster = cpu_to_cluster(cpu); @@ -192,7 +187,7 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); - dev_info(cpu_dev, "CPU %d initialized\n", policy->cpu); + dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu); return 0; } diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h index 70f18fc12d4a..79b2ce17884d 100644 --- a/drivers/cpufreq/arm_big_little.h +++ b/drivers/cpufreq/arm_big_little.h @@ -34,6 +34,11 @@ struct cpufreq_arm_bL_ops { int (*init_opp_table)(struct device *cpu_dev); }; +static inline int cpu_to_cluster(int cpu) +{ + return topology_physical_package_id(cpu); +} + int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops); diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c index 44be3115375c..173ed059d95f 100644 --- a/drivers/cpufreq/arm_big_little_dt.c +++ b/drivers/cpufreq/arm_big_little_dt.c @@ -66,8 +66,8 @@ static int dt_get_transition_latency(struct device *cpu_dev) parent = of_find_node_by_path("/cpus"); if (!parent) { - pr_err("failed to find OF /cpus\n"); - return -ENOENT; + pr_info("Failed to find OF /cpus. Use CPUFREQ_ETERNAL transition latency\n"); + return CPUFREQ_ETERNAL; } for_each_child_of_node(parent, np) { @@ -78,10 +78,11 @@ static int dt_get_transition_latency(struct device *cpu_dev) of_node_put(np); of_node_put(parent); - return 0; + return transition_latency; } - return -ENODEV; + pr_info("clock-latency isn't found, use CPUFREQ_ETERNAL transition latency\n"); + return CPUFREQ_ETERNAL; } static struct cpufreq_arm_bL_ops dt_bL_ops = { diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index 3ab8294eab04..a64eb8b70444 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -189,12 +189,29 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) if (!np) { pr_err("failed to find cpu0 node\n"); - return -ENOENT; + ret = -ENOENT; + goto out_put_parent; } cpu_dev = &pdev->dev; cpu_dev->of_node = np; + cpu_reg = devm_regulator_get(cpu_dev, "cpu0"); + if (IS_ERR(cpu_reg)) { + /* + * If cpu0 regulator supply node is present, but regulator is + * not yet registered, we should try defering probe. + */ + if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) { + dev_err(cpu_dev, "cpu0 regulator not ready, retry\n"); + ret = -EPROBE_DEFER; + goto out_put_node; + } + pr_warn("failed to get cpu0 regulator: %ld\n", + PTR_ERR(cpu_reg)); + cpu_reg = NULL; + } + cpu_clk = devm_clk_get(cpu_dev, NULL); if (IS_ERR(cpu_clk)) { ret = PTR_ERR(cpu_clk); @@ -202,12 +219,6 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) goto out_put_node; } - cpu_reg = devm_regulator_get(cpu_dev, "cpu0"); - if (IS_ERR(cpu_reg)) { - pr_warn("failed to get cpu0 regulator\n"); - cpu_reg = NULL; - } - ret = of_init_opp_table(cpu_dev); if (ret) { pr_err("failed to init OPP table: %d\n", ret); @@ -264,6 +275,8 @@ out_free_table: opp_free_cpufreq_table(cpu_dev, &freq_table); out_put_node: of_node_put(np); +out_put_parent: + of_node_put(parent); return ret; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1b8a48eaf90f..4b8c7f297d74 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1075,14 +1075,14 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif __func__, cpu_dev->id, cpu); } + if ((cpus == 1) && (cpufreq_driver->target)) + __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); + pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); cpufreq_cpu_put(data); /* If cpu is last user of policy, free policy */ if (cpus == 1) { - if (cpufreq_driver->target) - __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); - lock_policy_rwsem_read(cpu); kobj = &data->kobj; cmp = &data->kobj_unregister; @@ -1832,15 +1832,13 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb, if (dev) { switch (action) { case CPU_ONLINE: - case CPU_ONLINE_FROZEN: cpufreq_add_dev(dev, NULL); break; case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: + case CPU_UP_CANCELED_FROZEN: __cpufreq_remove_dev(dev, NULL); break; case CPU_DOWN_FAILED: - case CPU_DOWN_FAILED_FROZEN: cpufreq_add_dev(dev, NULL); break; } diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 443442df113b..5af40ad82d23 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -255,6 +255,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, if (have_governor_per_policy()) { WARN_ON(dbs_data); } else if (dbs_data) { + dbs_data->usage_count++; policy->governor_data = dbs_data; return 0; } @@ -266,6 +267,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, } dbs_data->cdata = cdata; + dbs_data->usage_count = 1; rc = cdata->init(dbs_data); if (rc) { pr_err("%s: POLICY_INIT: init() failed\n", __func__); @@ -294,7 +296,8 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate, latency * LATENCY_MULTIPLIER)); - if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { + if ((cdata->governor == GOV_CONSERVATIVE) && + (!policy->governor->initialized)) { struct cs_ops *cs_ops = dbs_data->cdata->gov_ops; cpufreq_register_notifier(cs_ops->notifier_block, @@ -306,12 +309,12 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; case CPUFREQ_GOV_POLICY_EXIT: - if ((policy->governor->initialized == 1) || - have_governor_per_policy()) { + if (!--dbs_data->usage_count) { sysfs_remove_group(get_governor_parent_kobj(policy), get_sysfs_attr(dbs_data)); - if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { + if ((dbs_data->cdata->governor == GOV_CONSERVATIVE) && + (policy->governor->initialized == 1)) { struct cs_ops *cs_ops = dbs_data->cdata->gov_ops; cpufreq_unregister_notifier(cs_ops->notifier_block, diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 8ac33538d0bd..e16a96130cb3 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -211,6 +211,7 @@ struct common_dbs_data { struct dbs_data { struct common_dbs_data *cdata; unsigned int min_sampling_rate; + int usage_count; void *tuners; /* dbs_mutex protects dbs_enable in governor start/stop */ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index b0ffef96bf77..4b9bb5def6f1 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -547,7 +547,6 @@ static int od_init(struct dbs_data *dbs_data) tuners->io_is_busy = should_io_be_busy(); dbs_data->tuners = tuners; - pr_info("%s: tuners %p\n", __func__, tuners); mutex_init(&dbs_data->mutex); return 0; } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index bfd6273fd873..fb65decffa28 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -349,15 +349,16 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, switch (action) { case CPU_ONLINE: - case CPU_ONLINE_FROZEN: cpufreq_update_policy(cpu); break; case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: cpufreq_stats_free_sysfs(cpu); break; case CPU_DEAD: - case CPU_DEAD_FROZEN: + cpufreq_stats_free_table(cpu); + break; + case CPU_UP_CANCELED_FROZEN: + cpufreq_stats_free_sysfs(cpu); cpufreq_stats_free_table(cpu); break; } diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index cc3a8e6c92be..9c36ace92a39 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -48,12 +48,7 @@ static inline int32_t div_fp(int32_t x, int32_t y) } struct sample { - ktime_t start_time; - ktime_t end_time; int core_pct_busy; - int pstate_pct_busy; - u64 duration_us; - u64 idletime_us; u64 aperf; u64 mperf; int freq; @@ -86,13 +81,9 @@ struct cpudata { struct pstate_adjust_policy *pstate_policy; struct pstate_data pstate; struct _pid pid; - struct _pid idle_pid; int min_pstate_count; - int idle_mode; - ktime_t prev_sample; - u64 prev_idle_time_us; u64 prev_aperf; u64 prev_mperf; int sample_ptr; @@ -124,6 +115,8 @@ struct perf_limits { int min_perf_pct; int32_t max_perf; int32_t min_perf; + int max_policy_pct; + int max_sysfs_pct; }; static struct perf_limits limits = { @@ -132,6 +125,8 @@ static struct perf_limits limits = { .max_perf = int_tofp(1), .min_perf_pct = 0, .min_perf = 0, + .max_policy_pct = 100, + .max_sysfs_pct = 100, }; static inline void pid_reset(struct _pid *pid, int setpoint, int busy, @@ -202,19 +197,6 @@ static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu) 0); } -static inline void intel_pstate_idle_pid_reset(struct cpudata *cpu) -{ - pid_p_gain_set(&cpu->idle_pid, cpu->pstate_policy->p_gain_pct); - pid_d_gain_set(&cpu->idle_pid, cpu->pstate_policy->d_gain_pct); - pid_i_gain_set(&cpu->idle_pid, cpu->pstate_policy->i_gain_pct); - - pid_reset(&cpu->idle_pid, - 75, - 50, - cpu->pstate_policy->deadband, - 0); -} - static inline void intel_pstate_reset_all_pid(void) { unsigned int cpu; @@ -302,7 +284,8 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, if (ret != 1) return -EINVAL; - limits.max_perf_pct = clamp_t(int, input, 0 , 100); + limits.max_sysfs_pct = clamp_t(int, input, 0 , 100); + limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); return count; } @@ -408,9 +391,8 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) if (pstate == cpu->pstate.current_pstate) return; -#ifndef MODULE trace_cpu_frequency(pstate * 100000, cpu->cpu); -#endif + cpu->pstate.current_pstate = pstate; wrmsrl(MSR_IA32_PERF_CTL, pstate << 8); @@ -450,48 +432,26 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu, struct sample *sample) { u64 core_pct; - sample->pstate_pct_busy = 100 - div64_u64( - sample->idletime_us * 100, - sample->duration_us); core_pct = div64_u64(sample->aperf * 100, sample->mperf); sample->freq = cpu->pstate.max_pstate * core_pct * 1000; - sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct), - 100); + sample->core_pct_busy = core_pct; } static inline void intel_pstate_sample(struct cpudata *cpu) { - ktime_t now; - u64 idle_time_us; u64 aperf, mperf; - now = ktime_get(); - idle_time_us = get_cpu_idle_time_us(cpu->cpu, NULL); - rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); - /* for the first sample, don't actually record a sample, just - * set the baseline */ - if (cpu->prev_idle_time_us > 0) { - cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; - cpu->samples[cpu->sample_ptr].start_time = cpu->prev_sample; - cpu->samples[cpu->sample_ptr].end_time = now; - cpu->samples[cpu->sample_ptr].duration_us = - ktime_us_delta(now, cpu->prev_sample); - cpu->samples[cpu->sample_ptr].idletime_us = - idle_time_us - cpu->prev_idle_time_us; - - cpu->samples[cpu->sample_ptr].aperf = aperf; - cpu->samples[cpu->sample_ptr].mperf = mperf; - cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf; - cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf; - - intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]); - } + cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; + cpu->samples[cpu->sample_ptr].aperf = aperf; + cpu->samples[cpu->sample_ptr].mperf = mperf; + cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf; + cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf; + + intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]); - cpu->prev_sample = now; - cpu->prev_idle_time_us = idle_time_us; cpu->prev_aperf = aperf; cpu->prev_mperf = mperf; } @@ -505,16 +465,6 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu) mod_timer_pinned(&cpu->timer, jiffies + delay); } -static inline void intel_pstate_idle_mode(struct cpudata *cpu) -{ - cpu->idle_mode = 1; -} - -static inline void intel_pstate_normal_mode(struct cpudata *cpu) -{ - cpu->idle_mode = 0; -} - static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu) { int32_t busy_scaled; @@ -547,50 +497,21 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) intel_pstate_pstate_decrease(cpu, steps); } -static inline void intel_pstate_adjust_idle_pstate(struct cpudata *cpu) -{ - int busy_scaled; - struct _pid *pid; - int ctl = 0; - int steps; - - pid = &cpu->idle_pid; - - busy_scaled = intel_pstate_get_scaled_busy(cpu); - - ctl = pid_calc(pid, 100 - busy_scaled); - - steps = abs(ctl); - if (ctl < 0) - intel_pstate_pstate_decrease(cpu, steps); - else - intel_pstate_pstate_increase(cpu, steps); - - if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) - intel_pstate_normal_mode(cpu); -} - static void intel_pstate_timer_func(unsigned long __data) { struct cpudata *cpu = (struct cpudata *) __data; intel_pstate_sample(cpu); + intel_pstate_adjust_busy_pstate(cpu); - if (!cpu->idle_mode) - intel_pstate_adjust_busy_pstate(cpu); - else - intel_pstate_adjust_idle_pstate(cpu); - -#if defined(XPERF_FIX) if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) { cpu->min_pstate_count++; if (!(cpu->min_pstate_count % 5)) { intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate); - intel_pstate_idle_mode(cpu); } } else cpu->min_pstate_count = 0; -#endif + intel_pstate_set_sample_time(cpu); } @@ -631,7 +552,6 @@ static int intel_pstate_init_cpu(unsigned int cpunum) (unsigned long)cpu; cpu->timer.expires = jiffies + HZ/100; intel_pstate_busy_pid_reset(cpu); - intel_pstate_idle_pid_reset(cpu); intel_pstate_sample(cpu); intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate); @@ -675,8 +595,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); - limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq; - limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100); + limits.max_policy_pct = policy->max * 100 / policy->cpuinfo.max_freq; + limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100); + limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); return 0; @@ -788,10 +709,9 @@ static int __init intel_pstate_init(void) pr_info("Intel P-state driver initializing.\n"); - all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus()); + all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus()); if (!all_cpu_data) return -ENOMEM; - memset(all_cpu_data, 0, sizeof(void *) * num_possible_cpus()); rc = cpufreq_register_driver(&intel_pstate_driver); if (rc) diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index d36ea8dc96eb..b2644af985ec 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c @@ -171,10 +171,6 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev) priv.dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Cannot get memory resource\n"); - return -ENODEV; - } priv.base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv.base)) return PTR_ERR(priv.base); |