1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright 2023 Maxime Ripard <mripard@kernel.org> |
3 | |
4 | #include <kunit/resource.h> |
5 | |
6 | #include <linux/device.h> |
7 | |
8 | #define DEVICE_NAME "test" |
9 | |
10 | struct test_priv { |
11 | bool probe_done; |
12 | bool release_done; |
13 | wait_queue_head_t release_wq; |
14 | struct device *dev; |
15 | }; |
16 | |
17 | static int root_device_devm_init(struct kunit *test) |
18 | { |
19 | struct test_priv *priv; |
20 | |
21 | priv = kunit_kzalloc(test, size: sizeof(*priv), GFP_KERNEL); |
22 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); |
23 | init_waitqueue_head(&priv->release_wq); |
24 | |
25 | test->priv = priv; |
26 | |
27 | return 0; |
28 | } |
29 | |
30 | static void devm_device_action(void *ptr) |
31 | { |
32 | struct test_priv *priv = ptr; |
33 | |
34 | priv->release_done = true; |
35 | wake_up_interruptible(&priv->release_wq); |
36 | } |
37 | |
38 | #define RELEASE_TIMEOUT_MS 100 |
39 | |
40 | /* |
41 | * Tests that a bus-less, non-probed device will run its device-managed |
42 | * actions when unregistered. |
43 | */ |
44 | static void root_device_devm_register_unregister_test(struct kunit *test) |
45 | { |
46 | struct test_priv *priv = test->priv; |
47 | int ret; |
48 | |
49 | priv->dev = root_device_register(DEVICE_NAME); |
50 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev); |
51 | |
52 | ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv); |
53 | KUNIT_ASSERT_EQ(test, ret, 0); |
54 | |
55 | root_device_unregister(root: priv->dev); |
56 | |
57 | ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, |
58 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
59 | KUNIT_EXPECT_GT(test, ret, 0); |
60 | } |
61 | |
62 | static void devm_put_device_action(void *ptr) |
63 | { |
64 | struct test_priv *priv = ptr; |
65 | |
66 | put_device(dev: priv->dev); |
67 | priv->release_done = true; |
68 | wake_up_interruptible(&priv->release_wq); |
69 | } |
70 | |
71 | /* |
72 | * Tests that a bus-less, non-probed device will run its device-managed |
73 | * actions when unregistered, even if someone still holds a reference to |
74 | * it. |
75 | */ |
76 | static void root_device_devm_register_get_unregister_with_devm_test(struct kunit *test) |
77 | { |
78 | struct test_priv *priv = test->priv; |
79 | int ret; |
80 | |
81 | priv->dev = root_device_register(DEVICE_NAME); |
82 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev); |
83 | |
84 | get_device(dev: priv->dev); |
85 | |
86 | ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv); |
87 | KUNIT_ASSERT_EQ(test, ret, 0); |
88 | |
89 | root_device_unregister(root: priv->dev); |
90 | |
91 | ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, |
92 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
93 | KUNIT_EXPECT_GT(test, ret, 0); |
94 | } |
95 | |
96 | static struct kunit_case root_device_devm_tests[] = { |
97 | KUNIT_CASE(root_device_devm_register_unregister_test), |
98 | KUNIT_CASE(root_device_devm_register_get_unregister_with_devm_test), |
99 | {} |
100 | }; |
101 | |
102 | static struct kunit_suite root_device_devm_test_suite = { |
103 | .name = "root-device-devm" , |
104 | .init = root_device_devm_init, |
105 | .test_cases = root_device_devm_tests, |
106 | }; |
107 | |
108 | kunit_test_suite(root_device_devm_test_suite); |
109 | |
110 | MODULE_DESCRIPTION("Test module for root devices" ); |
111 | MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>" ); |
112 | MODULE_LICENSE("GPL" ); |
113 | |