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 + -
显示快捷键?