diff options
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 | 169 |
3 files changed, 179 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..304d5c2bd5e9 --- /dev/null +++ b/drivers/base/test/test_async_driver_probe.c @@ -0,0 +1,169 @@ +/* + * 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", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = test_probe, +}; + +static struct platform_driver sync_driver = { + .driver = { + .name = "test_sync_driver", + .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(sync_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"); |