diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index d9e4f618..0098938a 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -22,12 +22,14 @@ #include #include #include +#include #include #include #include #include #include "acpuclock.h" +#include "cpufreq.h" #ifdef CONFIG_SMP struct cpufreq_work_struct { @@ -39,40 +41,77 @@ struct cpufreq_work_struct { }; static DEFINE_PER_CPU(struct cpufreq_work_struct, cpufreq_work); -static struct workqueue_struct *msm_cpufreq_wq; #endif -struct cpufreq_suspend_t { - struct mutex suspend_mutex; - int device_suspended; -}; +static DEFINE_MUTEX(msm_cpufreq_voter_lock); +static int msm_cpufreq_vote = MSM_CPUFREQ_IDLE; +static LIST_HEAD(msm_cpufreq_voters); + +#define dprintk(msg...) \ +cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-msm", msg) -static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend); +static int msm_cpufreq_check_votes(void) +{ +struct msm_cpufreq_voter *voter; +int vote = MSM_CPUFREQ_IDLE; -static int override_cpu; +list_for_each_entry(voter, &msm_cpufreq_voters, item) + vote |= voter->vote(voter); -#define dprintk(msg...) \ - cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-msm", msg) +return vote; +} + +void msm_cpufreq_voter_update(struct msm_cpufreq_voter *v) +{ + mutex_lock(&msm_cpufreq_voter_lock); + msm_cpufreq_vote = msm_cpufreq_check_votes(); + mutex_unlock(&msm_cpufreq_voter_lock); +} + EXPORT_SYMBOL_GPL(msm_cpufreq_voter_update); + + int msm_cpufreq_register_voter(struct msm_cpufreq_voter *v) +{ + if (v == NULL || v->vote == NULL) + return -EINVAL; + + mutex_lock(&msm_cpufreq_voter_lock); + list_add(&v->item, &msm_cpufreq_voters); + msm_cpufreq_vote = msm_cpufreq_check_votes(); + mutex_unlock(&msm_cpufreq_voter_lock); + + return 0; +} + EXPORT_SYMBOL_GPL(msm_cpufreq_register_voter); + +void msm_cpufreq_unregister_voter(struct msm_cpufreq_voter *v) +{ + if (v == NULL) + return; + + mutex_lock(&msm_cpufreq_voter_lock); + list_del(&v->item); + msm_cpufreq_vote = msm_cpufreq_check_votes(); + mutex_unlock(&msm_cpufreq_voter_lock); +} + EXPORT_SYMBOL_GPL(msm_cpufreq_unregister_voter); static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq) { int ret = 0; struct cpufreq_freqs freqs; + /* race condition ok */ +if (msm_cpufreq_vote == MSM_CPUFREQ_ACTIVE) + new_freq = policy->max; + freqs.old = policy->cur; - if (override_cpu) { - if (policy->cur == policy->max) - return 0; - else - freqs.new = policy->max; - } else - freqs.new = new_freq; + freqs.new = new_freq; freqs.cpu = policy->cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ); if (!ret) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - + return ret; } @@ -94,35 +133,12 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, int ret = -EFAULT; int index; struct cpufreq_frequency_table *table; -#ifdef CONFIG_SMP - struct cpufreq_work_struct *cpu_work = NULL; - cpumask_var_t mask; - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - if (!cpu_active(policy->cpu)) { - pr_info("cpufreq: cpu %d is not active.\n", policy->cpu); - return -ENODEV; - } -#endif - - mutex_lock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex); - - if (per_cpu(cpufreq_suspend, policy->cpu).device_suspended) { - pr_debug("cpufreq: cpu%d scheduling frequency change " - "in suspend.\n", policy->cpu); - ret = -EFAULT; - goto done; - } table = cpufreq_frequency_get_table(policy->cpu); - if (cpufreq_frequency_table_target(policy, table, target_freq, relation, - &index)) { + if (cpufreq_frequency_table_target(policy, table, target_freq, relation, &index)) { pr_err("cpufreq: invalid target_freq: %d\n", target_freq); - ret = -EINVAL; - goto done; - } +return -EINVAL; +} #ifdef CONFIG_CPU_FREQ_DEBUG dprintk("CPU[%d] target %d relation %d (%d-%d) selected %d\n", @@ -131,31 +147,29 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, #endif #ifdef CONFIG_SMP - cpu_work = &per_cpu(cpufreq_work, policy->cpu); - cpu_work->policy = policy; - cpu_work->frequency = table[index].frequency; - cpu_work->status = -ENODEV; - - cpumask_clear(mask); - cpumask_set_cpu(policy->cpu, mask); - if (cpumask_equal(mask, ¤t->cpus_allowed)) { - ret = set_cpu_freq(cpu_work->policy, cpu_work->frequency); - goto done; - } else { + if (get_cpu() == policy->cpu) { + /* Issue a direct call, since we are on the same cpu */ + ret = set_cpu_freq(policy, table[index].frequency); + put_cpu(); +} else { + struct cpufreq_work_struct *cpu_work = NULL; + + put_cpu(); + cpu_work = &per_cpu(cpufreq_work, policy->cpu); + cpu_work->policy = policy; + cpu_work->frequency = table[index].frequency; + + init_completion(&cpu_work->complete); cancel_work_sync(&cpu_work->work); - INIT_COMPLETION(cpu_work->complete); - queue_work_on(policy->cpu, msm_cpufreq_wq, &cpu_work->work); + schedule_work_on(policy->cpu, &cpu_work->work); wait_for_completion(&cpu_work->complete); - } + ret = cpu_work->status; +} - free_cpumask_var(mask); - ret = cpu_work->status; #else ret = set_cpu_freq(policy, table[index].frequency); #endif -done: - mutex_unlock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex); return ret; } @@ -168,14 +182,13 @@ static int msm_cpufreq_verify(struct cpufreq_policy *policy) static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy) { - int cur_freq; - int index; struct cpufreq_frequency_table *table; #ifdef CONFIG_SMP struct cpufreq_work_struct *cpu_work = NULL; #endif table = cpufreq_frequency_get_table(policy->cpu); + policy->cur = acpuclk_get_rate(policy->cpu); if (cpufreq_frequency_table_cpuinfo(policy, table)) { #ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_MIN; @@ -187,95 +200,21 @@ static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy) policy->max = CONFIG_MSM_CPU_FREQ_MAX; #endif - cur_freq = acpuclk_get_rate(policy->cpu); - if (cpufreq_frequency_table_target(policy, table, cur_freq, - CPUFREQ_RELATION_H, &index)) { - pr_info("cpufreq: cpu%d at invalid freq: %d\n", - policy->cpu, cur_freq); - return -EINVAL; - } - - if (cur_freq != table[index].frequency) { - int ret = 0; - ret = acpuclk_set_rate(policy->cpu, table[index].frequency, - SETRATE_CPUFREQ); - if (ret) - return ret; - pr_info("cpufreq: cpu%d init at %d switching to %d\n", - policy->cpu, cur_freq, table[index].frequency); - cur_freq = table[index].frequency; - } - - policy->cur = cur_freq; - policy->cpuinfo.transition_latency = - acpuclk_get_switch_time() * NSEC_PER_USEC; + acpuclk_get_switch_time() * NSEC_PER_USEC; + #ifdef CONFIG_SMP cpu_work = &per_cpu(cpufreq_work, policy->cpu); INIT_WORK(&cpu_work->work, set_cpu_work); - init_completion(&cpu_work->complete); #endif return 0; } -static int msm_cpufreq_suspend(void) -{ - int cpu; - - for_each_possible_cpu(cpu) { - mutex_lock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex); - per_cpu(cpufreq_suspend, cpu).device_suspended = 1; - mutex_unlock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex); - } - - return NOTIFY_DONE; -} - -static int msm_cpufreq_resume(void) -{ - int cpu; - - for_each_possible_cpu(cpu) { - per_cpu(cpufreq_suspend, cpu).device_suspended = 0; - } - - return NOTIFY_DONE; -} - -static int msm_cpufreq_pm_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - switch (event) { - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - return msm_cpufreq_resume(); - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - return msm_cpufreq_suspend(); - default: - return NOTIFY_DONE; - } -} - -static ssize_t store_mfreq(struct sysdev_class *class, - struct sysdev_class_attribute *attr, - const char *buf, size_t count) -{ - u64 val; - - if (strict_strtoull(buf, 0, &val) < 0) { - pr_err("Invalid parameter to mfreq\n"); - return 0; - } - if (val) - override_cpu = 1; - else - override_cpu = 0; - return count; -} - -static SYSDEV_CLASS_ATTR(mfreq, 0200, NULL, store_mfreq); +static struct freq_attr *msm_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; static struct cpufreq_driver msm_cpufreq_driver = { /* lps calculations are handled here. */ @@ -284,33 +223,12 @@ static struct cpufreq_driver msm_cpufreq_driver = { .verify = msm_cpufreq_verify, .target = msm_cpufreq_target, .name = "msm", -}; - -static struct notifier_block msm_cpufreq_pm_notifier = { - .notifier_call = msm_cpufreq_pm_event, + .attr = msm_cpufreq_attr, }; static int __init msm_cpufreq_register(void) { - int cpu; - - int err = sysfs_create_file(&cpu_sysdev_class.kset.kobj, - &attr_mfreq.attr); - if (err) - pr_err("Failed to create sysfs mfreq\n"); - - for_each_possible_cpu(cpu) { - mutex_init(&(per_cpu(cpufreq_suspend, cpu).suspend_mutex)); - per_cpu(cpufreq_suspend, cpu).device_suspended = 0; - } - -#ifdef CONFIG_SMP - msm_cpufreq_wq = create_workqueue("msm-cpufreq"); -#endif - - register_pm_notifier(&msm_cpufreq_pm_notifier); return cpufreq_register_driver(&msm_cpufreq_driver); } -late_initcall(msm_cpufreq_register); - +late_initcall(msm_cpufreq_register); \ No newline at end of file