当前位置 博文首页 > 想要去旅行:cpufreq 代码分析

    想要去旅行:cpufreq 代码分析

    作者:[db:作者] 时间:2021-08-31 15:56

    cpufreq 代码分析

    基础知识:

    1.cpufreq 的五种模式

    2.cpufreq 的框架

    cpufreq 代码分析

    从 drivers\cpufreq\Makefile 开始,(注:我的是linux-4.14.63)

    # SPDX-License-Identifier: GPL-2.0
    # CPUfreq core
    obj-$(CONFIG_CPU_FREQ)			+= cpufreq.o freq_table.o          # cpufreq core 代码
    
    # CPUfreq stats
    obj-$(CONFIG_CPU_FREQ_STAT)             += cpufreq_stats.o          # cpufreq stats  
    
    # CPUfreq governors 
    obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE)	+= cpufreq_performance.o    # 对应于cpufreq 五种模式
    obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE)	+= cpufreq_powersave.o
    obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE)	+= cpufreq_userspace.o
    obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND)	+= cpufreq_ondemand.o
    obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
    obj-$(CONFIG_CPU_FREQ_GOV_COMMON)		+= cpufreq_governor.o
    obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET)	+= cpufreq_governor_attr_set.o
    
    obj-$(CONFIG_CPUFREQ_DT)		+= cpufreq-dt.o                    # cpufreq_driver dt 表示设备树版
    obj-$(CONFIG_CPUFREQ_DT_PLATDEV)	+= cpufreq-dt-platdev.o        
    //....
    

    驱动入口:

    cpufreq-dt.c:

    static struct platform_driver dt_cpufreq_platdrv = {
    	.driver = {
    		.name	= "cpufreq-dt",
    	},
    	.probe		= dt_cpufreq_probe,
    	.remove		= dt_cpufreq_remove,
    };
    module_platform_driver(dt_cpufreq_platdrv);
    

    可以看出这是个平台驱动,与之对应的平台设备的添加在cpufreq-dt-platdev.c:

    static int __init cpufreq_dt_platdev_init(void)
    {
    create_pdev:
    	of_node_put(np);
    	return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt",
    			       -1, data,
    			       sizeof(struct cpufreq_dt_platform_data)));
    }
    device_initcall(cpufreq_dt_platdev_init);
    
    

    device_initcall(cpufreq_dt_platdev_init); 表示该函数在内核启动过程中会被调用。

    继续看 probe 函数,dt_cpufreq_probe:

    	ret = cpufreq_register_driver(&dt_cpufreq_driver);
    

    dt_cpufreq_driver 的定义

    static struct cpufreq_driver dt_cpufreq_driver = {
    	.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
    	.verify = cpufreq_generic_frequency_table_verify,
    	.target_index = set_target,
    	.get = cpufreq_generic_get,
    	.init = cpufreq_init,
    	.exit = cpufreq_exit,
    	.ready = cpufreq_ready,
    	.name = "cpufreq-dt",
    	.attr = cpufreq_dt_attr,
    	.suspend = cpufreq_generic_suspend,c
    };
    

    继续跟踪 cpufreq_register_driver

     int cpufreq_register_driver(struct cpufreq_driver *driver_data)
     {	
    	cpufreq_driver = driver_data;    // 1.给 cpufreq_driver 赋值	
    	
    	ret = subsys_interface_register(&cpufreq_interface);  // 2.注册 cpufreq_interface	
        // ...
    }
    

    cpufreq_interface 的定义

    static struct subsys_interface cpufreq_interface = {
    	.name		= "cpufreq",
    	.subsys		= &cpu_subsys,
    	.add_dev	= cpufreq_add_dev,
    	.remove_dev	= cpufreq_remove_dev,
    };
    

    subsys_interface_register 函数会调用 sif->add_dev 函数 ,即 cpufreq_add_dev

    int subsys_interface_register(struct subsys_interface *sif)
    {		
    	if (sif->add_dev) {		
    			sif->add_dev(dev, sif);		
    	}	
    }
    

    cpufreq_add_dev:

    static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
    {
    	
    	if (cpu_online(cpu)) {
    		ret = cpufreq_online(cpu);		
    	}	
    }
    

    cpufreq_online:

    static int cpufreq_online(unsigned int cpu)
    {
    	/* call driver. From then on the cpufreq must be able
    	 * to accept all calls to ->verify and ->setpolicy for this CPU
    	 */
    	ret = cpufreq_driver->init(policy);  // 1.调用 cpufreq_driver->init 函数 初始化policy	
    
    	down_write(&policy->rwsem);	
    
    	if (new_policy) {
    		ret = cpufreq_add_dev_interface(policy);  // 创建 sys 节点 cpufreq/scaling_cur_freq  等
    		if (ret)
    			goto out_exit_policy;
    
    		cpufreq_stats_create_table(policy);    // 创建 cpufreq/sys  stats 节点
    
    		write_lock_irqsave(&cpufreq_driver_lock, flags);
    		list_add(&policy->policy_list, &cpufreq_policy_list);  //
    		write_unlock_irqrestore(&cpufreq_driver_lock, flags);
    	}
    
    	ret = cpufreq_init_policy(policy);   //	初始化policy 的 governor
    
    	up_write(&policy->rwsem);
    
    	kobject_uevent(&policy->kobj, KOBJ_ADD);
    
    	/* Callback for handling stuff after policy is ready */
    	if (cpufreq_driver->ready)
    		cpufreq_driver->ready(policy);    // cpufreq_driver->ready , 创建了cpufreq_cooling_dev,
                                               // 与 thermal 系统关联
    
    	pr_debug("initialization complete\n");
    
    	return 0;
    
    }
    

    cpufreq_driver->init -----------------> cpufreq_init ,主要是填充policy结构体中的 freq_table

    static int cpufreq_init(struct cpufreq_policy *policy)
    {	
    	
    	dev_pm_opp_of_cpumask_add_table(policy->cpus);  // 从dts 中读取 opp cpufreq table
    
    	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    	if (!priv) {
    		ret = -ENOMEM;
    		goto out_free_opp;
    	}
    
    	priv->reg_name = name;
    	priv->opp_table = opp_table;
    
    	ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);  //取出 freq_table
    	if (ret) {
    		dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
    		goto out_free_priv;
    	}
    
    	priv->cpu_dev = cpu_dev;
    	policy->driver_data = priv;
    	policy->clk = cpu_clk;
    
    	policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;
    
    	ret = cpufreq_table_validate_and_show(policy, freq_table);	// freq_table 填入 policy
    
    	transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);
    	if (!transition_latency)
    		transition_latency = CPUFREQ_ETERNAL;
    
    	policy->cpuinfo.transition_latency = transition_latency;
    	policy->dvfs_possible_from_any_cpu = true;
    
    	return 0;
    
    
    }
    

    小结:cpufreq_driver 注册时序图:

    在这里插入图片描述

    接上面:cpufre_online -> cpufreq_init_policy , 继续跟踪

    cpufreq_init_policy:

    static int cpufreq_init_policy(struct cpufreq_policy *policy)
    {
    	new_policy.governor = gov;	
    	
    	/* set default policy */
    	return cpufreq_set_policy(policy, &new_policy);  // cpufreq_set_policy
    }
    

    cpufreq_set_policy:

    static int cpufreq_set_policy(struct cpufreq_policy *policy,
    				struct cpufreq_policy *new_policy)
    {	
    	/* start new governor */
    	policy->governor = new_policy->governor;
    	ret = cpufreq_init_governor(policy);
    	if (!ret) {
    		ret = cpufreq_start_governor(policy);     // start_governor		
    	}	
    
    	return ret;
    }
    

    cpufreq_start_governor:

    static int cpufreq_start_governor(struct cpufreq_policy *policy)
    {
    	int ret;
    
    	if (cpufreq_suspended)
    		return 0;
    
    	if (!policy->governor)
    		return -EINVAL;
    
    	pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
    
    	if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
    		cpufreq_update_current_freq(policy);
    
    	if (policy->governor->start) {
    		ret = policy->governor->start(policy);    // governor->start  
    		if (ret)
    			return ret;
    	}
    
    	if (policy->governor->limits)
    		policy->governor->limits(policy);        // governor->limits
    
    	return 0;
    }
    

    governor->start , 以 ondemand 为例

    static struct dbs_governor od_dbs_gov = {
    	.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"),
    	.kobj_type = { .default_attrs = od_attributes },
    	.gov_dbs_update = od_dbs_update,
    	.alloc = od_alloc,
    	.free = od_free,
    	.init = od_init,
    	.exit = od_exit,
    	.start = od_start,
    };
    
    #define CPUFREQ_DBS_GOVERNOR_INITIALIZER(_name_)			\
    	{								\
    		.name = _name_,						\
    		.dynamic_switching = true,				\
    		.owner = THIS_MODULE,					\
    		.init = cpufreq_dbs_governor_init,			\
    		.exit = cpufreq_dbs_governor_exit,			\
    		.start = cpufreq_dbs_governor_start,			\
    		.stop = cpufreq_dbs_governor_stop,			\
    		.limits = cpufreq_dbs_governor_limits,			\
    	}
    
    下一篇:没有了