如何找到由suspend_ops->调用的代码(输入(状态);

时间:2013-05-11 02:30:03

标签: debugging linux-kernel kernel power-management

我试图理解低级别的Linux内核电源管理,并且因为我的C不是很强大而终于卡住了。我可以按照suspend_ops->enter(state);方法(suspend_enter(suspend_state_t state, bool *wakeup))中的代码kernel/power/suspend.c跟踪代码,但是我无法再进一步遵循代码了。

我的理解是suspend_ops->enter(state)在一些使用suspend_ops注册的驱动程序中调用“enter”方法但我不确定如何找到它们或正在调用的方法。有人可以告诉我如何关注suspend_ops->enter(state)电话吗?

1 个答案:

答案 0 :(得分:1)

kernel/power/suspend.c的顶部附近注意以下行:

static struct platform_suspend_ops *suspend_ops;

这意味着suspend_ops是一个专用于此文件的全局变量。这意味着,为了能够使用,必须在suspend.c中的任何地方进行分配。所以让我们来看看作业。通过suspend.c搜索suspend_ops,我们在子例程suspend_set_ops中只能看到一个作业。在suspend_set_ops中搜索suspend.c,我们发现没有对其进行调用。所以,电话必须在其他地方!

我们在整个内核中搜索suspend_set_ops

yba@tavas:~/linux-2.6/linux-2.6.31$ find . -type f | xargs grep suspend_set_ops
./kernel/power/suspend.c: * suspend_set_ops - Set the global suspend method table.
./kernel/power/suspend.c:void suspend_set_ops(struct platform_suspend_ops *ops)
./arch/mips/alchemy/devboards/pm.c: suspend_set_ops(&db1x_pm_ops);
./arch/arm/mach-sa1100/pm.c:    suspend_set_ops(&sa11x0_pm_ops);
./arch/arm/plat-s3c/pm.c:   suspend_set_ops(&s3c_pm_ops);
./arch/arm/mach-omap2/pm24xx.c: suspend_set_ops(&omap_pm_ops);
./arch/arm/mach-omap2/pm34xx.c: suspend_set_ops(&omap_pm_ops);
./arch/arm/mach-pxa/pm.c:   suspend_set_ops(&pxa_pm_ops);
./arch/arm/mach-pxa/sharpsl_pm.c:   suspend_set_ops(&sharpsl_pm_ops);
./arch/arm/mach-pxa/sharpsl_pm.c:   suspend_set_ops(NULL);
./arch/arm/mach-at91/pm.c:  suspend_set_ops(&at91_pm_ops);
./arch/arm/mach-omap1/pm.c: suspend_set_ops(&omap_pm_ops);
./arch/arm/mach-pnx4008/pm.c:   suspend_set_ops(&pnx4008_pm_ops);
./arch/sh/kernel/cpu/shmobile/pm.c: suspend_set_ops(&sh_pm_ops);
./arch/sh/boards/mach-hp6xx/pm.c:   suspend_set_ops(&hp6x0_pm_ops);
./arch/powerpc/platforms/83xx/suspend.c:    suspend_set_ops(&mpc83xx_suspend_ops);
./arch/powerpc/platforms/52xx/mpc52xx_pm.c: suspend_set_ops(&mpc52xx_pm_ops);
./arch/powerpc/platforms/52xx/lite5200_pm.c:    suspend_set_ops(&lite5200_pm_ops);
./arch/avr32/mach-at32ap/pm.c:  suspend_set_ops(&avr32_pm_ops);
./arch/blackfin/mach-common/pm.c:   suspend_set_ops(&bfin_pm_ops);
./include/linux/suspend.h: * suspend_set_ops - set platform dependent suspend operations
./include/linux/suspend.h:extern void suspend_set_ops(struct platform_suspend_ops *ops);
./include/linux/suspend.h:static inline void suspend_set_ops(struct platform_suspend_ops *ops) {}
./drivers/macintosh/via-pmu.c:  suspend_set_ops(&pmu_pm_ops);
./drivers/acpi/sleep.c: suspend_set_ops(old_suspend_ordering ?

我们看到几乎所有对suspend_set_ops的调用都在特定于体系结构的目录中,除了输出末尾的两个驱动程序:macintosh/via-pmu.cacpi/sleep.c 。因此,下一步是查看某个平台的特定于体系结构的代码。我们将以./arch/powerpc/platforms/83xx/suspend.c为例。你应该自己为你正在使用的平台做这件事。如果它是x86,那么您可能需要查看./drivers/acpi/sleep.c

在该文件中搜索suspend_set_ops,我们看到它在子例程pmc_probe中被调用一次,这是静态的。所以我们在同一个文件中查找pmc_probe的调用,直到找到一个非静态的调用。我们找到了`of_platform_driver类型结构的静态声明,名为`pmc_driver that assigns pmc_probe to element probe``。

由于pmc_driver结构是静态的,我们在静态函数pmc_init中查找同一文件中对它的引用,并且很好。我们会查找pmc_init的来电并找到一个,作为module_init来电的参数。

我们从内核树的顶部搜索module_init,稍微限制了我们的搜索:

find . -type f | xargs grep -w "module_init.*)[^;]" |more

我们得到的结果中,最有希望的是:

./include/linux/init.h:#define module_init(initfn)                  \

查看./include/linux/init.h,如果未定义MODULE,我们会看到module_init是对__initcall的调用,或者

#define module_init(initfn)                                     \
    static inline initcall_t __inittest(void)               \
    { return initfn; }                                      \
    int init_module(void) __attribute__((alias(#initfn)));

此时我们真的在另一个主题 - 如何注册驱动程序和模块。 HTH。