1、研究前提
在使用xilinx的dma驱动时,其时钟是使用的外部时钟,驱动加载的优先级都是6,导致时钟还未初始化,其xilinx的dma驱动就启用了。出现以下问题:
xilinx-vdma 43000000.dma: reset timeout, cr 10006, sr 1
xilinx-vdma 43000000.dma: Reset channel failed
xilinx-vdma 43000000.dma: Xilinx AXI VDMA Engine Driver Probed!!
在xilinx的论坛也有该问题链接: link https://support.xilinx.com/s/question/0D52E00006hpqcWSAQ/xilinxvdma-43000000dma-reset-timeout%E9%97%AE%E9%A2%98?language=en_US
于是考虑时钟问题,开始想着把驱动编译成模块,待内核加载完成后,手动加载驱动,确认是否为时钟问题,但是编译失败,于是驱动优先级的方法解决该问题。
2、驱动优先级
从kernel/include/linux/init.h下可以查到以下优先级
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
再上面的不同优先级中,数字越小,优先级越高。同一优先级的驱动,加载顺序是链接过程决定的,结果是不确定的,我们无法手动设置谁先谁后。只能通过设置驱动的优先级来决定其先后。
xilinx_dma.c采用的是平台总线,其驱动入口函数为
module_platform_driver(xilinx_vdma_driver);
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
可以看出其最后是调用的__define_initcall(fn, 6) 函数,其优先级为6
时钟芯片对应的驱动入口函数采用的是
module_spi_driver(__spi_driver);
#define module_spi_driver(__spi_driver) \
module_driver(__spi_driver, spi_register_driver, \
spi_unregister_driver)
可以看出,其最后调用的也是__define_initcall(fn, 6) 函数,其优先级为6
3、xilinx_dma.c驱动优先级修改
在#include 。。。下添加以下内容
#define module_init_test(x) device_initcall_sync(x);
#define module_exit_test(x) __exitcall(x);
/**
* module_driver_test() - Helper macro for drivers that don't do anything
* special in module init/exit. This eliminates a lot of boilerplate.
* Each module may only use this macro once, and calling it replaces
* module_init_test() and module_exit_test().
*
* @__driver: driver name
* @__register: register function for this driver type
* @__unregister: unregister function for this driver type
* @...: Additional arguments to be passed to __register and __unregister.
*
* Use this macro to construct bus specific macros for registering
* drivers, and do not use it on its own.
*/
#define module_driver_test(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init_test(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit_test(__driver##_exit);
#define module_platform_driver_test(__platform_driver) \
module_driver_test(__platform_driver, platform_driver_register, \
platform_driver_unregister)
修改
module_platform_driver(xilinx_vdma_driver);
为以下内容
module_platform_driver_test(xilinx_vdma_driver);
即可