问题引入
[ 7898.374645] ------------[ cut here ]------------
[ 7898.374837] WARNING: CPU: 2 PID: 1517 at drivers/clk/clk.c:730 clk_core_enable+0x94/0x)
[ 7898.375021] Modules linked in: timer(O+) [last unloaded: timer]
[ 7898.375285] CPU: 2 PID: 1517 Comm: insmod Tainted: G W O 4.4.0 #3
[ 7898.380949] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
[ 7898.387084] [<c00160ec>] (unwind_backtrace) from [<c0012e08>] (show_stack+0x10/0x14)
[ 7898.394786] [<c0012e08>] (show_stack) from [<c01f6bd8>] (dump_stack+0x80/0xc0)
[ 7898.401947] [<c01f6bd8>] (dump_stack) from [<c00235c8>] (warn_slowpath_common+0x80/0xb)
[ 7898.410016] [<c00235c8>] (warn_slowpath_common) from [<c0023694>] (warn_slowpath_null+)
[ 7898.418781] [<c0023694>] (warn_slowpath_null) from [<c04092c4>] (clk_core_enable+0x94/)
[ 7898.427116] [<c04092c4>] (clk_core_enable) from [<c04095e0>] (clk_enable+0x1c/0x38)
[ 7898.434760] [<c04095e0>] (clk_enable) from [<bf02c07c>] (timer3_probe+0x5c/0x15c [time)
[ 7898.442921] [<bf02c07c>] (timer3_probe [timer]) from [<c02c58c4>] (platform_drv_probe+)
[ 7898.451680] [<c02c58c4>] (platform_drv_probe) from [<c02c3f54>] (driver_probe_device+0)
[ 7898.460532] [<c02c3f54>] (driver_probe_device) from [<c02c40a0>] (__driver_attach+0x8c)
[ 7898.468959] [<c02c40a0>] (__driver_attach) from [<c02c247c>] (bus_for_each_dev+0x60/0x)
[ 7898.477115] [<c02c247c>] (bus_for_each_dev) from [<c02c366c>] (bus_add_driver+0x1a0/0x)
[ 7898.485358] [<c02c366c>] (bus_add_driver) from [<c02c4874>] (driver_register+0x78/0xf8)
[ 7898.493346] [<c02c4874>] (driver_register) from [<bf02c18c>] (timer_init+0x10/0x3c [ti)
[ 7898.501681] [<bf02c18c>] (timer_init [timer]) from [<c0009774>] (do_one_initcall+0x90/)
[ 7898.510100] [<c0009774>] (do_one_initcall) from [<c0098050>] (do_init_module+0x60/0x34)
[ 7898.518172] [<c0098050>] (do_init_module) from [<c008bef0>] (load_module+0x1b3c/0x1d68)
[ 7898.526153] [<c008bef0>] (load_module) from [<c008c1f0>] (SyS_init_module+0xd4/0x144)
[ 7898.533967] [<c008c1f0>] (SyS_init_module) from [<c000f600>] (ret_fast_syscall+0x0/0x3)
[ 7898.542031] ---[ end trace 655de26992d22f14 ]---
[ 7898.546682] ret:-108
最近写驱动时ret=clk_enable(clk)报错,追溯原因:
http://blog.csdn.net/qq_33160790/article/details/79354855
108对应着ESHUTDOWN,所以出错是因为
后来查阅资料,在使用clk_enable之前调用clk_prepare,或者使用clk_prepare_enable API即可。
clk_prepare()和clk_prepare_enable
/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
static inline int clk_prepare_enable(struct clk *clk)
{
int ret;
ret = clk_prepare(clk);
if (ret)
return ret;
ret = clk_enable(clk);
if (ret)
clk_unprepare(clk);
return ret;
}
很明显clk_prepare_enable就是把clk_prepare和clk_enable封装在一起。
早期的驱动中,并没有clk_prepare这个API,带prepare关键字的都是新加入的。
值得一提的是,名称中含有prepare、unprepare字符串的API是内核后来才加入的,过去
只有clk_enable和clk_disable。只有clk_enable和clk_disable带来的问题是,
有时候,某些硬件的enable/disable clk可能引起睡眠使得enable/disable不能在原子
上下文进行。
加上prepare后,把过去的clk_enable分解成不可在原子上下文调用的
clk_prepare(该函数可能睡眠)和可以在原子上下文调用的clk_enable。
而clk_prepare_enable则同时完成
prepare和enable的工作,当然也只能在可能睡眠的上下文调用该API。
怎么理解上面这段话呢,我觉得关键点在于clk_prepare为什么可能睡眠。