diff options
author | Dmitry Torokhov <dtor@chromium.org> | 2016-09-29 18:13:14 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-11-10 19:28:16 +0300 |
commit | 79543cf2b18ea4a35f8864849d7ad8882ea8a23d (patch) | |
tree | 1a13abe673b27f0eaa3267022a0a4a7805fee790 /drivers/base/test | |
parent | 6751667a29d6fd64afb9ce30567ad616b68ed789 (diff) | |
download | linux-79543cf2b18ea4a35f8864849d7ad8882ea8a23d.tar.xz |
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/test')
-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 |
3 files changed, 181 insertions, 0 deletions
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 @@ +config TEST_ASYNC_DRIVER_PROBE + tristate "Build kernel module to test asynchronous driver probing" + depends on m + help + Enabling this option produces a kernel module that allows + testing asynchronous driver probing by the device core. + The module name will be test_async_driver_probe.ko + + 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 @@ +/* + * Copyright (C) 2014 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/hrtimer.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/time.h> + +#define TEST_PROBE_DELAY (5 * 1000) /* 5 sec */ +#define TEST_PROBE_THRESHOLD (TEST_PROBE_DELAY / 2) + +static int test_probe(struct platform_device *pdev) +{ + dev_info(&pdev->dev, "sleeping for %d msecs in probe\n", + TEST_PROBE_DELAY); + msleep(TEST_PROBE_DELAY); + dev_info(&pdev->dev, "done sleeping\n"); + + return 0; +} + +static struct platform_driver async_driver = { + .driver = { + .name = "test_async_driver", + .owner = THIS_MODULE, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = test_probe, +}; + +static struct platform_driver sync_driver = { + .driver = { + .name = "test_sync_driver", + .owner = THIS_MODULE, + .probe_type = PROBE_FORCE_SYNCHRONOUS, + }, + .probe = test_probe, +}; + +static struct platform_device *async_dev_1, *async_dev_2; +static struct platform_device *sync_dev_1; + +static int __init test_async_probe_init(void) +{ + ktime_t calltime, delta; + unsigned long long duration; + int error; + + pr_info("registering first asynchronous device...\n"); + + async_dev_1 = platform_device_register_simple("test_async_driver", 1, + NULL, 0); + if (IS_ERR(async_dev_1)) { + error = PTR_ERR(async_dev_1); + pr_err("failed to create async_dev_1: %d", error); + return error; + } + + pr_info("registering asynchronous driver...\n"); + calltime = ktime_get(); + error = platform_driver_register(&async_driver); + if (error) { + pr_err("Failed to register async_driver: %d\n", error); + goto err_unregister_async_dev_1; + } + + delta = ktime_sub(ktime_get(), calltime); + duration = (unsigned long long) ktime_to_ms(delta); + pr_info("registration took %lld msecs\n", duration); + if (duration > TEST_PROBE_THRESHOLD) { + pr_err("test failed: probe took too long\n"); + error = -ETIMEDOUT; + goto err_unregister_async_driver; + } + + pr_info("registering second asynchronous device...\n"); + calltime = ktime_get(); + async_dev_2 = platform_device_register_simple("test_async_driver", 2, + NULL, 0); + if (IS_ERR(async_dev_2)) { + error = PTR_ERR(async_dev_2); + pr_err("failed to create async_dev_2: %d", error); + goto err_unregister_async_driver; + } + + delta = ktime_sub(ktime_get(), calltime); + duration = (unsigned long long) ktime_to_ms(delta); + pr_info("registration took %lld msecs\n", duration); + if (duration > TEST_PROBE_THRESHOLD) { + pr_err("test failed: probe took too long\n"); + error = -ETIMEDOUT; + goto err_unregister_async_dev_2; + } + + pr_info("registering synchronous driver...\n"); + + error = platform_driver_register(&sync_driver); + if (error) { + pr_err("Failed to register async_driver: %d\n", error); + goto err_unregister_async_dev_2; + } + + pr_info("registering synchronous device...\n"); + calltime = ktime_get(); + sync_dev_1 = platform_device_register_simple("test_sync_driver", 1, + NULL, 0); + if (IS_ERR(async_dev_1)) { + error = PTR_ERR(sync_dev_1); + pr_err("failed to create sync_dev_1: %d", error); + goto err_unregister_sync_driver; + } + + delta = ktime_sub(ktime_get(), calltime); + duration = (unsigned long long) ktime_to_ms(delta); + pr_info("registration took %lld msecs\n", duration); + if (duration < TEST_PROBE_THRESHOLD) { + pr_err("test failed: probe was too quick\n"); + error = -ETIMEDOUT; + goto err_unregister_sync_dev_1; + } + + pr_info("completed successfully"); + + return 0; + +err_unregister_sync_dev_1: + platform_device_unregister(sync_dev_1); + +err_unregister_sync_driver: + platform_driver_unregister(&sync_driver); + +err_unregister_async_dev_2: + platform_device_unregister(async_dev_2); + +err_unregister_async_driver: + platform_driver_unregister(&async_driver); + +err_unregister_async_dev_1: + platform_device_unregister(async_dev_1); + + return error; +} +module_init(test_async_probe_init); + +static void __exit test_async_probe_exit(void) +{ + platform_driver_unregister(&async_driver); + platform_driver_unregister(&sync_driver); + platform_device_unregister(async_dev_1); + platform_device_unregister(async_dev_2); + platform_device_unregister(sync_dev_1); +} +module_exit(test_async_probe_exit); + +MODULE_DESCRIPTION("Test module for asynchronous driver probing"); +MODULE_AUTHOR("Dmitry Torokhov <dtor@chromium.org>"); +MODULE_LICENSE("GPL"); |