projects/linux·blob master · refs

366 lines · 10.1 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Test managed platform driver
4 */
5
6#include <linux/completion.h>
7#include <linux/device/bus.h>
8#include <linux/device/driver.h>
9#include <linux/err.h>
10#include <linux/platform_device.h>
11
12#include <kunit/platform_device.h>
13#include <kunit/resource.h>
14
15struct kunit_platform_device_alloc_params {
16 const char *name;
17 int id;
18};
19
20static int kunit_platform_device_alloc_init(struct kunit_resource *res, void *context)
21{
22 struct kunit_platform_device_alloc_params *params = context;
23 struct platform_device *pdev;
24
25 pdev = platform_device_alloc(params->name, params->id);
26 if (!pdev)
27 return -ENOMEM;
28
29 res->data = pdev;
30
31 return 0;
32}
33
34static void kunit_platform_device_alloc_exit(struct kunit_resource *res)
35{
36 struct platform_device *pdev = res->data;
37
38 platform_device_put(pdev);
39}
40
41/**
42 * kunit_platform_device_alloc() - Allocate a KUnit test managed platform device
43 * @test: test context
44 * @name: device name of platform device to alloc
45 * @id: identifier of platform device to alloc.
46 *
47 * Allocate a test managed platform device. The device is put when the test completes.
48 *
49 * Return: Allocated platform device on success, NULL on failure.
50 */
51struct platform_device *
52kunit_platform_device_alloc(struct kunit *test, const char *name, int id)
53{
54 struct kunit_platform_device_alloc_params params = {
55 .name = name,
56 .id = id,
57 };
58
59 return kunit_alloc_resource(test,
60 kunit_platform_device_alloc_init,
61 kunit_platform_device_alloc_exit,
62 GFP_KERNEL, &params);
63}
64EXPORT_SYMBOL_GPL(kunit_platform_device_alloc);
65
66static void kunit_platform_device_add_exit(struct kunit_resource *res)
67{
68 struct platform_device *pdev = res->data;
69
70 platform_device_unregister(pdev);
71}
72
73static bool
74kunit_platform_device_alloc_match(struct kunit *test,
75 struct kunit_resource *res, void *match_data)
76{
77 struct platform_device *pdev = match_data;
78
79 return res->data == pdev && res->free == kunit_platform_device_alloc_exit;
80}
81
82KUNIT_DEFINE_ACTION_WRAPPER(platform_device_unregister_wrapper,
83 platform_device_unregister, struct platform_device *);
84/**
85 * kunit_platform_device_add() - Register a KUnit test managed platform device
86 * @test: test context
87 * @pdev: platform device to add
88 *
89 * Register a test managed platform device. The device is unregistered when the
90 * test completes.
91 *
92 * Return: 0 on success, negative errno on failure.
93 */
94int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev)
95{
96 struct kunit_resource *res;
97 int ret;
98
99 ret = platform_device_add(pdev);
100 if (ret)
101 return ret;
102
103 res = kunit_find_resource(test, kunit_platform_device_alloc_match, pdev);
104 if (res) {
105 /*
106 * Transfer the reference count of the platform device if it
107 * was allocated with kunit_platform_device_alloc(). In this
108 * case, calling platform_device_put() when the test exits from
109 * kunit_platform_device_alloc_exit() would lead to reference
110 * count underflow because platform_device_unregister_wrapper()
111 * calls platform_device_unregister() which also calls
112 * platform_device_put().
113 *
114 * Usually callers transfer the refcount initialized in
115 * platform_device_alloc() to platform_device_add() by calling
116 * platform_device_unregister() when platform_device_add()
117 * succeeds or platform_device_put() when it fails. KUnit has to
118 * keep this straight by redirecting the free routine for the
119 * resource to the right function. Luckily this only has to
120 * account for the success scenario.
121 */
122 res->free = kunit_platform_device_add_exit;
123 kunit_put_resource(res);
124 } else {
125 ret = kunit_add_action_or_reset(test, platform_device_unregister_wrapper, pdev);
126 if (ret)
127 return ret;
128 }
129
130 return 0;
131}
132EXPORT_SYMBOL_GPL(kunit_platform_device_add);
133
134/**
135 * kunit_platform_device_register_full() - Register a KUnit test-managed platform
136 * device described by platform device info
137 * @test: test context
138 * @pdevinfo: platform device information describing the new device
139 *
140 * Register a test-managed platform device. The device is unregistered when the
141 * test completes.
142 *
143 * Return: New platform device on success, IS_ERR() on error.
144 */
145struct platform_device *
146kunit_platform_device_register_full(struct kunit *test,
147 const struct platform_device_info *pdevinfo)
148{
149 struct platform_device *pdev;
150 int ret;
151
152 pdev = platform_device_register_full(pdevinfo);
153 if (IS_ERR(pdev))
154 return pdev;
155
156 ret = kunit_add_action_or_reset(test, platform_device_unregister_wrapper, pdev);
157 if (ret)
158 return ERR_PTR(ret);
159
160 return pdev;
161}
162EXPORT_SYMBOL_GPL(kunit_platform_device_register_full);
163
164static bool
165kunit_platform_device_add_match(struct kunit *test, struct kunit_resource *res,
166 void *match_data)
167{
168 struct platform_device *pdev = match_data;
169
170 return res->data == pdev && res->free == kunit_platform_device_add_exit;
171}
172
173/**
174 * kunit_platform_device_unregister() - Unregister a KUnit-managed platform device
175 * @test: test context
176 * @pdev: platform device to unregister
177 *
178 * Unregister a test-managed platform device and cancel its release action.
179 */
180void kunit_platform_device_unregister(struct kunit *test,
181 struct platform_device *pdev)
182{
183 struct kunit_resource *res;
184
185 res = kunit_find_resource(test, kunit_platform_device_add_match, pdev);
186 if (res) {
187 res->free = NULL;
188 kunit_put_resource(res);
189 } else {
190 kunit_remove_action(test, platform_device_unregister_wrapper, pdev);
191 }
192
193 platform_device_unregister(pdev);
194}
195EXPORT_SYMBOL_GPL(kunit_platform_device_unregister);
196
197struct kunit_platform_device_probe_nb {
198 struct completion *x;
199 struct device *dev;
200 struct notifier_block nb;
201};
202
203static int kunit_platform_device_probe_notify(struct notifier_block *nb,
204 unsigned long event, void *data)
205{
206 struct kunit_platform_device_probe_nb *knb;
207 struct device *dev = data;
208
209 knb = container_of(nb, struct kunit_platform_device_probe_nb, nb);
210 if (event != BUS_NOTIFY_BOUND_DRIVER || knb->dev != dev)
211 return NOTIFY_DONE;
212
213 complete(knb->x);
214
215 return NOTIFY_OK;
216}
217
218static void kunit_platform_device_probe_nb_remove(void *nb)
219{
220 bus_unregister_notifier(&platform_bus_type, nb);
221}
222
223/**
224 * kunit_platform_device_prepare_wait_for_probe() - Prepare a completion
225 * variable to wait for a platform device to probe
226 * @test: test context
227 * @pdev: platform device to prepare to wait for probe of
228 * @x: completion variable completed when @dev has probed
229 *
230 * Prepare a completion variable @x to wait for @pdev to probe. Waiting on the
231 * completion forces a preemption, allowing the platform driver to probe.
232 *
233 * Example
234 *
235 * .. code-block:: c
236 *
237 * static int kunit_platform_driver_probe(struct platform_device *pdev)
238 * {
239 * return 0;
240 * }
241 *
242 * static void kunit_platform_driver_test(struct kunit *test)
243 * {
244 * struct platform_device *pdev;
245 * struct platform_driver *pdrv;
246 * DECLARE_COMPLETION_ONSTACK(comp);
247 *
248 * pdev = kunit_platform_device_alloc(test, "kunit-platform", -1);
249 * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
250 * KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, pdev));
251 *
252 * pdrv = kunit_kzalloc(test, sizeof(*pdrv), GFP_KERNEL);
253 * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdrv);
254 *
255 * pdrv->probe = kunit_platform_driver_probe;
256 * pdrv->driver.name = "kunit-platform";
257 * pdrv->driver.owner = THIS_MODULE;
258 *
259 * KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_prepare_wait_for_probe(test, pdev, &comp));
260 * KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, pdrv));
261 *
262 * KUNIT_EXPECT_NE(test, 0, wait_for_completion_timeout(&comp, 3 * HZ));
263 * }
264 *
265 * Return: 0 on success, negative errno on failure.
266 */
267int kunit_platform_device_prepare_wait_for_probe(struct kunit *test,
268 struct platform_device *pdev,
269 struct completion *x)
270{
271 struct device *dev = &pdev->dev;
272 struct kunit_platform_device_probe_nb *knb;
273 bool bound;
274
275 knb = kunit_kzalloc(test, sizeof(*knb), GFP_KERNEL);
276 if (!knb)
277 return -ENOMEM;
278
279 knb->nb.notifier_call = kunit_platform_device_probe_notify;
280 knb->dev = dev;
281 knb->x = x;
282
283 device_lock(dev);
284 bound = device_is_bound(dev);
285 if (bound) {
286 device_unlock(dev);
287 complete(x);
288 kunit_kfree(test, knb);
289 return 0;
290 }
291
292 bus_register_notifier(&platform_bus_type, &knb->nb);
293 device_unlock(&pdev->dev);
294
295 return kunit_add_action_or_reset(test, kunit_platform_device_probe_nb_remove, &knb->nb);
296}
297EXPORT_SYMBOL_GPL(kunit_platform_device_prepare_wait_for_probe);
298
299KUNIT_DEFINE_ACTION_WRAPPER(platform_driver_unregister_wrapper,
300 platform_driver_unregister, struct platform_driver *);
301/**
302 * kunit_platform_driver_register() - Register a KUnit test managed platform driver
303 * @test: test context
304 * @drv: platform driver to register
305 *
306 * Register a test managed platform driver. This allows callers to embed the
307 * @drv in a container structure and use container_of() in the probe function
308 * to pass information to KUnit tests.
309 *
310 * Example
311 *
312 * .. code-block:: c
313 *
314 * struct kunit_test_context {
315 * struct platform_driver pdrv;
316 * const char *data;
317 * };
318 *
319 * static inline struct kunit_test_context *
320 * to_test_context(struct platform_device *pdev)
321 * {
322 * return container_of(to_platform_driver(pdev->dev.driver),
323 * struct kunit_test_context,
324 * pdrv);
325 * }
326 *
327 * static int kunit_platform_driver_probe(struct platform_device *pdev)
328 * {
329 * struct kunit_test_context *ctx;
330 *
331 * ctx = to_test_context(pdev);
332 * ctx->data = "test data";
333 *
334 * return 0;
335 * }
336 *
337 * static void kunit_platform_driver_test(struct kunit *test)
338 * {
339 * struct kunit_test_context *ctx;
340 *
341 * ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
342 * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
343 *
344 * ctx->pdrv.probe = kunit_platform_driver_probe;
345 * ctx->pdrv.driver.name = "kunit-platform";
346 * ctx->pdrv.driver.owner = THIS_MODULE;
347 *
348 * KUNIT_EXPECT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv));
349 * <... wait for driver to probe ...>
350 * KUNIT_EXPECT_STREQ(test, ctx->data, "test data");
351 * }
352 *
353 * Return: 0 on success, negative errno on failure.
354 */
355int kunit_platform_driver_register(struct kunit *test,
356 struct platform_driver *drv)
357{
358 int ret;
359
360 ret = platform_driver_register(drv);
361 if (ret)
362 return ret;
363
364 return kunit_add_action_or_reset(test, platform_driver_unregister_wrapper, drv);
365}
366EXPORT_SYMBOL_GPL(kunit_platform_driver_register);