1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <kunit/platform_device.h>
4 #include <kunit/resource.h>
5
6 #include <linux/device.h>
7 #include <linux/device/bus.h>
8 #include <linux/of_platform.h>
9 #include <linux/platform_device.h>
10
11 #define DEVICE_NAME "test"
12
13 struct test_priv {
14 bool probe_done;
15 bool release_done;
16 wait_queue_head_t probe_wq;
17 wait_queue_head_t release_wq;
18 struct device *dev;
19 };
20
platform_device_devm_init(struct kunit * test)21 static int platform_device_devm_init(struct kunit *test)
22 {
23 struct test_priv *priv;
24
25 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
26 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
27 init_waitqueue_head(&priv->probe_wq);
28 init_waitqueue_head(&priv->release_wq);
29
30 test->priv = priv;
31
32 return 0;
33 }
34
devm_device_action(void * ptr)35 static void devm_device_action(void *ptr)
36 {
37 struct test_priv *priv = ptr;
38
39 priv->release_done = true;
40 wake_up_interruptible(&priv->release_wq);
41 }
42
devm_put_device_action(void * ptr)43 static void devm_put_device_action(void *ptr)
44 {
45 struct test_priv *priv = ptr;
46
47 put_device(priv->dev);
48 priv->release_done = true;
49 wake_up_interruptible(&priv->release_wq);
50 }
51
52 #define RELEASE_TIMEOUT_MS 100
53
54 /*
55 * Tests that a platform bus, non-probed device will run its
56 * device-managed actions when unregistered.
57 */
platform_device_devm_register_unregister_test(struct kunit * test)58 static void platform_device_devm_register_unregister_test(struct kunit *test)
59 {
60 struct platform_device *pdev;
61 struct test_priv *priv = test->priv;
62 int ret;
63
64 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
65 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
66
67 ret = platform_device_add(pdev);
68 KUNIT_ASSERT_EQ(test, ret, 0);
69
70 priv->dev = &pdev->dev;
71
72 ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
73 KUNIT_ASSERT_EQ(test, ret, 0);
74
75 platform_device_unregister(pdev);
76
77 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
78 msecs_to_jiffies(RELEASE_TIMEOUT_MS));
79 KUNIT_EXPECT_GT(test, ret, 0);
80 }
81
82 /*
83 * Tests that a platform bus, non-probed device will run its
84 * device-managed actions when unregistered, even if someone still holds
85 * a reference to it.
86 */
platform_device_devm_register_get_unregister_with_devm_test(struct kunit * test)87 static void platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
88 {
89 struct platform_device *pdev;
90 struct test_priv *priv = test->priv;
91 int ret;
92
93 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
94 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
95
96 ret = platform_device_add(pdev);
97 KUNIT_ASSERT_EQ(test, ret, 0);
98
99 priv->dev = &pdev->dev;
100
101 get_device(priv->dev);
102
103 ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
104 KUNIT_ASSERT_EQ(test, ret, 0);
105
106 platform_device_unregister(pdev);
107
108 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
109 msecs_to_jiffies(RELEASE_TIMEOUT_MS));
110 KUNIT_EXPECT_GT(test, ret, 0);
111 }
112
fake_probe(struct platform_device * pdev)113 static int fake_probe(struct platform_device *pdev)
114 {
115 struct test_priv *priv = platform_get_drvdata(pdev);
116
117 priv->probe_done = true;
118 wake_up_interruptible(&priv->probe_wq);
119
120 return 0;
121 }
122
123 static struct platform_driver fake_driver = {
124 .probe = fake_probe,
125 .driver = {
126 .name = DEVICE_NAME,
127 },
128 };
129
130 /*
131 * Tests that a platform bus, probed device will run its device-managed
132 * actions when unregistered.
133 */
probed_platform_device_devm_register_unregister_test(struct kunit * test)134 static void probed_platform_device_devm_register_unregister_test(struct kunit *test)
135 {
136 struct platform_device *pdev;
137 struct test_priv *priv = test->priv;
138 int ret;
139
140 ret = platform_driver_register(&fake_driver);
141 KUNIT_ASSERT_EQ(test, ret, 0);
142
143 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
144 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
145
146 priv->dev = &pdev->dev;
147 platform_set_drvdata(pdev, priv);
148
149 ret = platform_device_add(pdev);
150 KUNIT_ASSERT_EQ(test, ret, 0);
151
152 ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
153 msecs_to_jiffies(RELEASE_TIMEOUT_MS));
154 KUNIT_ASSERT_GT(test, ret, 0);
155
156 ret = devm_add_action_or_reset(priv->dev, devm_device_action, priv);
157 KUNIT_ASSERT_EQ(test, ret, 0);
158
159 platform_device_unregister(pdev);
160
161 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
162 msecs_to_jiffies(RELEASE_TIMEOUT_MS));
163 KUNIT_EXPECT_GT(test, ret, 0);
164
165 platform_driver_unregister(&fake_driver);
166 }
167
168 /*
169 * Tests that a platform bus, probed device will run its device-managed
170 * actions when unregistered, even if someone still holds a reference to
171 * it.
172 */
probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit * test)173 static void probed_platform_device_devm_register_get_unregister_with_devm_test(struct kunit *test)
174 {
175 struct platform_device *pdev;
176 struct test_priv *priv = test->priv;
177 int ret;
178
179 ret = platform_driver_register(&fake_driver);
180 KUNIT_ASSERT_EQ(test, ret, 0);
181
182 pdev = platform_device_alloc(DEVICE_NAME, PLATFORM_DEVID_NONE);
183 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
184
185 priv->dev = &pdev->dev;
186 platform_set_drvdata(pdev, priv);
187
188 ret = platform_device_add(pdev);
189 KUNIT_ASSERT_EQ(test, ret, 0);
190
191 ret = wait_event_interruptible_timeout(priv->probe_wq, priv->probe_done,
192 msecs_to_jiffies(RELEASE_TIMEOUT_MS));
193 KUNIT_ASSERT_GT(test, ret, 0);
194
195 get_device(priv->dev);
196
197 ret = devm_add_action_or_reset(priv->dev, devm_put_device_action, priv);
198 KUNIT_ASSERT_EQ(test, ret, 0);
199
200 platform_device_unregister(pdev);
201
202 ret = wait_event_interruptible_timeout(priv->release_wq, priv->release_done,
203 msecs_to_jiffies(RELEASE_TIMEOUT_MS));
204 KUNIT_EXPECT_GT(test, ret, 0);
205
206 platform_driver_unregister(&fake_driver);
207 }
208
209 static struct kunit_case platform_device_devm_tests[] = {
210 KUNIT_CASE(platform_device_devm_register_unregister_test),
211 KUNIT_CASE(platform_device_devm_register_get_unregister_with_devm_test),
212 KUNIT_CASE(probed_platform_device_devm_register_unregister_test),
213 KUNIT_CASE(probed_platform_device_devm_register_get_unregister_with_devm_test),
214 {}
215 };
216
217 static struct kunit_suite platform_device_devm_test_suite = {
218 .name = "platform-device-devm",
219 .init = platform_device_devm_init,
220 .test_cases = platform_device_devm_tests,
221 };
222
platform_device_find_by_null_test(struct kunit * test)223 static void platform_device_find_by_null_test(struct kunit *test)
224 {
225 struct platform_device *pdev;
226 int ret;
227
228 pdev = kunit_platform_device_alloc(test, DEVICE_NAME, PLATFORM_DEVID_NONE);
229 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
230
231 ret = kunit_platform_device_add(test, pdev);
232 KUNIT_ASSERT_EQ(test, ret, 0);
233
234 KUNIT_EXPECT_PTR_EQ(test, of_find_device_by_node(NULL), NULL);
235
236 KUNIT_EXPECT_PTR_EQ(test, bus_find_device_by_of_node(&platform_bus_type, NULL), NULL);
237 KUNIT_EXPECT_PTR_EQ(test, bus_find_device_by_fwnode(&platform_bus_type, NULL), NULL);
238 KUNIT_EXPECT_PTR_EQ(test, bus_find_device_by_acpi_dev(&platform_bus_type, NULL), NULL);
239
240 KUNIT_EXPECT_FALSE(test, device_match_of_node(&pdev->dev, NULL));
241 KUNIT_EXPECT_FALSE(test, device_match_fwnode(&pdev->dev, NULL));
242 KUNIT_EXPECT_FALSE(test, device_match_acpi_dev(&pdev->dev, NULL));
243 KUNIT_EXPECT_FALSE(test, device_match_acpi_handle(&pdev->dev, NULL));
244 }
245
246 static struct kunit_case platform_device_match_tests[] = {
247 KUNIT_CASE(platform_device_find_by_null_test),
248 {}
249 };
250
251 static struct kunit_suite platform_device_match_test_suite = {
252 .name = "platform-device-match",
253 .test_cases = platform_device_match_tests,
254 };
255
256 kunit_test_suites(
257 &platform_device_devm_test_suite,
258 &platform_device_match_test_suite,
259 );
260
261 MODULE_DESCRIPTION("Test module for platform devices");
262 MODULE_AUTHOR("Maxime Ripard <[email protected]>");
263 MODULE_LICENSE("GPL");
264