運用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);
}
}