设备驱动的异步加载 —— 示例分析

Posted 摩斯电码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设备驱动的异步加载 —— 示例分析相关的知识,希望对你有一定的参考价值。

作者

彭东林
 

平台

Linux-4.10.17
Qemu2.8 + vexpress-a9
 

概述

    在系统开机probe驱动的时候,有些设备驱动加载可能需要比较长的时间,尤其是像i2c这样的设备,总线带宽较低,如果在驱动的probe中读写大量的寄存器的话,会使系统的开机速度变长。针对这个问题,Linux内核提供的驱动异步的加载机制,当然在使用时也有一些限制,比如挂载同一条总线下的设备驱动加载只能串行等等,此外,如果设备的驱动之间存在依赖关系,那么就需要慎用。
    下面是Linux内核里引入驱动异步加载的几个patch:
 
        765230b5f084863183aa8adb3405ab3f32c0b16e
        f2411da746985e60d4d087f3a43e271c61785927
        d173a137c5bd95ee29d02705e5fa8890ef149718
 
引用提交记录记录中对设备驱动异步加载的解释:
    Some devices take a long time when initializing, and not all drivers are
    suited to initialize their devices when they are open. For example,
    input drivers need to interrogate their devices in order to publish
    devices capabilities before userspace will open them. When such drivers
    are compiled into kernel they may stall entire kernel initialization.
    
    This change allows drivers request for their probe functions to be
    called asynchronously during driver and device registration (manual
    binding is still synchronous). Because async_schedule is used to perform
    asynchronous calls module loading will still wait for the probing to
    complete.
    
    Note that the end goal is to make the probing asynchronous by default,
    so annotating drivers with PROBE_PREFER_ASYNCHRONOUS is a temporary
    measure that allows us to speed up boot process while we validating and
    fixing the rest of the drivers and preparing userspace.
下面用两个示例说明一下,一个是基于platform的,另一个是基于i2c的。
涉及到代码可以到下面的链接下载:https://github.com/pengdonglin137/async_drv_load_demo
 

正文

一、I2C从设备驱动的异步加载

        这里只关心调用驱动probe的情况,不太关心具体驱动的功能。在设备树里模拟出4个I2C控制器,在第1组I2C控制器下挂两个从设备,目的是观察同一个I2C总线下的从设备驱动的加载顺序,其他三个I2C控制器下面各挂一个从设备,目的是观察不同I2C总线下的从设备驱动的异步加载情况。为了方便,在驱动probe函数中加了不同的延迟。
        由于在下面的例子中,设备树的解析时间较早,也就是在注册驱动时,对应的device早已经存在了,所以主要分析注册驱动后,驱动找设备的情形。对于设备找驱动的情形以后分析。
  • 设备树

I2C控制器1,下面挂了两个设备:
    async_demo1_i2c: [email protected]20000 {
        compatible = "arm,versatile-i2c";
        reg = <0x20000 0x1000>;
        #address-cells = <1>;
        #size-cells = <0>;

        [email protected]39 {
            compatible = "async_demo1_i2c";
            reg = <0x39>;
            status = "okay";
        };

        [email protected] {
            compatible = "async_demo5_i2c";
            reg = <0x3a>;
            status = "okay";
        };
    };
其他三个I2C控制器,每个下面挂一个设备:
    async_demo2_i2c: [email protected]30000 {
        compatible = "arm,versatile-i2c";
        reg = <0x30000 0x1000>;

        #address-cells = <1>;
        #size-cells = <0>;

        [email protected]39 {
            compatible = "async_demo2_i2c";
            reg = <0x39>;
            status = "okay";
        };

    };

    async_demo3_i2c: [email protected]40000 {
        compatible = "arm,versatile-i2c";
        reg = <0x40000 0x1000>;

        #address-cells = <1>;
        #size-cells = <0>;

        [email protected]39 {
            compatible = "async_demo3_i2c";
            reg = <0x39>;
            status = "okay";
        };

    };

    async_demo4_i2c: [email protected]50000 {
        compatible = "arm,versatile-i2c";
        reg = <0x50000 0x1000>;

        #address-cells = <1>;
        #size-cells = <0>;

        [email protected]39 {
            compatible = "async_demo4_i2c";
            reg = <0x39>;
            status = "okay";
        };

    };

上面是三个I2C控制器,具体每个I2C控制的reg属性是随意指定的,只要跟其他设备不冲突就行,因为这里只关心驱动的probe。

 
  • 设备驱动

设备1的probe中延迟4s,在驱动中设置probe_type为PROBE_PREFER_ASYNCHRONOUS:
 1 static int async_demo1_probe(struct i2c_client *i2c,
 2              const struct i2c_device_id *id)
 3 {
 4     printk("%s enter\n", __func__);
 5     msleep(4000);
 6     printk("%s exit\n", __func__);
 7     return 0;
 8 }
 9 
10 static struct i2c_driver async_demo1_i2c_driver = {
11     .probe            = async_demo1_probe,
12     .remove         = async_demo1_remove,
13     .id_table       = async_demo1_i2c_id,
14     .driver         = {
15         .name           = "async_demo1_i2c",
16         .of_match_table = async_demo1_i2c_dt_ids,
17 #ifdef USE_ASYNC
18         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
19 #else
20         .probe_type = PROBE_FORCE_SYNCHRONOUS,
21 #endif
22     },
23 };
其他几个设备2、3、4、5的驱动中将probe_type也设置为PROBE_PREFER_ASYNCHRONOUS,在probe函数中分别延迟3s、2s、1s和100ms。
为了对比,上面设置了宏USE_ASYNC,如果没有定义,那么就将probe_type设置为PROBE_FORCE_SYNCHRONOUS,表示同步加载。否则设置为PROBE_PREFER_ASYNCHRONOUS
 
  • 验证

先看看同步加载驱动的耗时:
 1 [[email protected] mnt]# insmod async_demo_i2c.ko 
 2 [ 5099.103927] [ 1|  871|         insmod] async_demo_i2c_init enter.
 3 [ 5099.104108] [ 1|  871|         insmod] before async_demo1_i2c
 4 [ 5099.104312] [ 1|  871|         insmod] __driver_attach enter, dev: 2-0039
 5 [ 5099.104466] [ 1|  871|         insmod] bus: i2c: driver_probe_device: matched device 2-0039 with driver async_demo1_i2c
 6 [ 5099.104798] [ 1|  871|         insmod] async_demo1_probe enter
 7 [ 5102.861699] [ 1|  871|         insmod] async_demo1_probe exit
 8 [ 5102.862238] [ 1|  871|         insmod] bus_add_driver exit.
 9 [ 5102.862465] [ 1|  871|         insmod] before async_demo2_i2c
10 [ 5102.862663] [ 1|  871|         insmod] __driver_attach enter, dev: 3-0039
11 [ 5102.862794] [ 1|  871|         insmod] bus: i2c: driver_probe_device: matched device 3-0039 with driver async_demo2_i2c
12 [ 5102.863064] [ 1|  871|         insmod] async_demo2_probe enter
13 [ 5105.706465] [ 1|  871|         insmod] async_demo2_probe exit
14 [ 5105.707067] [ 1|  871|         insmod] bus_add_driver exit.
15 [ 5105.707317] [ 1|  871|         insmod] before async_demo3_i2c
16 [ 5105.707516] [ 1|  871|         insmod] __driver_attach enter, dev: 4-0039
17 [ 5105.707652] [ 1|  871|         insmod] bus: i2c: driver_probe_device: matched device 4-0039 with driver async_demo3_i2c
18 [ 5105.707939] [ 1|  871|         insmod] async_demo3_probe enter
19 [ 5107.652718] [ 1|  871|         insmod] async_demo3_probe exit
20 [ 5107.653142] [ 1|  871|         insmod] bus_add_driver exit.
21 [ 5107.653398] [ 1|  871|         insmod] before async_demo4_i2c
22 [ 5107.653653] [ 1|  871|         insmod] __driver_attach enter, dev: 5-0039
23 [ 5107.653852] [ 1|  871|         insmod] bus: i2c: driver_probe_device: matched device 5-0039 with driver async_demo4_i2c
24 [ 5107.654243] [ 1|  871|         insmod] async_demo4_probe enter
25 [ 5108.625550] [ 1|  871|         insmod] async_demo4_probe exit
26 [ 5108.626019] [ 1|  871|         insmod] bus_add_driver exit.
27 [ 5108.626219] [ 1|  871|         insmod] before async_demo5_i2c
28 [ 5108.626460] [ 1|  871|         insmod] __driver_attach enter, dev: 2-003a
29 [ 5108.626604] [ 1|  871|         insmod] bus: i2c: driver_probe_device: matched device 2-003a with driver async_demo5_i2c
30 [ 5108.626896] [ 1|  871|         insmod] async_demo5_probe enter
31 [ 5108.738170] [ 1|  871|         insmod] async_demo5_probe exit
32 [ 5108.738635] [ 1|  871|         insmod] bus_add_driver exit.
可以看到,从开始加载到最后加载完毕,耗时9.6s左右,是每个驱动probe耗时的累加。上面的驱动的probe被调用的顺序跟驱动的注册顺序相同,先注册的先被调用,串行进行,而且自始至总都在insmod这一个进程上下文中。
 
再看看异步加载的情况:
 1 [[email protected] mnt]# insmod async_demo_i2c.ko 
 2 [ 5487.522979] [ 2|  886|         insmod] async_demo_i2c_init enter.
 3 [ 5487.523168] [ 2|  886|         insmod] before async_demo1_i2c
 4 [ 5487.523379] [ 2|  886|         insmod] bus: i2c: probing driver async_demo1_i2c asynchronously
 5 [ 5487.523817] [ 2|  886|         insmod] bus_add_driver exit.
 6 [ 5487.524034] [ 2|  886|         insmod] before async_demo2_i2c
 7 [ 5487.524227] [ 2|  886|         insmod] bus: i2c: probing driver async_demo2_i2c asynchronously
 8 [ 5487.524545] [ 2|  886|         insmod] bus_add_driver exit.
 9 [ 5487.524759] [ 2|  886|         insmod] before async_demo3_i2c
10 [ 5487.524949] [ 2|  886|         insmod] bus: i2c: probing driver async_demo3_i2c asynchronously
11 [ 5487.525248] [ 2|  886|         insmod] bus_add_driver exit.
12 [ 5487.525448] [ 2|  886|         insmod] before async_demo4_i2c
13 [ 5487.525642] [ 2|  886|         insmod] bus: i2c: probing driver async_demo4_i2c asynchronously
14 [ 5487.525951] [ 2|  886|         insmod] bus_add_driver exit.
15 [ 5487.526177] [ 2|  886|         insmod] before async_demo5_i2c
16 [ 5487.526421] [ 2|  886|         insmod] bus: i2c: probing driver async_demo5_i2c asynchronously
17 [ 5487.526728] [ 2|  886|         insmod] bus_add_driver exit.
18 [ 5487.527397] [ 0|  858|   kworker/u8:3] driver_attach_async enter.
19 [ 5487.527627] [ 0|  858|   kworker/u8:3] __driver_attach enter, dev: 2-0039
20 [ 5487.527822] [ 0|  858|   kworker/u8:3] bus: i2c: driver_probe_device: matched device 2-0039 with driver async_demo1_i2c
21 [ 5487.528246] [ 0|  858|   kworker/u8:3] async_demo1_probe enter
22 [ 5487.531002] [ 0|  735|   kworker/u8:4] driver_attach_async enter.
23 [ 5487.531236] [ 0|  735|   kworker/u8:4] __driver_attach enter, dev: 3-0039
24 [ 5487.531431] [ 0|  735|   kworker/u8:4] bus: i2c: driver_probe_device: matched device 3-0039 with driver async_demo2_i2c
25 [ 5487.532741] [ 3|  888|   kworker/u8:0] driver_attach_async enter.
26 [ 5487.532968] [ 3|  888|   kworker/u8:0] __driver_attach enter, dev: 4-0039
27 [ 5487.533162] [ 3|  888|   kworker/u8:0] bus: i2c: driver_probe_device: matched device 4-0039 with driver async_demo3_i2c
28 [ 5487.533647] [ 3|  888|   kworker/u8:0] async_demo3_probe enter
29 [ 5487.534076] [ 3|  890|   kworker/u8:1] driver_attach_async enter.
30 [ 5487.534291] [ 3|  890|   kworker/u8:1] __driver_attach enter, dev: 5-0039
31 [ 5487.534505] [ 3|  890|   kworker/u8:1] bus: i2c: driver_probe_device: matched device 5-0039 with driver async_demo4_i2c
32 [ 5487.534865] [ 3|  890|   kworker/u8:1] async_demo4_probe enter
33 [ 5487.535282] [ 3|  892|   kworker/u8:2] driver_attach_async enter.
34 [ 5487.535488] [ 3|  892|   kworker/u8:2] __driver_attach enter, dev: 2-003a
35 [ 5487.539944] [ 0|  735|   kworker/u8:4] async_demo2_probe enter
36 [ 5488.514837] [ 3|  890|   kworker/u8:1] async_demo4_probe exit
37 [ 5488.515209] [ 3|  890|   kworker/u8:1] bus: i2c: driver async_demo4_i2c async attach completed: 0
38 [ 5489.488056] [ 3|  888|   kworker/u8:0] async_demo3_probe exit
39 [ 5489.488394] [ 3|  888|   kworker/u8:0] bus: i2c: driver async_demo3_i2c async attach completed: 0
40 [ 5490.384618] [ 0|  735|   kworker/u8:4] async_demo2_probe exit
41 [ 5490.384894] [ 0|  735|   kworker/u8:4] bus: i2c: driver async_demo2_i2c async attach completed: 0
42 [ 5491.282840] [ 0|  858|   kworker/u8:3] async_demo1_probe exit
43 [ 5491.283172] [ 0|  858|   kworker/u8:3] bus: i2c: driver async_demo1_i2c async attach completed: 0
44 [ 5491.283724] [ 3|  892|   kworker/u8:2] bus: i2c: driver_probe_device: matched device 2-003a with driver async_demo5_i2c
45 [ 5491.284663] [ 3|  892|   kworker/u8:2] async_demo5_probe enter
46 [ 5491.396770] [ 3|  892|   kworker/u8:2] async_demo5_probe exit
47 [ 5491.397074] [ 3|  892|   kworker/u8:2] bus: i2c: driver async_demo5_i2c async attach completed: 0
可以看到,驱动加载耗时3.9s左右,其实也就是耗时probe耗时最长的那个驱动的时间,看到异步加载的强大了吧。此外,可以看到由于demo5和demo1挂载在一个I2C控制器下,即便驱动里支持异步,但是从结果来看还是是串行的,可以看到上面第二个中括号中数字的含义 [处理器编号 | 进程号 | 进程名称]。
  在异步加载情形下,在驱动注册时,先在insmod进程的上下文,然后发现可以支持异步,紧接着就会启动一个后台内核线程来负责接下来的加载任务,上面先后出现了5个内核线程。上面的kworker/u8:n都是内核线程,属于内核工作队列的知识,关于内核工作队列可以阅读笨叔叔的《奔跑吧Linux内核》的5.3节,顺便学习一个笨叔叔在书中传授的关于Linux内核里CMWQ的一个知识点:
 
        CMWQ机制会动态地调整一个线程池中工作线程的执行情况,不会因为某个work回调函数执行了阻塞操作而影响整个线程池中其他work的执行。
 
上面的例子也充分说明了这一点。
 

二、platform设备驱动的异步加载

对于platform总线上的设备来说有些特殊,即便驱动里将probe_type设置为了PROBE_PREFER_ASYNCHRONOUS,但是如果是先注册device,再注册driver的话还是串行进行,原因是driver在attach到device时,会先device_lock(dev->parent),然后再去probe,对于platform总线上的device,其dev->parent都指向platform_bus,所以虽然从log上看,确实是由内核线程负责加载驱动的,但是由于锁的原因,表现出来的还是串行,这一点我觉得应该可以优化。如果是先注册driver,后注册device的话,是可以异步的,原因是没有调用device_lock(dev->parent)。
 

1、device找driver的情形

跟前面类似,有四个platform_driver,第1个platform_driver的probe里睡4s,第2、3和4个分别睡3s、2s和1s。在驱动模块init时,先注册platform_driver,再注册platform_device。下面是部分示例驱动:
 1 static struct platform_driver async_demo4_v2_driver = {
 2     .probe        = async_demo4_v2_probe,
 3     .remove        = async_demo4_v2_remove,
 4     .driver        = {
 5         .name    = "async_demo4_v2",
 6         .of_match_table = of_match_ptr(async_demo4_v2_dt_ids),
 7 #ifdef USE_ASYNC
 8         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
 9 #else
10         .probe_type = PROBE_FORCE_SYNCHRONOUS,
11 #endif
12     },
13 };
14 
15 static struct platform_device *pdev[4];
16 
17 static __init int async_demo_init(void)
18 {
19     printk("%s enter.\n", __func__);
20 
21     printk("Register Platform Driver\n");
22     platform_driver_register(&async_demo1_v2_driver);
23     platform_driver_register(&async_demo2_v2_driver);
24     platform_driver_register(&async_demo3_v2_driver);
25     platform_driver_register(&async_demo4_v2_driver);
26 
27     printk("\n\n Register Platform Device\n");
28     pdev[0] = platform_device_register_simple("async_demo1_v2", 0, NULL, 0);
29     pdev[1] = platform_device_register_simple("async_demo2_v2", 0, NULL, 0);
30     pdev[2] = platform_device_register_simple("async_demo3_v2", 0, NULL, 0);
31     pdev[3] = platform_device_register_simple("async_demo4_v2", 0, NULL, 0);
32 
33     return 0;
34 }
 
先看同步加载的耗时:
 1 [[email protected] mnt]# insmod async_demo_v2.ko 
 2 [   49.125194] [ 2|  830|         insmod] async_demo_init enter.
 3 [   49.125382] [ 2|  830|         insmod] Register Platform Driver
 4 [   49.125834] [ 2|  830|         insmod] bus_add_driver exit.
 5 [   49.126256] [ 2|  830|         insmod] bus_add_driver exit.
 6 [   49.126665] [ 2|  830|         insmod] bus_add_driver exit.
 7 [   49.127065] [ 2|  830|         insmod] bus_add_driver exit.
 8 [   49.127218] [ 2|  830|         insmod] 
 9 [   49.127218] [ 2|  830|         insmod] 
10 [   49.127218] [ 2|  830|         insmod]  Register Platform Device
11 [   49.127760] [ 2|  830|         insmod] bus: platform: driver_probe_device: matched device async_demo1_v2.0 with driver async_demo1_v2
12 [   49.128085] [ 2|  830|         insmod] async_demo1_v2_probe: parent platform
13 [   49.128232] [ 2|  830|         insmod] async_demo1_v2_probe enter.
14 [   52.900810] [ 2|  830|         insmod] async_demo1_v2_probe exit.
15 [   52.901450] [ 2|  830|         insmod] bus: platform: driver_probe_device: matched device async_demo2_v2.0 with driver async_demo2_v2
16 [   52.901819] [ 2|  830|         insmod] async_demo2_v2_probe: parent platform
17 [   52.902015] [ 2|  830|         insmod] async_demo2_v2_probe enter.
18 [   55.750675] [ 2|  830|         insmod] async_demo2_v2_probe exit.
19 [   55.751344] [ 2|  830|         insmod] bus: platform: driver_probe_device: matched device async_demo3_v2.0 with driver async_demo3_v2
20 [   55.751631] [ 2|  830|         insmod] async_demo3_v2_probe enter.
21 [   57.700598] [ 2|  830|         insmod] async_demo3_v2_probe exit.
22 [   57.701227] [ 2|  830|         insmod] bus: platform: driver_probe_device: matched device async_demo4_v2.0 with driver async_demo4_v2
23 [   57.701509] [ 2|  830|         insmod] async_demo4_v2_probe enter.
24 [   58.675576] [ 2|  830|         insmod] async_demo4_v2_probe exit.
耗时9.5s左右
 
看看异步的耗时:
 1 [[email protected] mnt]# insmod async_demo_v2.ko 
 2 [  360.852433] [ 1|  878|         insmod] async_demo_init enter.
 3 [  360.852618] [ 1|  878|         insmod] Register Platform Driver
 4 [  360.852808] [ 1|  878|         insmod] bus: platform: probing driver async_demo1_v2 asynchronously
 5 [  360.853108] [ 1|  878|         insmod] bus_add_driver exit.
 6 [  360.853327] [ 1|  878|         insmod] bus: platform: probing driver async_demo2_v2 asynchronously
 7 [  360.853608] [ 1|  878|         insmod] bus_add_driver exit.
 8 [  360.853831] [ 1|  878|         insmod] bus: platform: probing driver async_demo3_v2 asynchronously
 9 [  360.854090] [ 1|  878|         insmod] bus_add_driver exit.
10 [  360.854287] [ 1|  878|         insmod] bus: platform: probing driver async_demo4_v2 asynchronously
11 [  360.854568] [ 1|  878|         insmod] bus_add_driver exit.
12 [  360.854727] [ 1|  878|         insmod] 
13 [  360.854727] [ 1|  878|         insmod] 
14 [  360.854727] [ 1|  878|         insmod]  Register Platform Device
15 [  360.855376] [ 1|  878|         insmod] platform async_demo1_v2.0: scheduling asynchronous probe
16 [  360.855835] [ 1|  878|         insmod] platform async_demo2_v2.0: scheduling asynchronous probe
17 [  360.856274] [ 1|  878|         insmod] platform async_demo3_v2.0: scheduling asynchronous probe
18 [  360.857174] [ 0|  852|   kworker/u8:0] driver_attach_async enter.
19 [  360.857537] [ 0|  852|   kworker/u8:0] __driver_attach enter, dev: async_demo1_v2.0
20 [  360.857712] [ 0|  852|   kworker/u8:0] bus: platform: driver_probe_device: matched device async_demo1_v2.0 with driver async_demo1_v2
21 [  360.858984] [ 0|  852|   kworker/u8:0] async_demo1_v2_probe: parent platform
22 [  360.859267] [ 0|  852|   kworker/u8:0] async_demo1_v2_probe enter.
23 [  360.859571] [ 0|  854|   kworker/u8:1] driver_attach_async enter.
24 [  360.859876] [ 0|  854|   kworker/u8:1] __driver_attach enter, dev: async_demo2_v2.0
25 [  360.860130] [ 0|   50|   kworker/u8:2] driver_attach_async enter.
26 [  360.860412] [ 0|   50|   kworker/u8:2] __driver_attach enter, dev: async_demo3_v2.0
27 [  360.866237] [ 1|  878|         insmod] platform async_demo4_v2.0: scheduling asynchronous probe
28 [  360.866985] [ 2|  856|   kworker/u8:3] driver_attach_async enter.
29 [  360.867361] [ 2|  856|   kworker/u8:3] __driver_attach enter, dev: async_demo4_v2.0
30 [  360.868341] [ 3|  858|   kworker/u8:5] __device_attach_async_helper enter.
31 [  360.869812] [ 1|  292|   kworker/u8:4] __device_attach_async_helper enter.
32 [  360.870003] [ 1|  292|   kworker/u8:4] bus: platform: driver_probe_device: matched device async_demo2_v2.0 with driver async_demo2_v2
33 [  360.870296] [ 1|  292|   kworker/u8:4] async_demo2_v2_probe: parent platform
34 [  360.870423] [ 1|  292|   kworker/u8:4] async_demo2_v2_probe enter.
35 [  360.870882] [ 1|  863|   kworker/u8:7] __device_attach_async_helper enter.
36 [  360.871057] [ 1|  863|   kworker/u8:7] bus: platform: driver_probe_device: matched device async_demo3_v2.0 with driver async_demo3_v2
37 [  360.871365] [ 1|  863|   kworker/u8:7] async_demo3_v2_probe enter.
38 [  360.897155] [ 3|  861|   kworker/u8:6] __device_attach_async_helper enter.
39 [  360.897380] [ 3|  861|   kworker/u8:6] bus: platform: driver_probe_device: matched device async_demo4_v2.0 with driver async_demo4_v2
40 [  360.897688] [ 3|  861|   kworker/u8:6] async_demo4_v2_probe enter.
41 [  361.890088] [ 3|  861|   kworker/u8:6] async_demo4_v2_probe exit.
42 [  361.890527] [ 3|  861|   kworker/u8:6] async_demo4_v2 async_demo4_v2.0: async probe completed
43 [  362.789551] [ 1|  863|   kworker/u8:7] async_demo3_v2_probe exit.
44 [  362.789885] [ 1|  863|   kworker/u8:7] async_demo3_v2 async_demo3_v2.0: async probe completed
45 [  363.764507] [ 1|  292|   kworker/u8:4] async_demo2_v2_probe exit.
46 [  363.764866] [ 1|  292|   kworker/u8:4] async_demo2_v2 async_demo2_v2.0: async probe completed
47 [  364.662938] [ 0|  852|   kworker/u8:0] async_demo1_v2_probe exit.
48 [  364.663276] [ 0|  852|   kworker/u8:0] bus: platform: driver async_demo1_v2 async attach completed: 0
49 [  364.663581] [ 0|  854|   kworker/u8:1] bus: platform: driver async_demo2_v2 async attach completed: 0
50 [  364.663845] [ 0|   50|   kworker/u8:2] bus: platform: driver async_demo3_v2 async attach completed: 0
51 [  364.664372] [ 3|  858|   kworker/u8:5] async_demo1_v2 async_demo1_v2.0: async probe completed
52 [  364.664692] [ 2|  856|   kworker/u8:3] bus: platform: driver async_demo4_v2 async attach completed: 0
耗时3.8s左右。
 

2、driver找device的情形 

对于这种情况,只能修改一些驱动,修改driver/base/dd.c:
 1 @@ -749,13 +752,17 @@ static int __driver_attach(struct device *dev, void *data)
 2          return ret;
 3      } /* ret > 0 means positive match */
 4  
 5 -    if (dev->parent)    /* Needed for USB */
 6 +    printk("%s enter, dev: %s\n", __func__, dev_name(dev));
 7 +
 8 +    if (dev->parent && (dev->parent != &platform_bus))    /* Needed for USB */
 9          device_lock(dev->parent);
10 +
11      device_lock(dev);
12      if (!dev->driver)
13          driver_probe_device(drv, dev);
14      device_unlock(dev);
15 -    if (dev->parent)
16 +
17 +    if (dev->parent && (dev->parent != &platform_bus))    /* Needed for USB */
18          device_unlock(dev->parent);
19  
20      return 0;
也就是,当发现parent是platform_bus时,不调用device_lock。
 
下面看一下同步的耗时:
 1 [[email protected] mnt]# insmod async_demo.ko 
 2 [   21.384197] [ 1|  809|         insmod] async_demo: loading out-of-tree module taints kernel.
 3 [   21.389316] [ 1|  809|         insmod] async_demo_init enter.
 4 [   21.389462] [ 1|  809|         insmod] before async_demo1
 5 [   21.389829] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo1
 6 [   21.389978] [ 1|  809|         insmod] bus: platform: driver_probe_device: matched device async_demo1 with driver async_demo1
 7 [   21.390302] [ 1|  809|         insmod] async_demo1_probe: parent platform
 8 [   21.390479] [ 1|  809|         insmod] async_demo1_probe enter.
 9 [   25.161960] [ 1|  809|         insmod] async_demo1_probe exit.
10 [   25.162396] [ 1|  809|         insmod] bus_add_driver exit.
11 [   25.162583] [ 1|  809|         insmod] before async_demo2
12 [   25.162941] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo2
13 [   25.163091] [ 1|  809|         insmod] bus: platform: driver_probe_device: matched device async_demo2 with driver async_demo2
14 [   25.163374] [ 1|  809|         insmod] async_demo2_probe: parent platform
15 [   25.163517] [ 1|  809|         insmod] async_demo2_probe enter.
16 [   28.017117] [ 1|  809|         insmod] async_demo2_probe exit.
17 [   28.017622] [ 1|  809|         insmod] bus_add_driver exit.
18 [   28.017863] [ 1|  809|         insmod] before async_demo3
19 [   28.018244] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo3
20 [   28.018419] [ 1|  809|         insmod] bus: platform: driver_probe_device: matched device async_demo3 with driver async_demo3
21 [   28.018736] [ 1|  809|         insmod] async_demo3_probe enter.
22 [   29.970867] [ 1|  809|         insmod] async_demo3_probe exit.
23 [   29.971283] [ 1|  809|         insmod] bus_add_driver exit.
24 [   29.971509] [ 1|  809|         insmod] before async_demo4
25 [   29.971893] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo4
26 [   29.972048] [ 1|  809|         insmod] bus: platform: driver_probe_device: matched device async_demo4 with driver async_demo4
27 [   29.972341] [ 1|  809|         insmod] async_demo4_probe enter.
28 [   30.947713] [ 1|  809|         insmod] async_demo4_probe exit.
29 [   30.948153] [ 1|  809|         insmod] bus_add_driver exit.
耗时9.6s左右
 
下面是异步耗时:
 1 [  129.732599] [ 1|  822|         insmod] async_demo_init enter.
 2 [  129.732765] [ 1|  822|         insmod] before async_demo1
 3 [  129.732945] [ 1|  822|         insmod] bus: platform: probing driver async_demo1 asynchronously
 4 [  129.733311] [ 1|  822|         insmod] bus_add_driver exit.
 5 [  129.733461] [ 1|  822|         insmod] before async_demo2
 6 [  129.733611] [ 1|  822|         insmod] bus: platform: probing driver async_demo2 asynchronously
 7 [  129.733858] [ 1|  822|         insmod] bus_add_driver exit.
 8 [  129.734004] [ 1|  822|         insmod] before async_demo3
 9 [  129.734155] [ 1|  822|         insmod] bus: platform: probing driver async_demo3 asynchronously
10 [  129.734385] [ 1|  822|         insmod] bus_add_driver exit.
11 [  129.734524] [ 1|  822|         insmod] before async_demo4
12 [  129.734676] [ 1|  822|         insmod] bus: platform: probing driver async_demo4 asynchronously
13 [  129.734909] [ 1|  822|         insmod] bus_add_driver exit.
14 [  129.735450] [ 3|  403|   kworker/u8:4] driver_attach_async enter.
15 [  129.735772] [ 3|  403|   kworker/u8:4] __driver_attach enter, dev: async_demo1
16 [  129.736095] [ 3|  403|   kworker/u8:4] bus: platform: driver_probe_device: matched device async_demo1 with driver async_demo1
17 [  129.736430] [ 3|  403|   kworker/u8:4] async_demo1_probe: parent platform
18 [  129.736570] [ 3|  403|   kworker/u8:4] async_demo1_probe enter.
19 [  129.736818] [ 3|  262|   kworker/u8:3] driver_attach_async enter.
20 [  129.737088] [ 3|  262|   kworker/u8:3] __driver_attach enter, dev: async_demo2
21 [  129.737231] [ 3|  262|   kworker/u8:3] bus: platform: driver_probe_device: matched device async_demo2 with driver async_demo2
22 [  129.737496] [ 3|  262|   kworker/u8:3] async_demo2_probe: parent platform
23 [  129.737633] [ 3|  262|   kworker/u8:3] async_demo2_probe enter.
24 [  129.745080] [ 2|   35|   kworker/u8:2] driver_attach_async enter.
25 [  129.752320] [ 3|   28|   kworker/u8:1] driver_attach_async enter.
26 [  129.764287] [ 2|   35|   kworker/u8:2] __driver_attach enter, dev: async_demo3
27 [  129.764487] [ 2|   35|   kworker/u8:2] bus: platform: driver_probe_device: matched device async_demo3 with driver async_demo3
28 [  129.764807] [ 2|   35|   kworker/u8:2] async_demo3_probe enter.
29 [  129.765317] [ 3|   28|   kworker/u8:1] __driver_attach enter, dev: async_demo4
30 [  129.765465] [ 3|   28|   kworker/u8:1] bus: platform: driver_probe_device: matched device async_demo4 with driver async_demo4
31 [  129.765760] [ 3|   28|   kworker/u8:1] async_demo4_probe enter.
32 [  130.733864] [ 3|   28|   kworker/u8:1] async_demo4_probe exit.
33 [  130.734143] [ 3|   28|   kworker/u8:1] bus: platform: driver async_demo4 async attach completed: 0
34 [  131.710647] [ 2|   35|   kworker/u8:2] async_demo3_probe exit.
35 [  131.710940] [ 2|   35|   kworker/u8:2] bus: platform: driver async_demo3 async attach completed: 0
36 [  132.612441] [ 3|  262|   kworker/u8:3] async_demo2_probe exit.
37 [  132.612759] [ 3|  262|   kworker/u8:3] bus: platform: driver async_demo2 async attach completed: 0
38 [  133.514075] [ 3|  403|   kworker/u8:4] async_demo1_probe exit.
39 [  133.514386] [ 3|  403|   kworker/u8:4] bus: platform: driver async_demo1 async attach completed: 0

耗时3.8s左右。

 
 
未完待续……

以上是关于设备驱动的异步加载 —— 示例分析的主要内容,如果未能解决你的问题,请参考以下文章

当活动中的异步任务完成时如何在片段中重新加载ui?

如何延迟或异步此 WordPress javascript 片段以最后加载以加快页面加载时间?

异步任务片段背景数据

我应该在 Fragment 中的啥生命周期状态下执行异步任务?

从片段中调用分离的异步任务类

片段布局加载延迟