天天看點

裝置驅動的異步加載 —— 示例分析(1)

作者

彭東林

平台

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
    device's 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的。

正文

一、I2C從裝置驅動的異步加載

        這裡隻關心調用驅動probe的順序,不關心具體驅動的功能。在裝置樹裡添加4個I2C控制器節點,在第1組I2C控制器下挂兩個從裝置,目的是觀察同一條I2C總線下的從裝置驅動的加載順序,其他三個I2C控制器下面各挂一個從裝置,目的是觀察不同I2C總線下的從裝置驅動的異步加載順序。為了友善,在驅動probe函數中添加了msleep函數。

        由于在下面的例子中,裝置樹的解析時間較早,也就是在注冊驅動時,對應的device早已經存在了,是以主要分析注冊驅動後,驅動找裝置的情形。

  • 裝置樹

I2C控制器1,下面挂了兩個從裝置:

async_demo1_i2c: i2c@20000 {
        compatible = "arm,versatile-i2c";
        reg = <0x20000 0x1000>;
        #address-cells = <1>;
        #size-cells = <0>;

        async_demo1@39 {
            compatible = "async_demo1_i2c";
            reg = <0x39>;
            status = "okay";
        };

        async_demo1@3a {
            compatible = "async_demo5_i2c";
            reg = <0x3a>;
            status = "okay";
        };
    };      

其他三個I2C控制器,每個下面各挂一個從裝置:

async_demo2_i2c: i2c@30000 {
        compatible = "arm,versatile-i2c";
        reg = <0x30000 0x1000>;

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

        async_demo2@39 {
            compatible = "async_demo2_i2c";
            reg = <0x39>;
            status = "okay";
        };

    };

    async_demo3_i2c: i2c@40000 {
        compatible = "arm,versatile-i2c";
        reg = <0x40000 0x1000>;

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

        async_demo3@39 {
            compatible = "async_demo3_i2c";
            reg = <0x39>;
            status = "okay";
        };

    };

    async_demo4_i2c: i2c@50000 {
        compatible = "arm,versatile-i2c";
        reg = <0x50000 0x1000>;

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

        async_demo4@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 [root@vexpress 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 [root@vexpress 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控制器下,即便驅動裡支援異步,但是從結果來看還是是串行的。上面第二個中括号中數字的含義 [處理器編号 | 程序PID | 程序名稱]。

  在異步加載情形下,驅動注冊時,先在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 [root@vexpress 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 [root@vexpress 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 [root@vexpress 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      

未完待續……

繼續閱讀