Linux动态频率调节系统CPUFreq之二:核心(core)架构与API

本文详细介绍了CPUFreq子系统的初始化过程、governor和driver的注册机制,以及为每个CPU建立频率调整策略的方法。深入探讨了核心层提供的API及其使用方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一节中,我们大致地讲解了一下CPUFreq在用户空间的sysfs接口和它的几个重要的数据结构,同时也提到,CPUFreq子系统把一些公共的代码逻辑组织在一起,构成了CPUFreq的核心部分,这些公共逻辑向CPUFreq和其它内核模块提供了必要的API,像cpufreq_governor、cpufreq_driver等模块通过这些API来完成一个完整的CPUFreq体系。这一节我们就来讨论一下核心架构的代码架构以及如何使用这些公共的API接口。

/*****************************************************************************************************/

声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!

/*****************************************************************************************************/

核心部分的代码都在:/drivers/cpufreq/cpufreq.c中,本系列文章我使用的内核版本是3.10.0.

1.  CPUFreq子系统的初始化


先看看具体的代码:

static int __init cpufreq_core_init(void)
{
        int cpu;

        if (cpufreq_disabled())
                return -ENODEV;

        for_each_possible_cpu(cpu) {
                per_cpu(cpufreq_policy_cpu, cpu) = -1;
                init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
        }

        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;
}
core_initcall(cpufreq_core_init);

可见,在系统的启动阶段,经由initcall机制,cpufreq_core_init被调用,由它来完成核心部分的初始化工作,其中:

cpufreq_policy_cpu    是一个per_cpu变量,在smp的系统下,每个cpu可以有自己独立的调频policy,也可以所有的cpu都是用一种policy,这时候就有可能出现其中一个cpu管理着某个policy,而其它cpu因为也使用同一个policy,这些cpu的policy的就交由那个管理cpu代管,这个per_cpu变量就是用来记录各个cpu的policy实际上是由那个cpu进行管理的。初始化时都被初始化为-1了,代表现在还没有开始进行policy的管理。

接下来的kobject_create_and_add函数在/sys/devices/system/cpu这个节点下建立了一个cpufreq节点,该节点的下面以后会用来放置当前governor的一些配置参数。参数cpu_subsys是内核的一个全局变量,是由更早期的初始化时初始化的,代码在drivers/base/cpu.c中:

struct bus_type cpu_subsys = {
        .name = "cpu",
        .dev_name = "cpu",
};
EXPORT_SYMBOL_GPL(cpu_subsys);


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总线,总线下挂着系统中所有的cpu,cpu总线设备的根目录就位于:/sys/devices/system/cpu,同时,/sys/bus下也会出现一个cpu的总线节点。cpu总线设备的根目录下会依次出现cpu0,cpu1,...... cpux节点,每个cpu对应其中的一个设备节点。CPUFreq子系统利用这个cpu_subsys来获取系统中的cpu设备,并在这些cpu设备下面建立相应的cpufreq对象,这个我们在后面再讨论。

这样看来,cpufreq子系统的初始化其实没有做什么重要的事情,只是初始化了几个per_cpu变量和建立了一个cpufreq文件节点。下图是初始化过程的序列图:


                                                                   图 1.1  核心层初始化

2.  注册cpufreq_governor


系统中可以同时存在多个governor策略,一个policy通过cpufreq_policy结构中的governor指针和某个governor相关联。要想一个governor被policy使用,首先要把该governor注册到cpufreq的核心中,我们可以通过核心层提供的API来完成注册:

int cpufreq_register_governor(struct cpufreq_governor *governor)
{
        int err;
        ......

        governor->initialized = 0;
        err = -EBUSY;
        if (__find_governor(governor->name) == NULL) {
                err = 0;
                list_add(&governor->governor_list, &cpufreq_governor_list);
        }

        ......
        return err;
}
核心层定义了一个全局链表变量:cpufreq_governor_list,注册函数首先根据governor的名称,通过__find_governor()函数查找该governor是否已經被注册过,如果没有被注册过,则把代表该governor的结构体添加到cpufreq_governor_list链表中。在上一篇中我们提到,目前的内核版本提供了5种governor供我们使用,我们可以通过内核的配置項来选择需要编译的governor,同时需要指定一个默认的governor。在cpufreq.h中,将会根据配置項的选择,把CPUFREQ_DEFAULT_GOVERNOR宏指向默认governor结构体变量的地址,在注册cpufreq_driver的阶段需要使用这个宏来设定系统默认使用的governor。

3.  注册一个cpufreq_driver驱动


与governor不同,系统中只会存在一个cpufreq_driver驱动,根据上一篇Linux动态频率调节系统CPUFreq之一:概述的介绍,cpufreq_driver是平台相关的,负责最终实施频率的调整动作,而选择工作频率的策略是由governor完成的。所以,系统中只需要注册一个cpufreq_driver即可,它只负责知道如何控制该平台的时钟系统,从而设定由governor确定的工作频率。注册cpufreq_driver驱动会触发cpufreq核心的一系列额外的初始化动作,第一节所说的核心初始化工作非常简单,实际上,更多的初始化动作在注册cpufreq_driver阶段完成。核心提供了一个API:cpufreq_register_driver来完成注册工作。下面我们分析一下这个函数的工作过程:

int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{
        ......

        if (cpufreq_disabled())
                return -ENODEV;

        if (!driver_data || !driver_data->verify || !driver_data->init ||
            ((!driver_data->setpolicy) && (!driver_data->target)))
                return -EINVAL;
该API只有一个参数:一个cpufreq_driver指针,driver_data,该结构事先在驱动的代码中定义,调用该API时作为参数传入。函数先判断系统目前是否禁止了调频功能,然后检查cpufreq_driver的几个回调函数是否被实现,由代码可以看出,verify和init回调函数必须要实现,而setpolicy和target回调则至少要被实现其中的一个。这几个回调的作用请参考本系列的第一篇文章。接下来:

 write_lock_irqsave(&cpufreq_driver_lock, flags);
        if (cpufreq_driver) {
                write_unlock_irqrestore(&cpufreq_driver_lock, flags);
                return -EBUSY;
        }
        cpufreq_driver = driver_data;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
检查全局变量cpufreq_driver是否已经被赋值,如果没有,则传入的参数被赋值给全局变量cpufreq_driver,从而保证了系统中只会注册一个cpufreq_driver驱动。然后:

        ret = subsys_interface_register(&cpufreq_interface);
        
        ......
        ...... 

        register_hotcpu_notifier(&cpufreq_cpu_notifier);
通过subsys_interface_register给每一个cpu建立一个cpufreq_policy,最后注册cpu hot plug通知,以便在cpu hot plug的时候,能够动态地处理各个cpu policy之间的关系(比如迁移负责管理的cpu等等)。这里要重点讨论一下subsys_interface_register的过程,回到第一节的内容,我们知道初始化阶段,cpu_subsys被建立,从而每个cpu都会在cpu总线设备下建立一个属于自己的设备:sys/devices/system/cpu/cpux。subsys_interface_register负责在cpu_subsys子系统的子设备下面注册公共的接口。我们看看参数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函数的代码我就不再展开了,它的大致作用就是:遍历子系统下面的每一个子设备,然后用这个子设备作为参数,调用cpufrq_interface结构的add_dev回调函数,这里的回调函数被指向了cpufreq_add_dev,它的具体工作方式我们在下一节中讨论。

driver注册完成后,驱动被保存在全局变量cpufreq_driver中,供核心层使用,同时,每个cpu也会建立自己的policy策略,governor也开始工作,实时地监控着cpu的负载并计算合适的工作频率,然后通过driver调整真正的工作频率。下图是cpufreq_driver注册过程的序列图:


                                                                             图 3.1   cpufreq_driver的注册过程

4.  为每个cpu建立频率调整策略(policy)


为每个cpu建立频率调整策略实在注册cpufreq_driver阶段的subsys_interface_registe函数中完成的,上一节已经提到,该函数最终会调用cpufreq_add_dev回调函数,现在展开这个函数分析一下:

因为subsys_interface_registe会枚举各个cpu设备,不管该cpu处于offline还是online状态,cpufreq_add_dev都会被调用,所以函数的一开始,判断如果cpu处于offline状态,直接返回。

static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{
        ......

        if (cpu_is_offline(cpu))
                return 0;
如果是smp系统,本cpu的policy可能和其他cpu共同使用同一个policy,并委托另一个叫做管理cpu的cpu进行管理,下面的代码判断这种情况,如果已经委托别的cpu管理,则直接返回,核心层定义了另一个per_cpu变量:cpufreq_cpu_data,用来保存各个cpu所使用的cpufreq_policy结构的指针,cpufreq_cpu_get函数实际上就是通过这个per_cpu变量,获取该指针,如果该指针非0,代表该cpu已经建立好了它自身的policy(可能是在他之前的管理cpu建立policy期间一并建立的)。

        policy = cpufreq_cpu_get(cpu);
        if (unlikely(policy)) {
                cpufreq_cpu_put(policy);
                return 0;
        }
因为cpu hot plug期间,cpufreq_add_dev也会被调用,下面的代码片段检测该cpu之前是否被hot-unpluged过,如果是,找到其中一个相关的cpu(这些相关的cpu都委托给同一个托管它cpu进行管理,调用cpufreq_add_policy_cpu函数,该函数只是简单地建立一个cpufreq链接,链接到管理cpu的cpufreq节点。

       for_each_online_cpu(sibling) {
                struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
                if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
                        read_unlock_irqrestore(&cpufreq_driver_lock, flags);
                        return cpufreq_add_policy_cpu(cpu, sibling, dev);
                }
        }
当这是系统初始化阶段第一次调用cpufreq_add_dev时(subsys_interface_register枚举到的第一个cpu,通常就是cpu0),cpufreq_cpu_data应该为NULL,所以我们要为这样的cpu分配一个cpufreq_policy结构,并初始化该policy所管理的cpu,包括online的cpus字段和online+offline的cpu_related字段,并把自己设置为这个policy的管理cpu,使用默认governor初始化policy->governor字段,同时吧自己加入到online的cpus字段中:

        policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
        if (!policy)
                goto nomem_out;

        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;

        policy->cpu = cpu;
        policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        cpumask_copy(policy->cpus, cpumask_of(cpu));

        /* Initially set CPU itself as the policy_cpu */
        per_cpu(cpufreq_policy_cpu, cpu) = cpu;
接下来初始化一个供kobject系统注销时使用的同步变量,初始化一个workqueue,某些时候不能马上执行对该policy的更新操作,可以使用该workqueue来延迟执行。

        init_completion(&policy->kobj_unregister);
        INIT_WORK(&policy->update, handle_update);
接着,调用cpufreq_driver的init回调,进一步初始化该policy:

       ret = cpufreq_driver->init(policy);
        if (ret) {
                pr_debug("initialization failed\n");
                goto err_set_policy_cpu;
        }
在上述驱动的初始化内部,应该完成以下工作:

  • 设定该cpu的最大和最小工作频率
  • 设定该policy的最大和最小工作频率
  • 设定该policy可供调节的频率档位
  • 设定cpu调节频率时的延迟时间特性
  • 该policy可以管理的cpu个数(policy->cpus)
继续:
        /* related cpus should atleast have policy->cpus */
        cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
注释已经写的很清楚了,把online的cpu加到代表online+offline的related字段中。接着,剔除offline的cpu:

        cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
然后,发出CPUFREQ_START通知:
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                                     CPUFREQ_START, policy);

如果是hot-plug加入的cpu,找出它上次使用的governor:
#ifdef CONFIG_HOTPLUG_CPU
        gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
        if (gov) {
                policy->governor = gov;
                pr_debug("Restoring governor %s for cpu %d\n",
                       policy->governor->name, cpu);
        }
#endif

最后,建立cpu设备下的sysfs文件节点:cpufreq,它的完整路径是:/sys/devices/system/cpu/cpux/cpufreq,同时,在他的下面,相应的sysfs节点也同时被建立,节点的内容请参考本系列的第一篇文章: Linux动态频率调节系统CPUFreq之一:概述
       ret = cpufreq_add_dev_interface(cpu, policy, dev);
至此,一个cpu的policy建立完成,它的频率限制条件、使用的governor策略,sysfs文件节点都已经建立完成。需要注意点是,系统中有多少个cpu,cpufreq_add_dev函数就会被调用多少次,最后,每个cpu都会建立自己的policy,当然,也有可能只有部分cpu建立了真正的policy,而其它cpu则委托这些cpu进行policy的管理,关于这一点,一开始读代码的时候可能有点困扰,为了搞清楚他们之间的关系,我们再跟入cpufreq_add_dev_interface函数看看:
static int cpufreq_add_dev_interface(unsigned int cpu,
                                     struct cpufreq_policy *policy,
                                     struct device *dev)
{
        ......

        /* prepare interface data */
        ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
                                   &dev->kobj, "cpufreq");
        ......

        /* set up files for this cpu device */
        drv_attr = cpufreq_driver->attr;
        while ((drv_attr) && (*drv_attr)) {
                ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
                if (ret)
                        goto err_out_kobj_put;
                drv_attr++;
        }
函数的一开始,建立cpufreq文件节点,然后在它的下面再建立一系列节点,用户可以通过这些文件节点控制该policy的一些参数。这不是我们的重点,我们看下面这一段代码:
        for_each_cpu(j, policy->cpus) {
                per_cpu(cpufreq_cpu_data, j) = policy;
                per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
        }
前面的代码已经设定了该policy所管理的online cpu:policy->cpus,通过两个per_cpu变量,这里把每个online cpu的policy都设置为了本cpu(管理cpu)的policy,并且把所有online的cpu的管理cpu也指定为了本cpu。接下来,cpufreq_add_dev_symlink被调用,所有policy->cpus指定的cpu会建立一个cpufreq链接,指向本cpu(管理cpu)的真实cpufreq节点:
        ret = cpufreq_add_dev_symlink(cpu, policy);

注意,假如这时的cpu是cpu0,也就是说,其它cpu的cpufreq_add_dev还没有被调用,但是在cpufreq_cpu_data中,与之对应的policy指针已经被赋值为cpu0所对应的policy,这样,回到cpufreq_add_dev函数的开头部分,当接下其它被认为使用cpu0托管他们的policy的cpu也会进入cpufreq_add_dev函数,但是,因为cpufreq_cpu_data中对应的policy已经在cpu0的建立阶段被赋值,所以这些cpu他们不会走完所有的流程,在函数的开头的判断部分,判断cpufreq_cpu_data中cpu对应的policy已经被赋值,就直接返回了。
接着往下看cpufreq_add_dev_interface的代码:
        memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
        /* assure that the starting sequence is run in __cpufreq_set_policy */
        policy->governor = NULL;

        /* set default policy */
        ret = __cpufreq_set_policy(policy, &new_policy);
        policy->user_policy.policy = policy->policy;
        policy->user_policy.governor = policy->governor;
通过__cpufreq_set_policy函数,最终使得该policy正式生效。到这里,每个cpu的policy已经建立完毕,并正式开始工作。关于__cpufreq_set_policy的代码这里就不展开了,我只给出它的序列图:

                                                                               图 4.1  设置一个cpufreq_policy

5.  其它API


cpufreq的核心层除了提供上面几节讨论的注册governor,注册cpufreq_driver等API外,还提供了其他一些辅助的API,以方便其它模块的使用。

  • int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
  • int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);

以上两个API用于注册和注销cpufreq系统的通知消息,第二个参数可以选择通知的类型,可以有以下两种类型:

  • CPUFREQ_TRANSITION_NOTIFIER      收到频率变更通知
  • CPUFREQ_POLICY_NOTIFIER               收到policy更新通知

  • int cpufreq_driver_target(struct cpufreq_policy *policy,
                                     unsigned int target_freq,
                                     unsigned int relation);
  • int __cpufreq_driver_target(struct cpufreq_policy *policy,
                                       unsigned int target_freq,
                                       unsigned int relation);
以上两个API用来设置cpu的工作频率,区别在于cpufreq_driver_target是带锁的版本,而__cpufreq_driver_target是不带锁的版本,如果确定是在governor的上下文中,使用不带锁的版本,否则需要使用带锁的版本。

  • void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max);
这个API用来检查并重新设定policy的最大和最小频率。

  • int cpufreq_update_policy(unsigned int cpu);
这个API用来触发cpufreq核心进行policy的更新操作。





Starting Permit User Sessions... [ OK ] Reached target Network is Online. Starting LSB: HPA's tftp server... Starting /etc/rc.local Compatibility... [ OK ] Started Permit User Sessions. Starting Hostname Service... [ 7.873790] IPVS: Creating netns size=1592 id=1 Starting Light Display Manager... [ OK ] Started LSB: set CPUFreq kernel parameters. [ OK ] Started /etc/rc.local Compatibility. [ 7.616476] rc.local[514]: ssh-keygen: generating new host keys: RSA resize2fs 1.44.5 (15-Dec-2018) [ 7.944371] [WLAN_RFKILL]: rockchip_wifi_get_oob_irq: Enter [ 7.946454] ------------[ cut here ]------------ [ 7.946457] WARNING: at drivers/gpu/drm/rockchip/cdn-dp-reg.c:280 [ 7.946463] Modules linked in: 8188eu(+) [ 7.946464] [ 7.946470] CPU: 5 PID: 582 Comm: mcu_init_arm Not tainted 4.4.194 #45 [ 7.946471] Hardware name: EMB-3531-V2.2 (DT) [ 7.946474] task: ffffffc0734c9b00 task.stack: ffffffc075e74000 [ 7.946491] PC is at cdn_dp_dpcd_write+0x30/0x144 [ 7.946495] LR is at cdn_dp_aux_transfer+0x70/0xd0 [ 7.946497] pc : [<ffffff80084f0b8c>] lr : [<ffffff80084ee364>] pstate: 80000145 [ 7.946498] sp : ffffffc075e77b40 [ 7.946501] x29: ffffffc075e77b40 x28: ffffffc0734c9b00 [ 7.946504] x27: ffffff8008e74127 x26: 0000000000000000 [ 7.946506] x25: ffffff8008c03e70 x24: ffffff8008c03000 [ 7.946508] x23: 0000000000000000 x22: 000000000000007d [ 7.946511] x21: ffffffc00a27b028 x20: 0000000000000000 [ 7.946513] x19: 0000000000000000 x18: 0000000000000fff [ 7.946516] x17: 0000007fb35970f0 x16: ffffff80081c486c [ 7.946518] x15: 0000000000000020 x14: 000000000000000a [ 7.946520] x13: 000000000000000a x12: 0000000000000000 [ 7.946522] x11: 0000000000000000 x10: 0000000000000000 [ 7.946524] x9 : ffffff80ffffffd0 x8 : 03c609a613edac00 [ 7.946527] x7 : 0000007fec49e5f8 x6 : ffffffc078ee17a2 [ 7.946529] x5 : ffffffc078ee17a2 x4 : ffffffc00a27b5f8 [ 7.946531] x3 : 0000000000000000 x2 : 0000000000000000 [ 7.946533] x1 : 000000000000007d x0 : ffffff80084ee364 [ 7.946535] [ 7.946535] PC: 0xffffff80084f0b0c: [ 7.946542] 0b0c 92403ea0 a94153f3 a9425bf5 f9401bf7 a8c57bfd d65f03c0 f9400280 2a1303e6 [ 7.946548] 0b2c b0004c45 f0004c04 912010a5 9138a084 90003923 52800002 911ba063 f0004a21 [ 7.946554] 0b4c 913d9821 97ff7220 93407e60 17ffffee a9ba7bfd 910003fd a90153f3 a9025bf5 [ 7.946559] 0b6c 12003c74 aa0003f5 2a0103f6 aa0203f3 aa1e03e0 d503201f 7100529f 540000e9 [ 7.946565] 0b8c d4210000 928002a0 a94153f3 a9425bf5 a8c67bfd d65f03c0 34ffff54 53107ec0 [ 7.946571] 0bac 39010ba0 53087ec0 aa1303e1 39010fa0 92403e82 390103bf 910117a0 390107b4 [ 7.946576] 0bcc 390113b6 97fb58dc 11001683 910103a4 52800082 52800021 aa1503e0 97fffea7 [ 7.946582] 0bec 2a0003f3 350003a0 528000a3 52800082 52800021 aa1503e0 97fffef3 2a0003f3 [ 7.946583] [ 7.946583] LR: 0xffffff80084ee2e4: [ 7.946589] e2e4 d289c401 d2827120 9419b0ea 17ffffdc a9bd7bfd 910003fd a90153f3 f90013f5 [ 7.946595] e304 aa0103f3 aa0003f5 aa1e03e0 d503201f d11602b5 39401260 121d7801 7100243f [ 7.946600] e324 5400012c d2800020 9ac12000 d28020a1 ea01001f 540000c1 d2804041 ea01001f [ 7.946606] e344 54000261 928002a0 1400000d 79402263 aa1503e0 b9400261 f9400662 940009ff [ 7.946611] e364 2a0003f4 aa1503e0 94000a4d 72001c00 540001a1 3900167f 93407e80 a94153f3 [ 7.946617] e384 f94013f5 a8c37bfd d65f03c0 79402263 aa1503e0 b9400261 f9400662 940009ac [ 7.946623] e3a4 17fffff0 7100041f 54000061 39001660 17fffff2 7100081f 54fffe01 17fffffc [ 7.946628] e3c4 a9bd7bfd 910003fd a90153f3 f90013f5 aa0003f3 12001c55 aa1e03e0 d503201f [ 7.946630] [ 7.946630] SP: 0xffffffc075e77ac0: [ 7.946636] 7ac0 0000007d 00000000 00000000 00000000 08c03000 ffffff80 08c03e70 ffffff80 [ 7.946641] 7ae0 00000000 00000000 08e74127 ffffff80 734c9b00 ffffffc0 75e77b40 ffffffc0 [ 7.946647] 7b00 084ee364 ffffff80 75e77b40 ffffffc0 084f0b8c ffffff80 80000145 00000000 [ 7.946653] 7b20 75e77b50 ffffffc0 08b5b198 ffffff80 00000000 00000080 08b5b238 ffffff80 [ 7.946659] 7b40 75e77ba0 ffffffc0 084ee364 ffffff80 75e77ca0 ffffffc0 75e77ca0 ffffffc0 [ 7.946665] 7b60 0a27b028 ffffffc0 0a27b5a8 ffffffc0 75e77b90 ffffffc0 081c7a14 ffffff80 [ 7.946670] 7b80 7b025288 ffffffc0 081c7a00 ffffff80 75e77bc0 ffffffc0 081d144c ffffff80 [ 7.946676] 7ba0 75e77bd0 ffffffc0 084b8178 ffffff80 00000007 00000000 75e77ca0 ffffffc0 [ 7.946677] [ 7.946677] X0: 0xffffff80084ee2e4: [ 7.946683] e2e4 d289c401 d2827120 9419b0ea 17ffffdc a9bd7bfd 910003fd a90153f3 f90013f5 [ 7.946689] e304 aa0103f3 aa0003f5 aa1e03e0 d503201f d11602b5 39401260 121d7801 7100243f [ 7.946695] e324 5400012c d2800020 9ac12000 d28020a1 ea01001f 540000c1 d2804041 ea01001f [ 7.946700] e344 54000261 928002a0 1400000d 79402263 aa1503e0 b9400261 f9400662 940009ff [ 7.946706] e364 2a0003f4 aa1503e0 94000a4d 72001c00 540001a1 3900167f 93407e80 a94153f3 [ 7.946712] e384 f94013f5 a8c37bfd d65f03c0 79402263 aa1503e0 b9400261 f9400662 940009ac [ 7.946717] e3a4 17fffff0 7100041f 54000061 39001660 17fffff2 7100081f 54fffe01 17fffffc [ 7.946723] e3c4 a9bd7bfd 910003fd a90153f3 f90013f5 aa0003f3 12001c55 aa1e03e0 d503201f [ 7.946725] [ 7.946725] X4: 0xffffffc00a27b578: [ 7.946730] b578 7ae36000 ffffffc0 00000000 00000000 0a27b588 ffffffc0 0a27b588 ffffffc0 [ 7.946736] b598 084f00a8 ffffff80 00000000 00000000 08e79220 ffffff80 00000000 00000000 [ 7.946742] b5b8 00000008 00000000 08c03e38 ffffff80 0a27b5a8 ffffffc0 00000000 dead4ead [ 7.946747] b5d8 ffffffff 00000000 ffffffff ffffffff 00000000 00000000 00000000 00000000 [ 7.946753] b5f8 734c9b00 ffffffc0 000003e8 00000003 7c353810 ffffffc0 7ae103c0 ffffffc0 [ 7.946758] b618 7ae11840 ffffffc0 7ae35818 ffffffc0 7ae35418 ffffffc0 7c353820 ffffffc0 [ 7.946764] b638 7c1c6180 ffffffc0 09197328 ffffff80 7ae132d0 ffffffc0 00000006 00000007 [ 7.946770] b658 00000000 00000000 091dc418 ffffff80 00000001 00000000 00000000 dead4ead [ 7.946771] [ 7.946771] X5: 0xffffffc078ee1722: [ 7.946776] 1720 00000001 00000000 00000000 00000000 00000000 00000000 00000054 00000000 [ 7.946782] 1740 78ee1700 ffffffc0 7a082680 ffffffc0 00000100 dead0000 00000200 dead0000 [ 7.946788] 1760 7a0b72a0 ffffffc0 75cee6e0 ffffffc0 7aed6760 ffffffc0 00000054 00000000 [ 7.946793] 1780 00000000 00000000 ec49e5f8 0000007f 13edac00 03c609a6 00000000 00000000 [ 7.946799] 17a0 0000ac00 00000000 00000000 00000000 00000000 00000000 000000bc 00000000 [ 7.946804] 17c0 78ee1800 ffffffc0 7a0826e8 ffffffc0 00000100 dead0000 00000200 dead0000 [ 7.946810] 17e0 75cee660 ffffffc0 00000000 00000000 00000000 00000000 000000bc 00000000 [ 7.946816] 1800 78ee1840 ffffffc0 78e3ea28 ffffffc0 00000100 dead0000 00000200 dead0000 [ 7.946821] 1820 00000001 00000000 00000000 00000000 00000000 00000000 000000b7 00000000 [ 7.946822] [ 7.946822] X6: 0xffffffc078ee1722: [ 7.946828] 1720 00000001 00000000 00000000 00000000 00000000 00000000 00000054 00000000 [ 7.946833] 1740 78ee1700 ffffffc0 7a082680 ffffffc0 00000100 dead0000 00000200 dead0000 [ 7.946839] 1760 7a0b72a0 ffffffc0 75cee6e0 ffffffc0 7aed6760 ffffffc0 00000054 00000000 [ 7.946846] 1780 00000000 00000000 ec49e5f8 0000007f 13edac00 03c609a6 00000000 00000000 [ 7.946852] 17a0 0000ac00 00000000 00000000 00000000 00000000 00000000 000000bc 00000000 [ 7.946857] 17c0 78ee1800 ffffffc0 7a0826e8 ffffffc0 00000100 dead0000 00000200 dead0000 [ 7.946863] 17e0 75cee660 ffffffc0 00000000 00000000 00000000 00000000 000000bc 00000000 [ 7.946869] 1800 78ee1840 ffffffc0 78e3ea28 ffffffc0 00000100 dead0000 00000200 dead0000 [ 7.946874] 1820 00000001 00000000 00000000 00000000 00000000 00000000 000000b7 00000000 [ 7.946876] [ 7.946876] X9: 0xffffff80ffffff50: [ 7.946887] ff50 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946894] ff70 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946901] ff90 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946908] ffb0 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946915] ffd0 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946922] fff0 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946929] 0010 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946936] 0030 ******** ******** ******** ******** ******** ******** ******** ******** [ 7.946938] [ 7.946938] X16: 0xffffff80081c47ec: [ 7.946945] 47ec 35ffe093 f9404ea0 93407c21 f9401c02 aa1503e0 d63f0040 aa1403e1 f94006c2 [ 7.946951] 480c b1001021 fa423022 9a9f87e3 b4ffef83 d503201f b9000280 d503201f 17fffef5 [ 7.946957] 482c d5384100 f9400401 aa1403e0 b1001000 fa413002 9a9f87e2 b4ffee22 d503201f [ 7.946962] 484c f9404ea1 f94026c0 4b010000 17ffffc5 12800bd3 17fffee7 128002b3 17fffee5 [ 7.946968] 486c a9bc7bfd 910003fd a90153f3 a9025bf5 f9001bf7 aa0003f3 aa0103f6 aa1e03e0 [ 7.946974] 488c aa0203f7 d503201f 2a1303e0 94002701 aa0003f4 f27ef415 54000200 2a1303e1 [ 7.946979] 48ac aa1703e3 2a1603e2 aa1503e0 97fffe9b 2a0003f3 36000074 aa1503e0 97ffc0d2 [ 7.946985] 48cc 93407e60 a94153f3 a9425bf5 f9401bf7 a8c47bfd d65f03c0 92800100 17fffffa [ 7.946987] [ 7.946987] X21: 0xffffffc00a27afa8: [ 7.946992] afa8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.946998] afc8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.947003] afe8 00000000 00000000 00000000 00000000 00000000 00000000 7b505bc0 ffffffc0 [ 7.947009] b008 7c353af0 ffffffc0 0858a124 ffffff80 08e9f77f ffffff80 00000e48 00000000 [ 7.947015] b028 7c353810 ffffffc0 7b6b9800 ffffffc0 7b6b9800 ffffffc0 00000000 00000000 [ 7.947020] b048 7ae36800 ffffffc0 00000000 00000000 7b6b9c70 ffffffc0 0a27c048 ffffffc0 [ 7.947026] b068 00000063 c0c0c0c0 0a27b180 ffffffc0 7ae11b00 ffffffc0 0000000a 00000001 [ 7.947032] b088 00000000 00000000 0a27b090 ffffffc0 0a27b090 ffffffc0 00000002 00000000 [ 7.947033] [ 7.947033] X24: 0xffffff8008c02f80: [ 7.947039] 2f80 6d6d6f69 6e755f75 0070616d 00000000 6d6d6f69 616d5f75 00000070 00000000 [ 7.947045] 2fa0 6d6d6f69 72675f75 5f70756f 656c6572 00657361 00000000 6d6d6f69 72675f75 [ 7.947051] 2fc0 5f70756f 6f6c6c61 00000063 00000000 084acb18 ffffff80 084acb68 ffffff80 [ 7.947057] 2fe0 6d6d6f69 00000075 08f1ec2b ffffff80 00000000 00000000 00000000 00000000 [ 7.947062] 3000 09468b50 ffffff80 00000000 00000000 00000000 00000000 084b3250 ffffff80 [ 7.947068] 3020 084b312c ffffff80 084b39f0 ffffff80 084b3804 ffffff80 084b2d34 ffffff80 [ 7.947073] 3040 084b2c78 ffffff80 084b2a30 ffffff80 084b28f4 ffffff80 084b34a8 ffffff80 [ 7.947079] 3060 084b3d74 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.947080] [ 7.947080] X25: 0xffffff8008c03df0: [ 7.947086] 3df0 6f665f65 5f656372 65646f6d 00000000 5f6d7264 63747263 6c65685f 5f726570 [ 7.947092] 3e10 5f746573 666e6f63 00006769 00000000 5f6d7264 645f7064 5f646370 65636361 [ 7.947097] 3e30 00007373 00000000 084b8398 ffffff80 00000000 00000000 084b78f8 ffffff80 [ 7.947103] 3e50 01b92200 00000001 5f6d7264 725f7064 5f646165 63736564 00000000 00000000 [ 7.947108] 3e70 5f6d7264 695f7064 645f6332 736d5f6f 00000067 00000000 5f6d7264 695f7064 [ 7.947114] 3e90 645f6332 6e696172 67736d5f 00000000 5f6d7264 5f736d6b 706c6568 642e7265 [ 7.947120] 3eb0 75615f70 32695f78 72745f63 66736e61 735f7265 00657a69 5f6d7264 5f736d6b [ 7.947125] 3ed0 706c6568 642e7265 75615f70 32695f78 70735f63 5f646565 007a686b 00000000 [ 7.947127] [ 7.947127] X27: 0xffffff8008e740a7: [ 7.947132] 40a4 736e6172 69746361 66206e6f 656c6961 25203a64 6e000a64 76697461 616e2065 [ 7.947138] 40c4 28206b63 75736572 253d746c 73202c64 3d657a69 29757a25 616e000a 65766974 [ 7.947144] 40e4 66656420 000a7265 61766e69 2064696c 6974616e 72206576 796c7065 30232520 [ 7.947150] 4104 000a7834 20433249 6b63616e 65722820 746c7573 2c64253d 7a697320 7a253d65 [ 7.947155] 4124 49000a75 64204332 72656665 6e69000a 696c6176 32492064 65722043 20796c70 [ 7.947161] 4144 34302325 50000a78 69747261 49206c61 72204332 796c7065 6572203a 73657571 [ 7.947167] 4164 20646574 20757a25 65747962 6f672073 64252074 74796220 000a7365 4e4f435b [ 7.947173] 4184 5443454e 253a524f 73253a64 7473205d 73757461 64707520 64657461 6f726620 [ 7.947178] 41a4 7325206d 206f7420 000a7325 4e4f435b 5443454e 253a524f 73253a64 7473205d [ 7.947179] [ 7.947179] X28: 0xffffffc0734c9a80: [ 7.947185] 9a80 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.947191] 9aa0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.947196] 9ac0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.947202] 9ae0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff [ 7.947207] 9b00 00000010 00000000 ffffffff ffffffff 00000000 00000000 00000000 00000000 [ 7.947213] 9b20 75e74000 ffffffc0 00000002 00404000 00000000 00000000 00000000 00000000 [ 7.947218] 9b40 00000001 00000005 00000097 00000000 fffb8934 00000000 7c005100 ffffffc0 [ 7.947224] 9b60 00000005 00000001 00000078 00000078 00000078 00000000 08b78590 ffffff80 [ 7.947225] [ 7.947225] X29: 0xffffffc075e77ac0: [ 7.947231] 7ac0 0000007d 00000000 00000000 00000000 08c03000 ffffff80 08c03e70 ffffff80 [ 7.947236] 7ae0 00000000 00000000 08e74127 ffffff80 734c9b00 ffffffc0 75e77b40 ffffffc0 [ 7.947242] 7b00 084ee364 ffffff80 75e77b40 ffffffc0 084f0b8c ffffff80 80000145 00000000 [ 7.947248] 7b20 75e77b50 ffffffc0 08b5b198 ffffff80 00000000 00000080 08b5b238 ffffff80 [ 7.947253] 7b40 75e77ba0 ffffffc0 084ee364 ffffff80 75e77ca0 ffffffc0 75e77ca0 ffffffc0 [ 7.947259] 7b60 0a27b028 ffffffc0 0a27b5a8 ffffffc0 75e77b90 ffffffc0 081c7a14 ffffff80 [ 7.947265] 7b80 7b025288 ffffffc0 081c7a00 ffffff80 75e77bc0 ffffffc0 081d144c ffffff80 [ 7.947270] 7ba0 75e77bd0 ffffffc0 084b8178 ffffff80 00000007 00000000 75e77ca0 ffffffc0 [ 7.947271] [ 7.947272] ---[ end trace 5bc09093fa496094 ]--- [ 7.947274] Call trace: [ 7.947277] Exception stack(0xffffffc075e77960 to 0xffffffc075e77a90) [ 7.947280] 7960: 0000000000000000 0000008000000000 ffffffc075e77b40 ffffff80084f0b8c [ 7.947282] 7980: 0000000080000145 ffffffc07b5ca900 ffffffc075e77a10 ffffff80080d9f1c [ 7.947284] 79a0: ffffffc07ef5a280 ffffffc07b5ca880 ffffffc0734c9b80 ffffffc07b5ca900 [ 7.947286] 79c0: ffffffc07ef5a308 0000000000000000 ffffffc07ef5a280 0000000000000000 [ 7.947288] 79e0: ffffff80090ff000 ffffffc0734ca168 ffffffc075e77a00 ffffff80083d2374 [ 7.947290] 7a00: ffffffc075e77a50 ffffff80083d336c ffffff80084ee364 000000000000007d [ 7.947292] 7a20: 0000000000000000 0000000000000000 ffffffc00a27b5f8 ffffffc078ee17a2 [ 7.947294] 7a40: ffffffc078ee17a2 0000007fec49e5f8 03c609a613edac00 ffffff80ffffffd0 [ 7.947296] 7a60: 0000000000000000 0000000000000000 0000000000000000 000000000000000a [ 7.947297] 7a80: 000000000000000a 0000000000000020 [ 7.947301] [<ffffff80084f0b8c>] cdn_dp_dpcd_write+0x30/0x144 [ 7.947303] [<ffffff80084ee364>] cdn_dp_aux_transfer+0x70/0xd0 [ 7.947309] [<ffffff80084b8178>] drm_dp_i2c_do_msg+0xf0/0x310 [ 7.947311] [<ffffff80084b8490>] drm_dp_i2c_xfer+0xf8/0x218 [ 7.947318] [<ffffff800877b728>] __i2c_transfer+0x35c/0x418 [ 7.947320] [<ffffff800877b854>] i2c_transfer+0x70/0xbc [ 7.947323] [<ffffff800877e110>] i2cdev_ioctl_rdwr.isra.4+0xe8/0x20c [ 7.947325] [<ffffff800877e414>] i2cdev_ioctl+0x1e0/0x228 [ 7.947330] [<ffffff80081c43c0>] do_vfs_ioctl+0x9c/0x548 [ 7.947334] [<ffffff80081c48bc>] SyS_ioctl+0x50/0x80 [ 7.947339] [<ffffff8008082f70>] el0_svc_naked+0x24/0x28 [ 9.312941] [WLAN_RFKILL]: rockchip_wifi_get_oob_irq: rfkill-wlan driver has not Successful initialized 开机日志这样是有什么问题吗
最新发布
06-12
<think>嗯,用户现在问的是Linux系统启动日志中出现的"WARNING"和"Calltrace"错误可能由哪些模块或驱动引起。之前用户讨论过WiFi6和WiFi7的技术对比,但当前问题完全转向了Linux系统调试领域,需要独立分析。用户引用中提到了dmesg工具和内核日志机制的相关说明,这提供了理论基础。不过用户真正的痛点是:看到启动报错但不知道如何定位根源。ta可能正在尝试解决一台Linux设备的启动故障,需要具体排查思路而非泛泛而谈。从技术角度看,"Calltrace"(调用跟踪)是内核异常的关键线索——它本质是处理器寄存器状态的快照。其中"PC"寄存器(程序计数器)指向崩溃瞬间的代码位置,结合"LR"(链接寄存器)能重建函数调用栈。常见的罪魁祸首包括:内存控制器驱动故障(如EDAC报错)、存储驱动(SATA/NVMe初始化失败)、中断控制器配置冲突(GIC/APIC错误)等。而"WARNING"相对温和,通常是子系统检测到异常参数,例如时钟源驱动发现偏差过大(clocksource)、文件系统加载异常(ext4/xfs元数据损坏)或PCI设备枚举冲突。安全提示也很重要:必须警告用户勿盲目修改驱动参数,有些调用跟踪可能是硬件故障导致的(如RAM位翻转),这时需要运行memtester等工具检测物理设备。相关性问题可延伸设备调试方向:如何捕获宕机瞬间完整堆栈?怎样测试驱动兼容性?这些都是用户后续可能需要的。</think> 以下是对Linux系统启动日志中"WARNING"和"Call trace"错误的专业分析及排查指南,结合内核日志机制原理逐步说明: ### 一、关键错误类型根源分析 1. **WARNING类错误** - **硬件驱动模块**(出现频率>60%) - 存储驱动问题:`ata_piix`, `nvme`, `sdhci`等驱动在检测到磁盘异常时会告警 *示例*:`ata1.00: exception Emask 0x52 SAct 0x0` - 外设驱动异常:`usbcore`, `xhci_hcd`等USB驱动在设备枚举失败时触发 - **内核子系统** - 时钟管理:`clocksource`在计时器同步异常时告警 *示例*:`clocksource: timekeeping watchdog on CPU2` - 内存管理:`mmc`或`EDAC`模块检测到内存ECC错误 - 文件系统:`ext4-fs`, `XFS`挂载参数错误 - **固件兼容性** - ACPI表解析冲突:`ACPI Warning: Missing FACS`[^1] 2. **Call trace类错误** - **驱动缺陷**(80%以上案例根源) *典型模式*: ``` Call Trace: [<ffff000008083dc0>] __schedule_bug+0x4c/0x58 [<ffff000008e23400>] sdhci_pre_req+0x168/0x1e4 <-- 驱动函数调用点 ``` - **硬件故障** 内存地址错误:`BUG: unable to handle kernel paging request at ffff0000xxxxxxxx` 寄存器异常:`Internal error: Oops - BAD mode [#1] PREEMPT SMP` - **内核竞争条件** spinlock死锁:`INFO: task kworker/u8:5: state D stack...` - **固件指令集不兼容** ARM架构常见错误:`opcode: 1d85b8de` ### 二、诊断步骤(实操流程图) ```mermaid graph TD A[dmesg -T | grep -E 'WARNING|Call Trace'] --> B[提取触发模块名] B --> C{错误类型判断} C -->|WARNING| D[检查驱动加载顺序] C -->|Call trace| E[分析崩溃函数栈] D --> F[modinfo 检查驱动依赖] E --> G[addr2line转换地址] F/G --> H[定位源码文件] H --> I[更新驱动/内核/固件] ``` ### 三、关键排查工具 1. **地址解析** 当出现崩溃地址`[<ffff000008e23400>]`时: ```bash addr2line -e /usr/lib/debug/boot/vmlinux-$(uname -r) ffff000008e23400 ``` *输出示例*:`drivers/mmc/host/sdhci.c:2285` 2. **驱动状态检查** ```bash lsmod | grep sdhci # 检查驱动加载状态 dmesg -t | grep sdhci | tail -20 # 查看相关日志 ``` 3. **硬件检测命令** ```bash lspci -vvv | grep -i sata # 存储设备检测 dmidecode -t memory # 内存硬件信息 ``` ### 四、典型案例解决方案 1. **USB控制器警告** *日志*:`xhci_hcd: WARNING: unexpected command opcode 0x...` **处理**: ```bash echo 1 > /sys/bus/pci/devices/0000\:00\:14.0/remove # 移除设备 echo 1 > /sys/bus/pci/rescan # 重新加载 ``` 2. **内存页表Call trace** *错误*:`BUG: Unable to handle kernel paging request` **处理**:更新BIOS并执行内存测试: ```bash memtester 2G 5 # 测试2GB内存运行5轮 ``` > **重要原则**:当调用跟踪涉及多个模块时(如`scheduler`和`nvme`交互错误),需重点检查驱动间API兼容性,建议升级内核至LTS版本或禁用相关驱动`modprobe -r nvme`
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值