1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | |
3 | #include <kunit/resource.h> |
4 | |
5 | #include <linux/device.h> |
6 | #include <linux/platform_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 probe_wq; |
14 | wait_queue_head_t release_wq; |
15 | struct device *dev; |
16 | }; |
17 | |
18 | static int platform_device_devm_init(struct kunit *test) |
19 | { |
20 | struct test_priv *priv; |
21 | |
22 | priv = kunit_kzalloc(test, size: sizeof(*priv), GFP_KERNEL); |
23 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); |
24 | init_waitqueue_head(&priv->probe_wq); |
25 | init_waitqueue_head(&priv->release_wq); |
26 | |
27 | test->priv = priv; |
28 | |
29 | return 0; |
30 | } |
31 | |
32 | static void devm_device_action(void *ptr) |
33 | { |
34 | struct test_priv *priv = ptr; |
35 | |
36 | priv->release_done = true; |
37 | wake_up_interruptible(&priv->release_wq); |
38 | } |
39 | |
40 | static void devm_put_device_action(void *ptr) |
41 | { |
42 | struct test_priv *priv = ptr; |
43 | |
44 | put_device(dev: priv->dev); |
45 | priv->release_done = true; |
46 | wake_up_interruptible(&priv->release_wq); |
47 | } |
48 | |
49 | #define RELEASE_TIMEOUT_MS 100 |
50 | |
51 | /* |
52 | * Tests that a platform bus, non-probed device will run its |
53 | * device-managed actions when unregistered. |
54 | */ |
55 | static void platform_device_devm_register_unregister_test(struct kunit *test) |
56 | { |
57 | struct platform_device *pdev; |
58 | struct test_priv *priv = test->priv; |
59 | int ret; |
60 | |
61 | pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); |
62 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); |
63 | |
64 | ret = platform_device_add(pdev); |
65 | KUNIT_ASSERT_EQ(test, ret, 0); |
66 | |
67 | priv->dev = &pdev->dev; |
68 | |
69 | ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv); |
70 | KUNIT_ASSERT_EQ(test, ret, 0); |
71 | |
72 | platform_device_unregister(pdev); |
73 | |
74 | ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, |
75 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
76 | KUNIT_EXPECT_GT(test, ret, 0); |
77 | } |
78 | |
79 | /* |
80 | * Tests that a platform bus, non-probed device will run its |
81 | * device-managed actions when unregistered, even if someone still holds |
82 | * a reference to it. |
83 | */ |
84 | static void platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test) |
85 | { |
86 | struct platform_device *pdev; |
87 | struct test_priv *priv = test->priv; |
88 | int ret; |
89 | |
90 | pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); |
91 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); |
92 | |
93 | ret = platform_device_add(pdev); |
94 | KUNIT_ASSERT_EQ(test, ret, 0); |
95 | |
96 | priv->dev = &pdev->dev; |
97 | |
98 | get_device(dev: priv->dev); |
99 | |
100 | ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv); |
101 | KUNIT_ASSERT_EQ(test, ret, 0); |
102 | |
103 | platform_device_unregister(pdev); |
104 | |
105 | ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, |
106 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
107 | KUNIT_EXPECT_GT(test, ret, 0); |
108 | } |
109 | |
110 | static int fake_probe(struct platform_device *pdev) |
111 | { |
112 | struct test_priv *priv = platform_get_drvdata(pdev); |
113 | |
114 | priv->probe_done = true; |
115 | wake_up_interruptible(&priv->probe_wq); |
116 | |
117 | return 0; |
118 | } |
119 | |
120 | static struct platform_driver fake_driver = { |
121 | .probe = fake_probe, |
122 | .driver = { |
123 | .name = DEVICE_NAME, |
124 | }, |
125 | }; |
126 | |
127 | /* |
128 | * Tests that a platform bus, probed device will run its device-managed |
129 | * actions when unregistered. |
130 | */ |
131 | static void probed_platform_device_devm_register_unregister_test(struct kunit *test) |
132 | { |
133 | struct platform_device *pdev; |
134 | struct test_priv *priv = test->priv; |
135 | int ret; |
136 | |
137 | ret = platform_driver_register(&fake_driver); |
138 | KUNIT_ASSERT_EQ(test, ret, 0); |
139 | |
140 | pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); |
141 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); |
142 | |
143 | priv->dev = &pdev->dev; |
144 | platform_set_drvdata(pdev, data: priv); |
145 | |
146 | ret = platform_device_add(pdev); |
147 | KUNIT_ASSERT_EQ(test, ret, 0); |
148 | |
149 | ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done, |
150 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
151 | KUNIT_ASSERT_GT(test, ret, 0); |
152 | |
153 | ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv); |
154 | KUNIT_ASSERT_EQ(test, ret, 0); |
155 | |
156 | platform_device_unregister(pdev); |
157 | |
158 | ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, |
159 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
160 | KUNIT_EXPECT_GT(test, ret, 0); |
161 | |
162 | platform_driver_unregister(&fake_driver); |
163 | } |
164 | |
165 | /* |
166 | * Tests that a platform bus, probed device will run its device-managed |
167 | * actions when unregistered, even if someone still holds a reference to |
168 | * it. |
169 | */ |
170 | static void probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test) |
171 | { |
172 | struct platform_device *pdev; |
173 | struct test_priv *priv = test->priv; |
174 | int ret; |
175 | |
176 | ret = platform_driver_register(&fake_driver); |
177 | KUNIT_ASSERT_EQ(test, ret, 0); |
178 | |
179 | pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE); |
180 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); |
181 | |
182 | priv->dev = &pdev->dev; |
183 | platform_set_drvdata(pdev, data: priv); |
184 | |
185 | ret = platform_device_add(pdev); |
186 | KUNIT_ASSERT_EQ(test, ret, 0); |
187 | |
188 | ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done, |
189 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
190 | KUNIT_ASSERT_GT(test, ret, 0); |
191 | |
192 | get_device(dev: priv->dev); |
193 | |
194 | ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv); |
195 | KUNIT_ASSERT_EQ(test, ret, 0); |
196 | |
197 | platform_device_unregister(pdev); |
198 | |
199 | ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done, |
200 | msecs_to_jiffies(RELEASE_TIMEOUT_MS)); |
201 | KUNIT_EXPECT_GT(test, ret, 0); |
202 | |
203 | platform_driver_unregister(&fake_driver); |
204 | } |
205 | |
206 | static struct kunit_case platform_device_devm_tests[] = { |
207 | KUNIT_CASE(platform_device_devm_register_unregister_test), |
208 | KUNIT_CASE(platform_device_devm_register_get_unregister_with_devm_test), |
209 | KUNIT_CASE(probed_platform_device_devm_register_unregister_test), |
210 | KUNIT_CASE(probed_platform_device_devm_register_get_unregister_with_devm_test), |
211 | {} |
212 | }; |
213 | |
214 | static struct kunit_suite platform_device_devm_test_suite = { |
215 | .name = "platform-device-devm", |
216 | .init = platform_device_devm_init, |
217 | .test_cases = platform_device_devm_tests, |
218 | }; |
219 | |
220 | kunit_test_suite(platform_device_devm_test_suite); |
221 | |
222 | MODULE_DESCRIPTION("Test module for platform devices"); |
223 | MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>"); |
224 | MODULE_LICENSE("GPL"); |
225 |
Definitions
- test_priv
- platform_device_devm_init
- devm_device_action
- devm_put_device_action
- platform_device_devm_register_unregister_test
- platform_device_devm_register_get_unregister_with_devm_test
- fake_probe
- fake_driver
- probed_platform_device_devm_register_unregister_test
- probed_platform_device_devm_register_get_unregister_with_devm_test
- platform_device_devm_tests
Improve your Profiling and Debugging skills
Find out more