diff options
author | Dmitry Torokhov <dtor@chromium.org> | 2016-09-29 11:13:14 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-11-10 11:28:16 -0500 |
commit | 79543cf2b18ea4a35f8864849d7ad8882ea8a23d (patch) | |
tree | 1a13abe673b27f0eaa3267022a0a4a7805fee790 /drivers/base | |
parent | 6751667a29d6fd64afb9ce30567ad616b68ed789 (diff) |
driver-core: add test module for asynchronous probing
This test module tries to test asynchronous driver probing by having a
driver that sleeps for an extended period of time (5 secs) in its
probe() method. It measures the time needed to register this driver
(with device already registered) and a new device (with driver already
registered). The module will fail to load if the time spent in register
call is more than half the probing sleep time.
As a sanity check the driver will then try to synchronously register
driver and device and fail if registration takes less than half of the
probing sleep time.
Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Reviewed-by: Olof Johansson <olofj@chromium.org>
Signed-off-by: Guenter Roeck <groeck@chromium.org>
Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 2 | ||||
-rw-r--r-- | drivers/base/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/test/Kconfig | 9 | ||||
-rw-r--r-- | drivers/base/test/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/test/test_async_driver_probe.c | 171 |
5 files changed, 185 insertions, 0 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index d02e7c0f5bfd..8defa9d87a6f 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -224,6 +224,8 @@ config DEBUG_TEST_DRIVER_REMOVE | |||
224 | unusable. You should say N here unless you are explicitly looking to | 224 | unusable. You should say N here unless you are explicitly looking to |
225 | test this functionality. | 225 | test this functionality. |
226 | 226 | ||
227 | source "drivers/base/test/Kconfig" | ||
228 | |||
227 | config SYS_HYPERVISOR | 229 | config SYS_HYPERVISOR |
228 | bool | 230 | bool |
229 | default n | 231 | default n |
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 2609ba20b396..f2816f6ff76a 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -24,5 +24,7 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o | |||
24 | obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o | 24 | obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o |
25 | obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o | 25 | obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o |
26 | 26 | ||
27 | obj-y += test/ | ||
28 | |||
27 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG | 29 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG |
28 | 30 | ||
diff --git a/drivers/base/test/Kconfig b/drivers/base/test/Kconfig new file mode 100644 index 000000000000..9aa0d45a60db --- /dev/null +++ b/drivers/base/test/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config TEST_ASYNC_DRIVER_PROBE | ||
2 | tristate "Build kernel module to test asynchronous driver probing" | ||
3 | depends on m | ||
4 | help | ||
5 | Enabling this option produces a kernel module that allows | ||
6 | testing asynchronous driver probing by the device core. | ||
7 | The module name will be test_async_driver_probe.ko | ||
8 | |||
9 | If unsure say N. | ||
diff --git a/drivers/base/test/Makefile b/drivers/base/test/Makefile new file mode 100644 index 000000000000..90477c5fd9f9 --- /dev/null +++ b/drivers/base/test/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_TEST_ASYNC_DRIVER_PROBE) += test_async_driver_probe.o | |||
diff --git a/drivers/base/test/test_async_driver_probe.c b/drivers/base/test/test_async_driver_probe.c new file mode 100644 index 000000000000..3a71e83e5d98 --- /dev/null +++ b/drivers/base/test/test_async_driver_probe.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Google, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/hrtimer.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/time.h> | ||
22 | |||
23 | #define TEST_PROBE_DELAY (5 * 1000) /* 5 sec */ | ||
24 | #define TEST_PROBE_THRESHOLD (TEST_PROBE_DELAY / 2) | ||
25 | |||
26 | static int test_probe(struct platform_device *pdev) | ||
27 | { | ||
28 | dev_info(&pdev->dev, "sleeping for %d msecs in probe\n", | ||
29 | TEST_PROBE_DELAY); | ||
30 | msleep(TEST_PROBE_DELAY); | ||
31 | dev_info(&pdev->dev, "done sleeping\n"); | ||
32 | |||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static struct platform_driver async_driver = { | ||
37 | .driver = { | ||
38 | .name = "test_async_driver", | ||
39 | .owner = THIS_MODULE, | ||
40 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, | ||
41 | }, | ||
42 | .probe = test_probe, | ||
43 | }; | ||
44 | |||
45 | static struct platform_driver sync_driver = { | ||
46 | .driver = { | ||
47 | .name = "test_sync_driver", | ||
48 | .owner = THIS_MODULE, | ||
49 | .probe_type = PROBE_FORCE_SYNCHRONOUS, | ||
50 | }, | ||
51 | .probe = test_probe, | ||
52 | }; | ||
53 | |||
54 | static struct platform_device *async_dev_1, *async_dev_2; | ||
55 | static struct platform_device *sync_dev_1; | ||
56 | |||
57 | static int __init test_async_probe_init(void) | ||
58 | { | ||
59 | ktime_t calltime, delta; | ||
60 | unsigned long long duration; | ||
61 | int error; | ||
62 | |||
63 | pr_info("registering first asynchronous device...\n"); | ||
64 | |||
65 | async_dev_1 = platform_device_register_simple("test_async_driver", 1, | ||
66 | NULL, 0); | ||
67 | if (IS_ERR(async_dev_1)) { | ||
68 | error = PTR_ERR(async_dev_1); | ||
69 | pr_err("failed to create async_dev_1: %d", error); | ||
70 | return error; | ||
71 | } | ||
72 | |||
73 | pr_info("registering asynchronous driver...\n"); | ||
74 | calltime = ktime_get(); | ||
75 | error = platform_driver_register(&async_driver); | ||
76 | if (error) { | ||
77 | pr_err("Failed to register async_driver: %d\n", error); | ||
78 | goto err_unregister_async_dev_1; | ||
79 | } | ||
80 | |||
81 | delta = ktime_sub(ktime_get(), calltime); | ||
82 | duration = (unsigned long long) ktime_to_ms(delta); | ||
83 | pr_info("registration took %lld msecs\n", duration); | ||
84 | if (duration > TEST_PROBE_THRESHOLD) { | ||
85 | pr_err("test failed: probe took too long\n"); | ||
86 | error = -ETIMEDOUT; | ||
87 | goto err_unregister_async_driver; | ||
88 | } | ||
89 | |||
90 | pr_info("registering second asynchronous device...\n"); | ||
91 | calltime = ktime_get(); | ||
92 | async_dev_2 = platform_device_register_simple("test_async_driver", 2, | ||
93 | NULL, 0); | ||
94 | if (IS_ERR(async_dev_2)) { | ||
95 | error = PTR_ERR(async_dev_2); | ||
96 | pr_err("failed to create async_dev_2: %d", error); | ||
97 | goto err_unregister_async_driver; | ||
98 | } | ||
99 | |||
100 | delta = ktime_sub(ktime_get(), calltime); | ||
101 | duration = (unsigned long long) ktime_to_ms(delta); | ||
102 | pr_info("registration took %lld msecs\n", duration); | ||
103 | if (duration > TEST_PROBE_THRESHOLD) { | ||
104 | pr_err("test failed: probe took too long\n"); | ||
105 | error = -ETIMEDOUT; | ||
106 | goto err_unregister_async_dev_2; | ||
107 | } | ||
108 | |||
109 | pr_info("registering synchronous driver...\n"); | ||
110 | |||
111 | error = platform_driver_register(&sync_driver); | ||
112 | if (error) { | ||
113 | pr_err("Failed to register async_driver: %d\n", error); | ||
114 | goto err_unregister_async_dev_2; | ||
115 | } | ||
116 | |||
117 | pr_info("registering synchronous device...\n"); | ||
118 | calltime = ktime_get(); | ||
119 | sync_dev_1 = platform_device_register_simple("test_sync_driver", 1, | ||
120 | NULL, 0); | ||
121 | if (IS_ERR(async_dev_1)) { | ||
122 | error = PTR_ERR(sync_dev_1); | ||
123 | pr_err("failed to create sync_dev_1: %d", error); | ||
124 | goto err_unregister_sync_driver; | ||
125 | } | ||
126 | |||
127 | delta = ktime_sub(ktime_get(), calltime); | ||
128 | duration = (unsigned long long) ktime_to_ms(delta); | ||
129 | pr_info("registration took %lld msecs\n", duration); | ||
130 | if (duration < TEST_PROBE_THRESHOLD) { | ||
131 | pr_err("test failed: probe was too quick\n"); | ||
132 | error = -ETIMEDOUT; | ||
133 | goto err_unregister_sync_dev_1; | ||
134 | } | ||
135 | |||
136 | pr_info("completed successfully"); | ||
137 | |||
138 | return 0; | ||
139 | |||
140 | err_unregister_sync_dev_1: | ||
141 | platform_device_unregister(sync_dev_1); | ||
142 | |||
143 | err_unregister_sync_driver: | ||
144 | platform_driver_unregister(&sync_driver); | ||
145 | |||
146 | err_unregister_async_dev_2: | ||
147 | platform_device_unregister(async_dev_2); | ||
148 | |||
149 | err_unregister_async_driver: | ||
150 | platform_driver_unregister(&async_driver); | ||
151 | |||
152 | err_unregister_async_dev_1: | ||
153 | platform_device_unregister(async_dev_1); | ||
154 | |||
155 | return error; | ||
156 | } | ||
157 | module_init(test_async_probe_init); | ||
158 | |||
159 | static void __exit test_async_probe_exit(void) | ||
160 | { | ||
161 | platform_driver_unregister(&async_driver); | ||
162 | platform_driver_unregister(&sync_driver); | ||
163 | platform_device_unregister(async_dev_1); | ||
164 | platform_device_unregister(async_dev_2); | ||
165 | platform_device_unregister(sync_dev_1); | ||
166 | } | ||
167 | module_exit(test_async_probe_exit); | ||
168 | |||
169 | MODULE_DESCRIPTION("Test module for asynchronous driver probing"); | ||
170 | MODULE_AUTHOR("Dmitry Torokhov <dtor@chromium.org>"); | ||
171 | MODULE_LICENSE("GPL"); | ||