Linux内核模块中cpufreq_get返回0的问题求助
看起来你在调用内核API cpufreq_get(3) 获取CPU频率时遇到了返回0的问题,结合你提到的内核配置正常、sysfs能读取频率的信息,咱们一步步来排查解决:
1. 先确认目标CPU是否存在且在线
首先要确保系统里真的有CPU3——CPU编号是从0开始计数的,你可以通过cat /proc/cpuinfo查看系统的CPU总数。如果你的系统CPU数量不足4,那调用cpufreq_get(3)自然会返回无效值(比如0)。
就算CPU存在,也要检查它是否处于在线状态,离线CPU的cpufreq policy不会被初始化,调用cpufreq_get()也会返回0。
2. 改用更可靠的policy读取方式
cpufreq_get()内部其实是获取目标CPU的cpufreq policy结构,然后返回policy->cur,但它没有做任何错误检查。如果policy未初始化,就会返回0。咱们可以手动做检查,代码示例如下:
#include <linux/cpufreq.h> #include <linux/smp.h> void func() { struct cpufreq_policy *policy; const unsigned int target_cpu = 3; // 第一步:检查CPU是否在线 if (!cpu_online(target_cpu)) { printk(KERN_ALERT "CPU %u is not online\n", target_cpu); return; } // 第二步:获取cpufreq policy policy = cpufreq_get_policy(target_cpu); if (!policy) { printk(KERN_ALERT "Failed to retrieve cpufreq policy for CPU %u\n", target_cpu); return; } // 第三步:读取当前频率 printk(KERN_ALERT "CPU %u Freq in KHz: %u\n", target_cpu, policy->cur); }
这种方式能明确排查出是CPU离线还是policy未初始化的问题,比直接调用cpufreq_get()更健壮。
3. 检查模块的加载时机与依赖
如果你的内核模块是在系统启动早期加载的,此时cpufreq子系统可能还没完成所有CPU的policy初始化。可以尝试:
- 先手动加载
cpufreq模块:modprobe cpufreq,再加载你的自定义模块 - 在模块代码中确保初始化逻辑在cpufreq子系统就绪后执行(比如使用
late_initcall()替代module_init())
4. Intel P-State驱动的特殊情况
因为你启用了CONFIG_X86_INTEL_PSTATE=y,Intel P-State驱动在某些模式下(比如主动模式),cpufreq的policy->cur可能不会实时更新,但sysfs能正常读取说明驱动工作正常。如果需要更直接的方式,也可以通过读取MSR寄存器获取频率(需要开启CONFIG_X86_MSR=y):
#include <asm/msr.h> unsigned int get_intel_cpu_freq_khz(unsigned int cpu) { uint64_t msr_val; unsigned int core_ratio, bus_freq; // 读取当前核心倍频(MSR_IA32_PERF_STATUS) rdmsrl_on_cpu(cpu, MSR_IA32_PERF_STATUS, &msr_val); core_ratio = (msr_val >> 0) & 0xffff; // 读取基准总线频率(这里假设是100MHz,部分CPU可能不同) // 也可以通过MSR_IA32_PERF_CTL读取,或者从sysfs获取总线频率 bus_freq = 100; return core_ratio * bus_freq; // 转换为KHz }
不过这种方法需要注意CPU型号的兼容性,不同Intel CPU的MSR定义可能有差异。
总结
最稳妥的方案是先检查CPU在线状态,再获取cpufreq policy并读取频率,这样能有效避免因CPU离线或policy未初始化导致的返回0问题。
内容的提问来源于stack exchange,提问作者sal_guy

