sys接口:/sys/devices/system/cpu/目录下所有节点怎么创建的

最近碰到一个版本在cpu0目录下面没有online节点.check root cause之后,就萌生了将cpu目录下的所有节点全部总结下的想法.

凡是对cpu有点了解的都知道,查看cpu online或者offline状态,cpu的频率信息等等信息都在下面的目录下:

mi9:/sys/devices/system/cpu # ls -l  
total 0  
drwxr-xr-x 8 root root    0 2019-08-15 22:06 cpu0  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu1  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu2  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu3  
drwxr-xr-x 8 root root    0 2019-08-15 22:06 cpu4  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu5  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu6  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu7  
drwxr-xr-x 5 root root    0 2019-08-15 22:09 cpufreq  
drwxr-xr-x 2 root root    0 2019-08-15 22:24 cpuidle  
drwxr-xr-x 2 root root    0 2019-08-15 22:24 hotplug  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 isolated  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 kernel_max  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 modalias  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 offline  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 online  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 possible  
drwxr-xr-x 2 root root    0 2019-08-15 22:24 power  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 present  
-rw-r--r-- 1 root root 4096 2019-08-15 22:24 uevent  

对于各个cpuX下的有如下节点:

mi9:/sys/devices/system/cpu # ls cpu0/ -l                                                                                                                                                              
total 0  
-rw-r--r-- 1 root root 4096 2019-08-15 22:26 cpu_capacity  
lrwxrwxrwx 1 root root    0 2019-08-15 22:09 cpufreq -> ../cpufreq/policy0  
drwxr-xr-x 5 root root    0 2019-08-15 22:26 cpuidle  
drwxr-xr-x 2 root root    0 2019-08-15 22:26 hotplug  
lrwxrwxrwx 1 root root    0 2019-08-15 22:26 of_node -> ../../../../firmware/devicetree/base/cpus/cpu@0  
-rw-r--r-- 1 root root 4096 2019-08-15 22:26 online  
drwxr-xr-x 2 root root    0 2019-08-15 22:26 power  
drwxr-xr-x 3 root root    0 2019-08-15 22:26 regs  
lrwxrwxrwx 1 root root    0 2019-08-15 22:26 subsystem -> ../../../../bus/cpu  
drwxr-xr-x 2 root root    0 2019-08-15 22:26 topology  
-rw-r--r-- 1 root root 4096 2019-08-15 22:26 uevent 

那么上面的所有的这些节点信息怎么来的呢?

1 cpu目录的节点信息

我们想知道下面的节点信息如何得来的:

mi9:/sys/devices/system/cpu # ls -l  
total 0  
drwxr-xr-x 8 root root    0 2019-08-15 22:06 cpu0  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu1  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu2  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu3  
drwxr-xr-x 8 root root    0 2019-08-15 22:06 cpu4  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu5  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu6  
drwxr-xr-x 7 root root    0 2019-08-15 22:06 cpu7  
drwxr-xr-x 5 root root    0 2019-08-15 22:09 cpufreq  
drwxr-xr-x 2 root root    0 2019-08-15 22:24 cpuidle  
drwxr-xr-x 2 root root    0 2019-08-15 22:24 hotplug  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 isolated  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 kernel_max  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 modalias  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 offline  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 online  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 possible  
drwxr-xr-x 2 root root    0 2019-08-15 22:24 power  
-r--r--r-- 1 root root 4096 2019-08-15 22:24 present  
-rw-r--r-- 1 root root 4096 2019-08-15 22:24 uevent  

分析如下:

1.1 cpuX 目录的创建

代码流程如下:cpu_dev_init—> cpu_dev_register_generic—>register_cpu

void __init cpu_dev_init(void)  
{  
    if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))  
        panic("Failed to register CPU subsystem");  
   
    cpu_dev_register_generic();  
    cpu_register_vulnerabilities();  
}                                                                                                                                                                                                              
  
static void __init cpu_dev_register_generic(void)                                                                                                                                                              
{  
#ifdef CONFIG_GENERIC_CPU_DEVICES  
    int i;  
   
    for_each_possible_cpu(i) { 
        /*给每个cpu注册一个sys节点*/ 
        if (register_cpu(&per_cpu(cpu_devices, i), i))  
            panic("Failed to register CPU device");  
    }  
#endif  
}  
  
/*  
 * register_cpu - Setup a sysfs device for a CPU. 
 * @cpu - cpu->hotpluggable field set to 1 will generate a control file in 
 *    sysfs for this CPU. 
 * @num - CPU number to use when creating the device. 
 *  
 * Initialize and register the CPU device. 
 */  
int register_cpu(struct cpu *cpu, int num)  
{    
    int error;  
     
    cpu->node_id = cpu_to_node(num);  
    memset(&cpu->dev, 0x00, sizeof(struct device));  
    cpu->dev.id = num;  
    cpu->dev.bus = &cpu_subsys;  
    cpu->dev.release = cpu_device_release;  
    cpu->dev.offline_disabled = !cpu->hotpluggable;  
    cpu->dev.offline = !cpu_online(num);  
    cpu->dev.of_node = of_get_cpu_node(num, NULL);  
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE                                                                                                                                                                            
    cpu->dev.bus->uevent = cpu_uevent;  
#endif  
    cpu->dev.groups = common_cpu_attr_groups;  
    if (cpu->hotpluggable)  
        cpu->dev.groups = hotplugable_cpu_attr_groups; 
    /*这个是核心,注册每个cpuX,并且会创建cpuX目录下的相关节点信息*/ 
    error = device_register(&cpu->dev);  
    if (error)  
        return error;  
     
    per_cpu(cpu_sys_devices, num) = &cpu->dev;  
    register_cpu_under_node(num, cpu_to_node(num));  
    dev_pm_qos_expose_latency_limit(&cpu->dev, 0);  
     
    return 0;  
}  
/*这是一个全局性bus_type,后面在cpu目录下创建的除了cpuX之外的所有目录都会使用这个bus type*/
struct bus_type cpu_subsys = {  
    .name = "cpu",  
    .dev_name = "cpu",  
    .match = cpu_subsys_match,  
#ifdef CONFIG_HOTPLUG_CPU  
    .online = cpu_subsys_online,  
    .offline = cpu_subsys_offline,  
#endif  
};  
EXPORT_SYMBOL_GPL(cpu_subsys);  

我们来看看device_register的实现,实现在driver/base/core.c文件里面:

int device_register(struct device *dev)  
{              
    device_initialize(dev);      
    return device_add(dev);                                                                                                                                                                                    
}              
EXPORT_SYMBOL_GPL(device_register);  
  
int device_add(struct device *dev)  
{    
    struct device *parent;  
    struct kobject *kobj;  
    struct class_interface *class_intf;  
    int error = -EINVAL;  
    struct kobject *glue_dir = NULL;  
     
    dev = get_device(dev);  
    if (!dev)  
        goto done;  
     
    if (!dev->p) {  
        error = device_private_init(dev);  
        if (error)  
            goto done;  
    }  
     
    /* 
     * for statically allocated devices, which should all be converted 
     * some day, we need to initialize the name. We prevent reading back 
     * the name, and force the use of dev_name() 
     */  
    if (dev->init_name) {  
        dev_set_name(dev, "%s", dev->init_name);  
        dev->init_name = NULL;  
    }  
     
    /* subsystems can specify simple device enumeration */  
    if (!dev_name(dev) && dev->bus && dev->bus->dev_name)  
        /*这里设置了cpuX的文件名字,在register_cpu里面,dev_name,dev->id都被赋值了*/
        dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);  
     
.....................  
}  

所以到这里cpuX创建完毕

1.2 cpufreq/cpuidle/hotplug/power目录的创建

1.2.1 cpufreq的创建
mi9:/sys/devices/system/cpu # ls cpufreq/ -l                                                                                                                                                           
total 0  
-rw-r--r-- 1 root root 4096 2019-08-15 23:14 boost  
drwxr-xr-x 4 root root    0 2019-08-15 22:09 policy0  
drwxr-xr-x 4 root root    0 2019-08-15 22:09 policy4  

代码实现:

struct kobject *cpufreq_global_kobject;  
EXPORT_SYMBOL(cpufreq_global_kobject);  
       
static int __init cpufreq_core_init(void)  
{      
    if (cpufreq_disabled())  
        return -ENODEV;  
    /*这里创建cpufreq目录,已经全局性的kobject对象,这样对于其他模块也是可以在此目录下创建响应的文件的*/   
    cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);                                                                                                                    
    BUG_ON(!cpufreq_global_kobject);  
       
    register_syscore_ops(&cpufreq_syscore_ops);  
       
    return 0;  
}      
/*创建boost节点*/  
static int create_boost_sysfs_file(void)  
{                              
    int ret;                   
                               
    ret = sysfs_create_file(cpufreq_global_kobject, &boost.attr);                                                                                                                                              
    if (ret)                   
        pr_err("%s: cannot register global BOOST sysfs file\n",  
        ┊   ┊  __func__);      
                               
    return ret;                
}                              
                               
static void remove_boost_sysfs_file(void)  
{                              
    if (cpufreq_boost_supported())  
        sysfs_remove_file(cpufreq_global_kobject, &boost.attr);  
}                              
  
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)  
{                     
    struct cpufreq_policy *policy;  
    int ret;          
                      
    policy = kzalloc(sizeof(*policy), GFP_KERNEL);  
    if (!policy)      
        return NULL;  
                      
    if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))  
        goto err_free_policy;  
                      
    if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))  
        goto err_free_cpumask;  
                      
    if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))  
        goto err_free_rcpumask;  
    /*创建policyX节点信息,根据cluster来创建*/                  
    ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,  
                ┊  cpufreq_global_kobject, "policy%u", cpu);                                                                                                                                                   
    if (ret) {        
        pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);  
        goto err_free_real_cpus;  
    }                 
................  
}  

至于policyX的目录下的信息,在driver/cpufreq/cpufreq.c文件中.包含频率信息,governor信息等等.

1.2.2 cpuidle的创建
mi9:/sys/devices/system/cpu # ls cpuidle/ -l                                                                                                                                                           
total 0  
-r--r--r-- 1 root root 4096 2019-08-15 23:00 current_driver  
-r--r--r-- 1 root root 4096 2019-08-15 23:00 current_governor_ro  

可以看到下面的代码创建上面的目录以及节点信息:

static int __init cpuidle_init(void)  
{  
        int ret;  
  
        if (cpuidle_disabled())  
                return -ENODEV;  
       /*关键的cpu_subsys的使用,可以在cpu目录下创建文件*/
        ret = cpuidle_add_interface(cpu_subsys.dev_root);  
        if (ret)  
                return ret;  
  
        latency_notifier_init(&cpuidle_latency_notifier);  
  
        return 0;  
}  
  
int cpuidle_add_interface(struct device *dev)  
{  
        if (sysfs_switch)  
                cpuidle_attr_group.attrs = cpuidle_switch_attrs;  
  
        return sysfs_create_group(&dev->kobj, &cpuidle_attr_group);  
}  
  
static DEVICE_ATTR(current_driver, 0444, show_current_driver, NULL);  
static DEVICE_ATTR(current_governor_ro, 0444, show_current_governor, NULL);  
  
static struct attribute *cpuidle_default_attrs[] = {  
        &dev_attr_current_driver.attr,  
        &dev_attr_current_governor_ro.attr,  
        NULL  
};  
  
static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL);  
static DEVICE_ATTR(current_governor, 0644, show_current_governor,  
                   store_current_governor);  
  
static struct attribute *cpuidle_switch_attrs[] = {  
        &dev_attr_available_governors.attr,  
        &dev_attr_current_driver.attr,  
        &dev_attr_current_governor.attr,  
        NULL  
};  
  
static struct attribute_group cpuidle_attr_group = {  
        .attrs = cpuidle_default_attrs,  
        .name = "cpuidle",  
};  

上面写的很清楚,不赘述.

1.2.3 hotplug的创建

节点信息如下:

mi9:/sys/devices/system/cpu # ls hotplug/ -l                                                                                                                                                           
total 0  
-r--r--r-- 1 root root 4096 2019-08-15 22:56 states  

代码实现在driver/base/cpu.c文件里面:

static int __init cpuhp_sysfs_init(void)  
{  
        int cpu, ret;  
  
        ret = cpu_smt_state_init();  
        if (ret)  
                return ret;  
       /*这个是创建cpu目录下的节点信息*/
        ret = sysfs_create_group(&cpu_subsys.dev_root->kobj,  
                                 &cpuhp_cpu_root_attr_group);  
        if (ret)  
                return ret;  
  
        for_each_possible_cpu(cpu) {  
                struct device *dev = get_cpu_device(cpu);  
  
                if (!dev)  
                        continue;  
                /*这个是创建cpuX/hotplug目录及其此目录的节点信息,后面讲解*/
                ret = sysfs_create_group(&dev->kobj, &cpuhp_cpu_attr_group);  
                if (ret)  
                        return ret;  
        }  
        return 0;  
}  
device_initcall(cpuhp_sysfs_init);  
  
static const struct attribute_group cpuhp_cpu_root_attr_group = {  
        .attrs = cpuhp_cpu_root_attrs,  
        .name = "hotplug",  
        NULL  
};  
  
static ssize_t show_cpuhp_states(struct device *dev,  
                                 struct device_attribute *attr, char *buf)  
{  
        ssize_t cur, res = 0;  
        int i;  
  
        mutex_lock(&cpuhp_state_mutex);  
        for (i = CPUHP_OFFLINE; i <= CPUHP_ONLINE; i++) {  
                struct cpuhp_step *sp = cpuhp_get_step(i);  
  
                if (sp->name) {  
                        cur = sprintf(buf, "%3d: %s\n", i, sp->name);  
                        buf += cur;  
                        res += cur;  
                }  
        }  
        mutex_unlock(&cpuhp_state_mutex);  
        return res;  
}  
static DEVICE_ATTR(states, 0444, show_cpuhp_states, NULL);  
  
static struct attribute *cpuhp_cpu_root_attrs[] = {  
        &dev_attr_states.attr,  
        NULL  
};  
  
static const struct attribute_group cpuhp_cpu_root_attr_group = {  
        .attrs = cpuhp_cpu_root_attrs,  
        .name = "hotplug",  
        NULL  
};  

比较简单,一目了然.

1.2.4 power的创建

power 的节点信息如下:

mi11:/sys/devices/system/cpu # ls power/ -l                                                                                                                                                             
total 0  
-rw-r--r-- 1 root root 4096 2019-08-15 23:30 autosuspend_delay_ms  
-rw-r--r-- 1 root root 4096 2019-08-15 23:30 control  
-r--r--r-- 1 root root 4096 2019-08-15 23:30 runtime_active_time  
-r--r--r-- 1 root root 4096 2019-08-15 23:30 runtime_status  
-r--r--r-- 1 root root 4096 2019-08-15 23:30 runtime_suspended_time  

代码如下:

static struct attribute *runtime_attrs[] = {  
#ifndef CONFIG_PM_ADVANCED_DEBUG  
        &dev_attr_runtime_status.attr,  
#endif  
        &dev_attr_control.attr,  
        &dev_attr_runtime_suspended_time.attr,  
        &dev_attr_runtime_active_time.attr,  
        &dev_attr_autosuspend_delay_ms.attr,  
        NULL,  
};  
static const struct attribute_group pm_runtime_attr_group = {  
        .name   = power_group_name,  
        .attrs  = runtime_attrs,  
};  
  
int dpm_sysfs_add(struct device *dev)          
{                                           
    int rc;                                 
                                            
    rc = sysfs_create_group(&dev->kobj, &pm_attr_group);                                                                                                                                                       
    if (rc)                                 
        return rc;                          
                                            
    if (pm_runtime_callbacks_present(dev)) {  
        rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);  
        if (rc)                             
            goto err_out;                   
....................  
}  
  
int device_add(struct device *dev)  
{                  
    struct device *parent;  
    struct kobject *kobj;  
    struct class_interface *class_intf;  
    int error = -EINVAL;  
    struct kobject *glue_dir = NULL;  
                   
    dev = get_device(dev);  
    if (!dev)      
        goto done;  
                   
    if (!dev->p) {  
        error = device_private_init(dev);  
        if (error)  
            goto done;  
    }              
                   
    /*            
     * for statically allocated devices, which should all be converted 
     * some day, we need to initialize the name. We prevent reading back 
     * the name, and force the use of dev_name() 
     */            
    if (dev->init_name) {  
        dev_set_name(dev, "%s", dev->init_name);  
        dev->init_name = NULL;  
    }              
                   
    /* subsystems can specify simple device enumeration */  
    if (!dev_name(dev) && dev->bus && dev->bus->dev_name)                                                                                                                                                      
        dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);  
  
...............  
    error = dpm_sysfs_add(dev);  
  
...............  
}  

其实上面的过程也是cpuX/power类似的创建过程,不在赘述.

1.3 其他节点的创建

这些节点信息比较简单,直接在driver/base/cpu.c文件里面创建,具体如下:

void __init cpu_dev_init(void)                 
{                                              
    if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))                                                                                                                                             
        panic("Failed to register CPU subsystem");  
                                               
    cpu_dev_register_generic();                
    cpu_register_vulnerabilities();            
}                                              
  
/* Keep in sync with cpu_subsys_attrs */  
static struct cpu_attr cpu_attrs[] = {                                                                                                                                                                         
    _CPU_ATTR(online, &__cpu_online_mask),  
    _CPU_ATTR(possible, &__cpu_possible_mask),  
    _CPU_ATTR(present, &__cpu_present_mask),  
};                        
  
  
static struct attribute *cpu_root_attrs[] = {  
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE  
    &dev_attr_probe.attr,           
    &dev_attr_release.attr,  
#endif                      
    &cpu_attrs[0].attr.attr,  
    &cpu_attrs[1].attr.attr,  
    &cpu_attrs[2].attr.attr,                   
    &dev_attr_kernel_max.attr,  
    &dev_attr_offline.attr,  
    &dev_attr_isolated.attr,   
#ifdef CONFIG_NO_HZ_FULL    
    &dev_attr_nohz_full.attr,  
#endif                      
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE   
    &dev_attr_modalias.attr,   
#endif                      
    NULL                    
};                          
                            
static struct attribute_group cpu_root_attr_group = {  
    .attrs = cpu_root_attrs,   
};                          
                            
static const struct attribute_group *cpu_root_attr_groups[] = {  
    &cpu_root_attr_group,   
    NULL,                   
};

至此,cpu目录下全部讲解完毕.

2 cpuX目录下的节点信息

cpuX目录下的节点信息如下:

miX:/sys/devices/system/cpu/cpu0 # ls -l  
total 0  
-rw-r--r-- 1 root root 4096 2019-08-15 22:26 cpu_capacity  
lrwxrwxrwx 1 root root    0 2019-08-15 22:09 cpufreq -> ../cpufreq/policy0  
drwxr-xr-x 5 root root    0 2019-08-15 22:26 cpuidle  
drwxr-xr-x 2 root root    0 2019-08-15 22:26 hotplug  
-r--r--r-- 1 root root 4096 2019-08-15 22:26 isolate  
lrwxrwxrwx 1 root root    0 2019-08-15 22:26 of_node -> ../../../../firmware/devicetree/base/cpus/cpu@0  
-rw-r--r-- 1 root root 4096 2019-08-15 22:26 online  
drwxr-xr-x 2 root root    0 2019-08-15 22:26 power  
drwxr-xr-x 3 root root    0 2019-08-15 22:26 regs  
lrwxrwxrwx 1 root root    0 2019-08-15 22:26 subsystem -> ../../../../bus/cpu  
drwxr-xr-x 2 root root    0 2019-08-15 22:26 topology  
-rw-r--r-- 1 root root 4096 2019-08-15 22:26 uevent  

2.1 cpu_capacity

具体实现在driver/base/arch_topology.c文件中,这个数值是每个cpu的工作能力,数值越大,性能越好.

static int register_cpu_capacity_sysctl(void)  
{  
    int i;  
    struct device *cpu;  
   
    for_each_possible_cpu(i) {  
        cpu = get_cpu_device(i);  
        if (!cpu) {  
            pr_err("%s: too early to get CPU%d device!\n",  
            ┊   ┊  __func__, i);   
            continue;  
        }     
        device_create_file(cpu, &dev_attr_cpu_capacity);  
    }     
                                                                                                                                                                                                               
    return 0;  
}  
subsys_initcall(register_cpu_capacity_sysctl);

2.2 cpufreq目录

我们能够看到此目录是link到/sys/devices/system/cpu/cpufreq/policy0/上,上面已经知道此目录怎么来的,只需要知道怎么link的就OK.

int cpufreq_register_driver(struct cpufreq_driver *driver_data)  
{             
    unsigned long flags;    
    int ret;                                                                                                                                                                                                   
              
    if (cpufreq_disabled())  
        return -ENODEV;     
........................                                                
                            
    ret = subsys_interface_register(&cpufreq_interface);  
........................  
}  
  
static struct subsys_interface cpufreq_interface = {                                                                                                                                                           
    .name       = "cpufreq", 
     /*在每个cpuX目录下创建cpufreq*/     
    .subsys     = &cpu_subsys,    
    .add_dev    = cpufreq_add_dev,  
    .remove_dev = cpufreq_remove_dev,  
};                                
  
  
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)  
{          
    struct cpufreq_policy *policy;  
    unsigned cpu = dev->id;  
    int ret;  
           
    dev_dbg(dev, "%s: adding CPU%u\n", __func__, cpu);  
           
    if (cpu_online(cpu)) {  
        ret = cpufreq_online(cpu);  
        if (ret)  
            return ret;  
    }      
           
    /* Create sysfs link on CPU registration */  
    policy = per_cpu(cpufreq_cpu_data, cpu);  
    if (policy)  
        add_cpu_dev_symlink(policy, cpu);                                                                                                                                                                      
           
    return 0;  
}          
  
  
static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu)   
{     
    struct device *dev = get_cpu_device(cpu);  
      
    if (!dev)  
        return;  
      
    if (cpumask_test_and_set_cpu(cpu, policy->real_cpus))  
        return;  
      
    dev_dbg(dev, "%s: Adding symlink\n", __func__);
    /*此cpufreq目录link到policy->kobj目录*/  
    if (sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq"))                                                                                                                                               
        dev_err(dev, "cpufreq symlink creation failed\n");  
}     

2.3 cpuidle目录

节点信息如下:

miX:/sys/devices/system/cpu/cpu0 # ls cpuidle/ -l                                                                                                                                                      
total 0  
drwxr-xr-x 2 root root 0 2019-08-15 23:01 driver  
drwxr-xr-x 2 root root 0 2019-08-15 23:01 state0  
drwxr-xr-x 2 root root 0 2019-08-15 23:01 state1  

代码实现如下:

static int __init arm_idle_init(void)  
{   
    int cpu, ret;  
    struct cpuidle_driver *drv;  
    struct cpuidle_device *dev;  
    
    for_each_possible_cpu(cpu) {  
    
        drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);  
.................  
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);  
        if (!dev) {    
            pr_err("Failed to allocate cpuidle device\n");  
            ret = -ENOMEM;  
            goto out_unregister_drv;  
        }        
        dev->cpu = cpu;  
                 
        ret = cpuidle_register_device(dev);                                                                                                                                                                    
        if (ret) {  
            pr_err("Failed to register cpuidle device for CPU %d\n",  
            ┊   ┊  cpu);  
            goto out_kfree_dev;  
        }        
..............  
}  
  
int cpuidle_register_device(struct cpuidle_device *dev)  
{                  
    int ret = -EBUSY;  
                   
.................  
    ret = cpuidle_enable_device(dev);                                                                                                                                                                          
    if (ret)       
        goto out_sysfs;  
                   
.................  
}                  
  
int cpuidle_enable_device(struct cpuidle_device *dev)  
{    
...............     
    ret = cpuidle_add_device_sysfs(dev);  
    if (ret)  
        return ret;  
     
..............  
}    
  
int cpuidle_add_device_sysfs(struct cpuidle_device *device)                                                                                                                                                    
{         
    int ret;        
      
    ret = cpuidle_add_state_sysfs(device);  
    if (ret)        
        return ret;  
      
    ret = cpuidle_add_driver_sysfs(device);  
    if (ret)        
        cpuidle_remove_state_sysfs(device);  
    return ret;  
}         
  
static int cpuidle_add_state_sysfs(struct cpuidle_device *device)  
{    
    int i, ret = -ENOMEM;  
    struct cpuidle_state_kobj *kobj;  
    struct cpuidle_device_kobj *kdev = device->kobj_dev;  
    struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);  
     
    /* state statistics */  
    for (i = 0; i < drv->state_count; i++) {  
        kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);  
        if (!kobj) {  
            ret = -ENOMEM;  
            goto error_state;  
        }  
        kobj->state = &drv->states[i];  
        kobj->state_usage = &device->states_usage[i];  
        init_completion(&kobj->kobj_unregister);  
     
        ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,  
                    ┊  &kdev->kobj, "state%d", i);  
        if (ret) {  
            kfree(kobj);  
            goto error_state;  
        }  
        kobject_uevent(&kobj->kobj, KOBJ_ADD);  
        device->kobjs[i] = kobj;  
    }  
     
    return 0;  
     
error_state:  
    for (i = i - 1; i >= 0; i--)  
        cpuidle_free_state_kobj(device, i);  
    return ret;  
}  
  
static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)  
{     
    struct cpuidle_driver_kobj *kdrv;  
    struct cpuidle_device_kobj *kdev = dev->kobj_dev;  
    struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);  
    int ret;  
      
    kdrv = kzalloc(sizeof(*kdrv), GFP_KERNEL);  
    if (!kdrv)  
        return -ENOMEM;  
      
    kdrv->drv = drv;  
    init_completion(&kdrv->kobj_unregister);  
      
    ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,  
                ┊  &kdev->kobj, "driver");  
    if (ret) {  
        kfree(kdrv);  
        return ret;  
    }  
      
    kobject_uevent(&kdrv->kobj, KOBJ_ADD);  
    dev->kobj_driver = kdrv;  
      
    return ret;                                                                                                                                                                                                
}     

2.4 power目录

2.5 hotplug目录

2.4和2.5与第一章类似

2.6 online节点

这个节点重点讲解,很有意思,如下:

int device_register(struct device *dev)  
{             
    device_initialize(dev);  
    return device_add(dev);                                                                                                                                                                                  
}             
EXPORT_SYMBOL_GPL(device_register);  
  
int device_add(struct device *dev)  
{  
.........  
      error = device_add_attrs(dev);  
.........  
}  
  
int register_cpu(struct cpu *cpu, int num)  
{  
............  
     error = device_register(&cpu->dev);  
............  
}  
  
static int device_add_attrs(struct device *dev)  
{     
    struct class *class = dev->class;  
    const struct device_type *type = dev->type;  
    int error;  
      
....................  
    /*这里只要符合调节就可以创建online调节*/  
    if (device_supports_offline(dev) && !dev->offline_disabled) {  
        error = device_create_file(dev, &dev_attr_online);  
        if (error)  
            goto err_remove_dev_groups;  
    }  
      
    return 0;  
      
 ..............  
}     
  
  
static ssize_t online_show(struct device *dev, struct device_attribute *attr,  
             ┊ char *buf)  
{                
    bool val;    
                 
    device_lock(dev);  
    val = !dev->offline;  
    device_unlock(dev);  
    return sprintf(buf, "%u\n", val);  
}                
                 
static ssize_t online_store(struct device *dev, struct device_attribute *attr,  
             ┊  const char *buf, size_t count)  
{                
    bool val;    
    int ret;     
                 
    ret = strtobool(buf, &val);  
    if (ret < 0)  
        return ret;  
                 
    ret = lock_device_hotplug_sysfs();  
    if (ret)     
        return ret;  
                 
    ret = val ? device_online(dev) : device_offline(dev);  
    unlock_device_hotplug();  
    return ret < 0 ? ret : count;  
}                
static DEVICE_ATTR_RW(online);  

2.7 of_node和subsystem节点

过程与online节点创建走的是同一个路径

int device_register(struct device *dev)    
{               
    device_initialize(dev);    
    return device_add(dev);                                                                                                                                                                                    
}               
EXPORT_SYMBOL_GPL(device_register);    
    
int device_add(struct device *dev)    
{    
.........    
      error = device_add_class_symlinks(dev);   
.........    
}    
    
int register_cpu(struct cpu *cpu, int num)    
{    
............    
     error = device_register(&cpu->dev);    
...........  
}  
  
static int device_add_class_symlinks(struct device *dev)  
{            
    struct device_node *of_node = dev_of_node(dev);  
    int error;  
             
    if (of_node) {  
        error = sysfs_create_link(&dev->kobj, &of_node->kobj,"of_node");  
        if (error)  
            dev_warn(dev, "Error %d creating of_node link\n",error);  
        /* An error here doesn't warrant bringing down the device */  
    }        
             
    if (!dev->class)  
        return 0;  
             
    error = sysfs_create_link(&dev->kobj,  
                ┊ &dev->class->p->subsys.kobj,  
                ┊ "subsystem");  
............  
  
}  

2.8 topology目录

这个一个非常重要的目录
具体信息:

MIX5:/sys/devices/system/cpu/cpu0 # ls topology/ -l                                                                                                                                                     
total 0  
-r--r--r-- 1 root root 4096 2019-08-15 22:57 core_id  
-r--r--r-- 1 root root 4096 2019-08-15 22:57 core_siblings  
-r--r--r-- 1 root root 4096 2019-08-15 22:57 core_siblings_list  
-r--r--r-- 1 root root 4096 2019-08-15 22:57 physical_package_id  
-r--r--r-- 1 root root 4096 2019-08-15 22:57 thread_siblings  
-r--r--r-- 1 root root 4096 2019-08-15 22:57 thread_siblings_list  

具体含义如下:

  • core_id:某个cluster内的cpu id(从0开始)
  • core_siblings:处于同一个cluster内的所有cpu的cpumask bit位
  • core_siblings_list:bit位转化为list id显示
  • physical_package_id: cluster id
  • thread_siblings:cpu具体处在bit位的哪一个位置
  • thread_siblings_list:系统cpu id号

接口代码如下:

static struct attribute *default_attrs[] = {  
        &dev_attr_physical_package_id.attr,  
        &dev_attr_core_id.attr,  
        &dev_attr_thread_siblings.attr,  
        &dev_attr_thread_siblings_list.attr,  
        &dev_attr_core_siblings.attr,  
        &dev_attr_core_siblings_list.attr,  
#ifdef CONFIG_SCHED_BOOK  
        &dev_attr_book_id.attr,  
        &dev_attr_book_siblings.attr,  
        &dev_attr_book_siblings_list.attr,  
#endif  
#ifdef CONFIG_SCHED_DRAWER  
        &dev_attr_drawer_id.attr,  
        &dev_attr_drawer_siblings.attr,  
        &dev_attr_drawer_siblings_list.attr,  
#endif  
        NULL  
};  
  
static const struct attribute_group topology_attr_group = {  
        .attrs = default_attrs,  
        .name = "topology"  
};  
  
/* Add/Remove cpu_topology interface for CPU device */  
static int topology_add_dev(unsigned int cpu)  
{  
        struct device *dev = get_cpu_device(cpu);  
  
        return sysfs_create_group(&dev->kobj, &topology_attr_group);  
}  
  
static int topology_remove_dev(unsigned int cpu)  
{  
        struct device *dev = get_cpu_device(cpu);  
  
        sysfs_remove_group(&dev->kobj, &topology_attr_group);  
        return 0;  
}  
  
static int topology_sysfs_init(void)  
{  
        return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE,  
                                 "base/topology:prepare", topology_add_dev,  
                                 topology_remove_dev);  
}  
  
device_initcall(topology_sysfs_init);  

上面仅仅是实现接口 的代码,具体的topology下面各个节点的数值是在arch/arm64/kernel/topology.c文件中实现的, 当然是通过读取dts里面的配置信息得来的.

over!!!

发布了50 篇原创文章 · 获赞 34 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wuming_422103632/article/details/100043644
sys