运用debugfs调试方法
DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据。类似的虚拟文件系统还有procfs和sysfs等,这几种虚拟文件系统都并不实际存储在硬盘上,而是Linux内核运行起来后才建立起来。
通常情况下,最常用的内核调试手段是printk。但printk并不是所有情况都好用,比如打印的数据可能过多,我们真正关心的数据在大量的输出里不是那么一目了然;或者我们在调试时可能需要修改某些内核变量,这种情况下printk就无能为力,而如果为了修改某个值重新编译内核或者驱动又过于低效,此时就需要一个临时的文件系统可以把我们需要关心的数据映射到用户空间。在过去,procfs可以实现这个目的,到了2.6时代,新引入的sysfs也同样可以实现,但不论是procfs或是sysfs,用它们来实现某些debug的需求,似乎偏离了它们创建的本意。比如procfs,其目的是反映进程的状态信息;而sysfs主要用于Linux设备模型。不论是procfs或是sysfs的接口应该保持相对稳定,因为用户态程序很可能会依赖它们。当然,如果我们只是临时借用procfs或者sysfs来作debug之用,在代码发布之前将相关调试代码删除也无不可。但如果相关的调试借口要在相当长的一段时间内存在于内核之中,就不太适合放在procfs和sysfs里了。故此,debugfs应运而生。
以上摘自互联网中,详解了debugfs的好处。我么知道在kernel里面许多大型模块都使用了debugfs调试,像qualcomm display中就使用了许多,可以打印mdp等内部各个参数的值,对调试大型模块起到了至关重要作用。
对于模块出现问题使用debugfs来调试是非常好的,前提是模块中有debugfs的加入。我们通常都是在出现问题之后才添加log来跟踪。记得有个蓝屏问题提case给高通,高通就要求在debugfs中cat mdp statues,来判断mdp有没有正常工作。
本文中以pm8921_chg.c详叙使用debugfs调试寄存器以及中断方法。绕dmesg,在debugfs中查看CHG的IRG还是非常重要的,
在模块中添加debugfs来实现自己的分析方法。当然要想在模块出现问题时就能使用自己添加的debugfs就ok了。
.
/*cat时被调用——读
data的值为寄存器地址,在debugfs_create_file()第四个参数中填入;
*val为cat的值
*/
static int get_reg(void *data, u64 * val)
{
int addr = (int)data;
int ret;
u8 temp;
ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
if (ret) {
pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
addr, temp, ret);
return -EAGAIN;
}
printk("%s data = 0x%02x, val= x%02x\n",__func__,addr,temp);
*val = temp;
return 0;
}
/*echo时被调用——写
data值同上
val为写入的值
*/
static int set_reg(void *data, u64 val)
{
int addr = (int)data;
int ret;
u8 temp;
temp = (u8) val;
printk("%s data = 0x%02x, val= x%02x\n",__func__,addr,temp);
ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
if (ret) {
pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
addr, temp, ret);
return -EAGAIN;
}
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
/*获取中断状态文件操作只有读*/
static int get_rt_status(void *data, u64 * val)
{
int i = (int)data;
int ret;
/* global irq number is passed in via data */
ret = pm_chg_get_rt_status(the_chip, i);
printk("%s i=%d ret=%d \n",__func__,i,ret);
*val = ret;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
static void create_debugfs_entries(struct pm8921_chg_chip *chip)
{
int i;
chip->dent = debugfs_create_dir("pm8921_chg", NULL);
if (IS_ERR(chip->dent)) {
pr_err("pmic charger couldnt create debugfs dir\n");
return;
}
debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
(void *)CHG_CNTRL, ®_fops);
debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
(void *)CHG_CNTRL_2, ®_fops);
debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
(void *)CHG_CNTRL_3, ®_fops);
debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
(void *)PBL_ACCESS1, ®_fops);
debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
(void *)PBL_ACCESS2, ®_fops);
debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
(void *)SYS_CONFIG_1, ®_fops);
debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
(void *)SYS_CONFIG_2, ®_fops);
debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
(void *)CHG_VDD_MAX, ®_fops);
debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
(void *)CHG_VDD_SAFE, ®_fops);
debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
(void *)CHG_VBAT_DET, ®_fops);
debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
(void *)CHG_IBAT_MAX, ®_fops);
debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
(void *)CHG_IBAT_SAFE, ®_fops);
debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
(void *)CHG_VIN_MIN, ®_fops);
debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
(void *)CHG_VTRICKLE, ®_fops);
debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
(void *)CHG_ITRICKLE, ®_fops);
debugfs_create_file("CHG_ITERM", 0644, chip->dent,
(void *)CHG_ITERM, ®_fops);
debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
(void *)CHG_TCHG_MAX, ®_fops);
debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
(void *)CHG_TWDOG, ®_fops);
debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
(void *)CHG_TEMP_THRESH, ®_fops);
debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
(void *)CHG_COMP_OVR, ®_fops);
debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
(void *)CHG_BUCK_CTRL_TEST1, ®_fops);
debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
(void *)CHG_BUCK_CTRL_TEST2, ®_fops);
debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
(void *)CHG_BUCK_CTRL_TEST3, ®_fops);
debugfs_create_file("CHG_TEST", 0644, chip->dent,
(void *)CHG_TEST, ®_fops);
debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
&fsm_fops);
debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
®_loop_fops);
debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
(void *)BAT_WARM_ZONE, &warm_cool_fops);
debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
(void *)BAT_COOL_ZONE, &warm_cool_fops);
for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
debugfs_create_file(chg_irq_data[i].name, 0444,
chip->dent,
(void *)chg_irq_data[i].irq_id,
&rt_fops);
}
}
使用debugfs调试:
root@android:/ # mkdir /data/debugfs
root@android:/ # mount -t debugfs debugfs /data/debugfs
root@android:/ # cd /data/debugfs/
root@android:/data/debugfs # cd pm8921
pm8921-bms/ pm8921-dbg/ pm8921_chg/
root@android:/data/debugfs # cd pm8921_chg/
root@android:/data/debugfs/pm8921_chg #
root@android:/data/debugfs/pm8921_chg #
root@android:/data/debugfs/pm8921_chg # ls -l
-r--r--r-- root root 0 2013-04-18 15:25 ATCDONE_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 ATCFAIL_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATFET_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATTTEMP_COLD_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATTTEMP_HOT_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATT_INSERTED_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 BATT_REMOVED_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 BAT_COOL_ZONE
-r--r--r-- root root 0 2013-04-18 15:25 BAT_TEMP_OK_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 BAT_WARM_ZONE
-r--r--r-- root root 0 2013-04-18 15:25 CHGDONE_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGFAIL_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGHOT_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGSTATE_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 CHGWDOG_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_BUCK_CTRL_TEST1
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_BUCK_CTRL_TEST2
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_BUCK_CTRL_TEST3
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_CNTRL
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_CNTRL_2
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_CNTRL_3
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_COMP_OVR
-r--r--r-- root root 0 2013-04-18 15:25 CHG_GONE_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_IBAT_MAX
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_IBAT_SAFE
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_ITERM
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_ITRICKLE
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TCHG_MAX
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TEMP_THRESH
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TEST
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_TWDOG
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VBAT_DET
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VDD_MAX
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VDD_SAFE
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VIN_MIN
-rw-r--r-- root root 0 2013-04-18 15:25 CHG_VTRICKLE
-r--r--r-- root root 0 2013-04-18 15:25 COARSE_DET_LOW_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 DCIN_OV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 DCIN_UV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 DCIN_VALID_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 FASTCHG_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 FSM_STATE
-r--r--r-- root root 0 2013-04-18 15:25 LOOP_CHANGE_IRQ
-rw-r--r-- root root 0 2013-04-18 15:25 PBL_ACCESS1
-rw-r--r-- root root 0 2013-04-18 15:25 PBL_ACCESS2
-rw-r--r-- root root 0 2013-04-18 15:25 REGULATION_LOOP_CONTROL
-rw-r--r-- root root 0 2013-04-18 15:25 SYS_CONFIG_1
-rw-r--r-- root root 0 2013-04-18 15:25 SYS_CONFIG_2
-r--r--r-- root root 0 2013-04-18 15:25 TRKLCHG_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 USBIN_OV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 USBIN_UV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 USBIN_VALID_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VBATDET_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VBATDET_LOW_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VBAT_OV_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VCP_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VDD_LOOP_IRQ
-r--r--r-- root root 0 2013-04-18 15:25 VREG_OV_IRQ
查看中断状态:
root@android:/data/debugfs/pm8921_chg # cat FASTCHG_IRQ //查看是否在快速充电阶段 调用get_reg();
1
dmesg:
<4>[ 95.057652] get_rt_status i=14 ret=1
查看寄存器的值:
root@android:/data/debugfs/pm8921_chg # cat CHG_ITERM //查看充电截至电流寄存器Value 调用set_reg();
0x07
dmesg:
<4>[ 275.319975] get_reg data = 0x215, val= 0x07
写入某个寄存器:
root@android:/data/debugfs/pm8921_chg # echo 0x06 > CHG_ITERM //将0x06写入CHG_ITERM 调用get_rt_status();
0x07
dmesg:
<4>[ 476.374118] set_reg data = 0x215, val= 0x06