作者
彭東林
pengdonglin137@163.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 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的。
涉及到代碼可以到下面的鏈接下載:
https://github.com/pengdonglin137/async_drv_load_demo
正文
一、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
耗時3.8s左右。
未完待續……