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
13struct 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
21static int platform_device_devm_init(struct kunit *test)
22{
23 struct test_priv *priv;
24
25 priv = kunit_kzalloc(test, size: 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
35static 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
43static void devm_put_device_action(void *ptr)
44{
45 struct test_priv *priv = ptr;
46
47 put_device(dev: 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 */
58static 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 */
87static 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(dev: 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
113static 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
123static 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 */
134static 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, data: 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 */
173static 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, data: 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(dev: 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
209static 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
217static 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
223static 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
246static struct kunit_case platform_device_match_tests[] = {
247 KUNIT_CASE(platform_device_find_by_null_test),
248 {}
249};
250
251static struct kunit_suite platform_device_match_test_suite = {
252 .name = "platform-device-match",
253 .test_cases = platform_device_match_tests,
254};
255
256kunit_test_suites(
257 &platform_device_devm_test_suite,
258 &platform_device_match_test_suite,
259);
260
261MODULE_DESCRIPTION("Test module for platform devices");
262MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
263MODULE_LICENSE("GPL");
264

source code of linux/drivers/base/test/platform-device-test.c