106188bc8SMaxime Ripard // SPDX-License-Identifier: GPL-2.0
206188bc8SMaxime Ripard // Copyright 2023 Maxime Ripard <mripard@kernel.org>
306188bc8SMaxime Ripard
406188bc8SMaxime Ripard #include <kunit/resource.h>
506188bc8SMaxime Ripard
606188bc8SMaxime Ripard #include <linux/device.h>
706188bc8SMaxime Ripard
806188bc8SMaxime Ripard #define DEVICE_NAME "test"
906188bc8SMaxime Ripard
1006188bc8SMaxime Ripard struct test_priv {
1106188bc8SMaxime Ripard bool probe_done;
1206188bc8SMaxime Ripard bool release_done;
1306188bc8SMaxime Ripard wait_queue_head_t release_wq;
1406188bc8SMaxime Ripard struct device *dev;
1506188bc8SMaxime Ripard };
1606188bc8SMaxime Ripard
root_device_devm_init(struct kunit * test)1706188bc8SMaxime Ripard static int root_device_devm_init(struct kunit *test)
1806188bc8SMaxime Ripard {
1906188bc8SMaxime Ripard struct test_priv *priv;
2006188bc8SMaxime Ripard
2106188bc8SMaxime Ripard priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
2206188bc8SMaxime Ripard KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
2306188bc8SMaxime Ripard init_waitqueue_head(&priv->release_wq);
2406188bc8SMaxime Ripard
2506188bc8SMaxime Ripard test->priv = priv;
2606188bc8SMaxime Ripard
2706188bc8SMaxime Ripard return 0;
2806188bc8SMaxime Ripard }
2906188bc8SMaxime Ripard
devm_device_action(void * ptr)3006188bc8SMaxime Ripard static void devm_device_action(void *ptr)
3106188bc8SMaxime Ripard {
3206188bc8SMaxime Ripard struct test_priv *priv = ptr;
3306188bc8SMaxime Ripard
3406188bc8SMaxime Ripard priv->release_done = true;
3506188bc8SMaxime Ripard wake_up_interruptible(&priv->release_wq);
3606188bc8SMaxime Ripard }
3706188bc8SMaxime Ripard
3806188bc8SMaxime Ripard #define RELEASE_TIMEOUT_MS 100
3906188bc8SMaxime Ripard
4006188bc8SMaxime Ripard /*
4106188bc8SMaxime Ripard * Tests that a bus-less, non-probed device will run its device-managed
4206188bc8SMaxime Ripard * actions when unregistered.
4306188bc8SMaxime Ripard */
root_device_devm_register_unregister_test(struct kunit * test)4406188bc8SMaxime Ripard static void root_device_devm_register_unregister_test(struct kunit *test)
4506188bc8SMaxime Ripard {
4606188bc8SMaxime Ripard struct test_priv *priv = test->priv;
4706188bc8SMaxime Ripard int ret;
4806188bc8SMaxime Ripard
4906188bc8SMaxime Ripard priv->dev = root_device_register(DEVICE_NAME);
5006188bc8SMaxime Ripard KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
5106188bc8SMaxime Ripard
5206188bc8SMaxime Ripard ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
5306188bc8SMaxime Ripard KUNIT_ASSERT_EQ(test, ret, 0);
5406188bc8SMaxime Ripard
5506188bc8SMaxime Ripard root_device_unregister(priv->dev);
5606188bc8SMaxime Ripard
5706188bc8SMaxime Ripard ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
5806188bc8SMaxime Ripard msecs_to_jiffies(RELEASE_TIMEOUT_MS));
5906188bc8SMaxime Ripard KUNIT_EXPECT_GT(test, ret, 0);
6006188bc8SMaxime Ripard }
6106188bc8SMaxime Ripard
devm_put_device_action(void * ptr)6206188bc8SMaxime Ripard static void devm_put_device_action(void *ptr)
6306188bc8SMaxime Ripard {
6406188bc8SMaxime Ripard struct test_priv *priv = ptr;
6506188bc8SMaxime Ripard
6606188bc8SMaxime Ripard put_device(priv->dev);
6706188bc8SMaxime Ripard priv->release_done = true;
6806188bc8SMaxime Ripard wake_up_interruptible(&priv->release_wq);
6906188bc8SMaxime Ripard }
7006188bc8SMaxime Ripard
7106188bc8SMaxime Ripard /*
7206188bc8SMaxime Ripard * Tests that a bus-less, non-probed device will run its device-managed
7306188bc8SMaxime Ripard * actions when unregistered, even if someone still holds a reference to
7406188bc8SMaxime Ripard * it.
7506188bc8SMaxime Ripard */
root_device_devm_register_get_unregister_with_devm_test(struct kunit * test)7606188bc8SMaxime Ripard static void root_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
7706188bc8SMaxime Ripard {
7806188bc8SMaxime Ripard struct test_priv *priv = test->priv;
7906188bc8SMaxime Ripard int ret;
8006188bc8SMaxime Ripard
8106188bc8SMaxime Ripard priv->dev = root_device_register(DEVICE_NAME);
8206188bc8SMaxime Ripard KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
8306188bc8SMaxime Ripard
8406188bc8SMaxime Ripard get_device(priv->dev);
8506188bc8SMaxime Ripard
8606188bc8SMaxime Ripard ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
8706188bc8SMaxime Ripard KUNIT_ASSERT_EQ(test, ret, 0);
8806188bc8SMaxime Ripard
8906188bc8SMaxime Ripard root_device_unregister(priv->dev);
9006188bc8SMaxime Ripard
9106188bc8SMaxime Ripard ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
9206188bc8SMaxime Ripard msecs_to_jiffies(RELEASE_TIMEOUT_MS));
9306188bc8SMaxime Ripard KUNIT_EXPECT_GT(test, ret, 0);
9406188bc8SMaxime Ripard }
9506188bc8SMaxime Ripard
9606188bc8SMaxime Ripard static struct kunit_case root_device_devm_tests[] = {
9706188bc8SMaxime Ripard KUNIT_CASE(root_device_devm_register_unregister_test),
9806188bc8SMaxime Ripard KUNIT_CASE(root_device_devm_register_get_unregister_with_devm_test),
9906188bc8SMaxime Ripard {}
10006188bc8SMaxime Ripard };
10106188bc8SMaxime Ripard
10206188bc8SMaxime Ripard static struct kunit_suite root_device_devm_test_suite = {
10306188bc8SMaxime Ripard .name = "root-device-devm",
10406188bc8SMaxime Ripard .init = root_device_devm_init,
10506188bc8SMaxime Ripard .test_cases = root_device_devm_tests,
10606188bc8SMaxime Ripard };
10706188bc8SMaxime Ripard
10806188bc8SMaxime Ripard kunit_test_suite(root_device_devm_test_suite);
109*f7bb2426SMaxime Ripard
110*f7bb2426SMaxime Ripard MODULE_DESCRIPTION("Test module for root devices");
111*f7bb2426SMaxime Ripard MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
112*f7bb2426SMaxime Ripard MODULE_LICENSE("GPL");
113