cpufreq.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,167 行 · 第 1/2 页
C
1,167 行
{ unsigned int cpu = (unsigned int)(long)data; cpufreq_update_policy(cpu);}/** * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble. * @cpu: cpu number * @old_freq: CPU frequency the kernel thinks the CPU runs at * @new_freq: CPU frequency the CPU actually runs at * * We adjust to current frequency first, and need to clean up later. So either call * to cpufreq_update_policy() or schedule handle_update()). */static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigned int new_freq){ struct cpufreq_freqs freqs; printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " "core thinks of %u, is %u kHz.\n", old_freq, new_freq); freqs.cpu = cpu; freqs.old = old_freq; freqs.new = new_freq; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);}/** * cpufreq_get - get the current CPU frequency (in kHz) * @cpu: CPU number * * Get the CPU current (static) CPU frequency */unsigned int cpufreq_get(unsigned int cpu){ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); unsigned int ret = 0; if (!policy) return 0; if (!cpufreq_driver->get) goto out; down(&policy->lock); ret = cpufreq_driver->get(cpu); if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { /* verify no discrepancy between actual and saved value exists */ if (unlikely(ret != policy->cur)) { cpufreq_out_of_sync(cpu, policy->cur, ret); schedule_work(&policy->update); } } up(&policy->lock); out: cpufreq_cpu_put(policy); return (ret);}EXPORT_SYMBOL(cpufreq_get);/** * cpufreq_resume - restore proper CPU frequency handling after resume * * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) * 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored. */static int cpufreq_resume(struct sys_device * sysdev){ int cpu = sysdev->id; unsigned int ret = 0; struct cpufreq_policy *cpu_policy; if (!cpu_online(cpu)) return 0; /* we may be lax here as interrupts are off. Nonetheless * we need to grab the correct cpu policy, as to check * whether we really run on this CPU. */ cpu_policy = cpufreq_cpu_get(cpu); if (!cpu_policy) return -EINVAL; if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { unsigned int cur_freq = 0; if (cpufreq_driver->get) cur_freq = cpufreq_driver->get(cpu_policy->cpu); if (!cur_freq || !cpu_policy->cur) { printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n"); goto out; } if (unlikely(cur_freq != cpu_policy->cur)) { struct cpufreq_freqs freqs; printk(KERN_WARNING "Warning: CPU frequency is %u, " "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); freqs.cpu = cpu; freqs.old = cpu_policy->cur; freqs.new = cur_freq; notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs); adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs); cpu_policy->cur = cur_freq; } }out: schedule_work(&cpu_policy->update); cpufreq_cpu_put(cpu_policy); return ret;}static struct sysdev_driver cpufreq_sysdev_driver = { .add = cpufreq_add_dev, .remove = cpufreq_remove_dev, .resume = cpufreq_resume,};/********************************************************************* * NOTIFIER LISTS INTERFACE * *********************************************************************//** * cpufreq_register_notifier - register a driver with cpufreq * @nb: notifier function to register * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER * * Add a driver to one of two lists: either a list of drivers that * are notified about clock rate changes (once before and once after * the transition), or a list of drivers that are notified about * changes in cpufreq policy. * * This function may sleep, and has the same return conditions as * notifier_chain_register. */int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list){ int ret; down_write(&cpufreq_notifier_rwsem); switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb); break; default: ret = -EINVAL; } up_write(&cpufreq_notifier_rwsem); return ret;}EXPORT_SYMBOL(cpufreq_register_notifier);/** * cpufreq_unregister_notifier - unregister a driver with cpufreq * @nb: notifier block to be unregistered * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER * * Remove a driver from the CPU frequency notifier list. * * This function may sleep, and has the same return conditions as * notifier_chain_unregister. */int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list){ int ret; down_write(&cpufreq_notifier_rwsem); switch (list) { case CPUFREQ_TRANSITION_NOTIFIER: ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb); break; case CPUFREQ_POLICY_NOTIFIER: ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb); break; default: ret = -EINVAL; } up_write(&cpufreq_notifier_rwsem); return ret;}EXPORT_SYMBOL(cpufreq_unregister_notifier);/********************************************************************* * GOVERNORS * *********************************************************************/int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation){ int retval = -EINVAL; lock_cpu_hotplug(); if (cpu_online(policy->cpu)) retval = cpufreq_driver->target(policy, target_freq, relation); unlock_cpu_hotplug(); return retval;}EXPORT_SYMBOL_GPL(__cpufreq_driver_target);int cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation){ unsigned int ret; policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; down(&policy->lock); ret = __cpufreq_driver_target(policy, target_freq, relation); up(&policy->lock); cpufreq_cpu_put(policy); return ret;}EXPORT_SYMBOL_GPL(cpufreq_driver_target);static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event){ int ret = -EINVAL; if (!try_module_get(policy->governor->owner)) return -EINVAL; ret = policy->governor->governor(policy, event); /* we keep one module reference alive for each CPU governed by this CPU */ if ((event != CPUFREQ_GOV_START) || ret) module_put(policy->governor->owner); if ((event == CPUFREQ_GOV_STOP) && !ret) module_put(policy->governor->owner); return ret;}int cpufreq_governor(unsigned int cpu, unsigned int event){ int ret = 0; struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); if (!policy) return -EINVAL; down(&policy->lock); ret = __cpufreq_governor(policy, event); up(&policy->lock); cpufreq_cpu_put(policy); return ret;}EXPORT_SYMBOL_GPL(cpufreq_governor);int cpufreq_register_governor(struct cpufreq_governor *governor){ struct cpufreq_governor *t; if (!governor) return -EINVAL; down(&cpufreq_governor_sem); list_for_each_entry(t, &cpufreq_governor_list, governor_list) { if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) { up(&cpufreq_governor_sem); return -EBUSY; } } list_add(&governor->governor_list, &cpufreq_governor_list); up(&cpufreq_governor_sem); return 0;}EXPORT_SYMBOL_GPL(cpufreq_register_governor);void cpufreq_unregister_governor(struct cpufreq_governor *governor){ if (!governor) return; down(&cpufreq_governor_sem); list_del(&governor->governor_list); up(&cpufreq_governor_sem); return;}EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);/********************************************************************* * POLICY INTERFACE * *********************************************************************//** * cpufreq_get_policy - get the current cpufreq_policy * @policy: struct cpufreq_policy into which the current cpufreq_policy is written * * Reads the current cpufreq policy. */int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu){ struct cpufreq_policy *cpu_policy; if (!policy) return -EINVAL; cpu_policy = cpufreq_cpu_get(cpu); if (!cpu_policy) return -EINVAL; down(&cpu_policy->lock); memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); up(&cpu_policy->lock); cpufreq_cpu_put(cpu_policy); return 0;}EXPORT_SYMBOL(cpufreq_get_policy);static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy){ int ret = 0; memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); /* verify the cpu speed can be set within this limit */ ret = cpufreq_driver->verify(policy); if (ret) goto error_out; down_read(&cpufreq_notifier_rwsem); /* adjust if necessary - all reasons */ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, policy); /* adjust if necessary - hardware incompatibility*/ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE, policy); /* verify the cpu speed can be set within this limit, which might be different to the first one */ ret = cpufreq_driver->verify(policy); if (ret) { up_read(&cpufreq_notifier_rwsem); goto error_out; } /* notification of the new policy */ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, policy); up_read(&cpufreq_notifier_rwsem); data->min = policy->min; data->max = policy->max; if (cpufreq_driver->setpolicy) { data->policy = policy->policy; ret = cpufreq_driver->setpolicy(policy); } else { if (policy->governor != data->governor) { /* save old, working values */ struct cpufreq_governor *old_gov = data->governor; /* end old governor */ if (data->governor) __cpufreq_governor(data, CPUFREQ_GOV_STOP); /* start new governor */ data->governor = policy->governor; if (__cpufreq_governor(data, CPUFREQ_GOV_START)) { /* new governor failed, so re-start old one */ if (old_gov) { data->governor = old_gov; __cpufreq_governor(data, CPUFREQ_GOV_START); } ret = -EINVAL; goto error_out; } /* might be a policy change, too, so fall through */ } __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); } error_out: return ret;}/** * cpufreq_set_policy - set a new CPUFreq policy * @policy: policy to be set. * * Sets a new CPU frequency and voltage scaling policy. */int cpufreq_set_policy(struct cpufreq_policy *policy){ int ret = 0; struct cpufreq_policy *data; if (!policy) return -EINVAL; data = cpufreq_cpu_get(policy->cpu); if (!data) return -EINVAL; /* lock this CPU */ down(&data->lock); ret = __cpufreq_set_policy(data, policy); data->user_policy.min = data->min; data->user_policy.max = data->max; data->user_policy.policy = data->policy; data->user_policy.governor = data->governor; up(&data->lock); cpufreq_cpu_put(data); return ret;}EXPORT_SYMBOL(cpufreq_set_policy);/** * cpufreq_update_policy - re-evaluate an existing cpufreq policy * @cpu: CPU which shall be re-evaluated * * Usefull for policy notifiers which have different necessities * at different times. */int cpufreq_update_policy(unsigned int cpu){ struct cpufreq_policy *data = cpufreq_cpu_get(cpu); struct cpufreq_policy policy; int ret = 0; if (!data) return -ENODEV; down(&data->lock); memcpy(&policy, data, sizeof(struct cpufreq_policy)); policy.min = data->user_policy.min; policy.max = data->user_policy.max; policy.policy = data->user_policy.policy; policy.governor = data->user_policy.governor; ret = __cpufreq_set_policy(data, &policy); up(&data->lock); cpufreq_cpu_put(data); return ret;}EXPORT_SYMBOL(cpufreq_update_policy);/********************************************************************* * REGISTER / UNREGISTER CPUFREQ DRIVER * *********************************************************************//** * cpufreq_register_driver - register a CPU Frequency driver * @driver_data: A struct cpufreq_driver containing the values# * submitted by the CPU Frequency driver. * * Registers a CPU Frequency driver to this core code. This code * returns zero on success, -EBUSY when another driver got here first * (and isn't unregistered in the meantime). * */int cpufreq_register_driver(struct cpufreq_driver *driver_data){ unsigned long flags; int ret; if (!driver_data || !driver_data->verify || !driver_data->init || ((!driver_data->setpolicy) && (!driver_data->target))) return -EINVAL; if (driver_data->setpolicy) driver_data->flags |= CPUFREQ_CONST_LOOPS; spin_lock_irqsave(&cpufreq_driver_lock, flags); if (cpufreq_driver) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); return -EBUSY; } cpufreq_driver = driver_data; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); ret = sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver); if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) { int i; ret = -ENODEV; /* check for at least one working CPU */ for (i=0; i<NR_CPUS; i++) if (cpufreq_cpu_data[i]) ret = 0; /* if all ->init() calls failed, unregister */ if (ret) { sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); spin_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); } } return (ret);}EXPORT_SYMBOL_GPL(cpufreq_register_driver);/** * cpufreq_unregister_driver - unregister the current CPUFreq driver * * Unregister the current CPUFreq driver. Only call this if you have * the right to do so, i.e. if you have succeeded in initialising before! * Returns zero if successful, and -EINVAL if the cpufreq_driver is * currently not initialised. */int cpufreq_unregister_driver(struct cpufreq_driver *driver){ unsigned long flags; if (!cpufreq_driver || (driver != cpufreq_driver)) return -EINVAL; sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); spin_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); return 0;}EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?