]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2e7d35d2 SG |
2 | /* |
3 | * Tests for the core driver model code | |
4 | * | |
5 | * Copyright (c) 2013 Google, Inc | |
2e7d35d2 SG |
6 | */ |
7 | ||
8 | #include <common.h> | |
9 | #include <errno.h> | |
10 | #include <dm.h> | |
11 | #include <fdtdec.h> | |
f7ae49fc | 12 | #include <log.h> |
2e7d35d2 SG |
13 | #include <malloc.h> |
14 | #include <dm/device-internal.h> | |
15 | #include <dm/root.h> | |
2e7d35d2 SG |
16 | #include <dm/util.h> |
17 | #include <dm/test.h> | |
18 | #include <dm/uclass-internal.h> | |
e721b882 | 19 | #include <test/ut.h> |
2e7d35d2 SG |
20 | |
21 | DECLARE_GLOBAL_DATA_PTR; | |
22 | ||
23 | enum { | |
24 | TEST_INTVAL1 = 0, | |
25 | TEST_INTVAL2 = 3, | |
26 | TEST_INTVAL3 = 6, | |
27 | TEST_INTVAL_MANUAL = 101112, | |
00606d7e | 28 | TEST_INTVAL_PRE_RELOC = 7, |
2e7d35d2 SG |
29 | }; |
30 | ||
31 | static const struct dm_test_pdata test_pdata[] = { | |
32 | { .ping_add = TEST_INTVAL1, }, | |
33 | { .ping_add = TEST_INTVAL2, }, | |
34 | { .ping_add = TEST_INTVAL3, }, | |
35 | }; | |
36 | ||
37 | static const struct dm_test_pdata test_pdata_manual = { | |
38 | .ping_add = TEST_INTVAL_MANUAL, | |
39 | }; | |
40 | ||
00606d7e SG |
41 | static const struct dm_test_pdata test_pdata_pre_reloc = { |
42 | .ping_add = TEST_INTVAL_PRE_RELOC, | |
43 | }; | |
44 | ||
2e7d35d2 SG |
45 | U_BOOT_DEVICE(dm_test_info1) = { |
46 | .name = "test_drv", | |
47 | .platdata = &test_pdata[0], | |
48 | }; | |
49 | ||
50 | U_BOOT_DEVICE(dm_test_info2) = { | |
51 | .name = "test_drv", | |
52 | .platdata = &test_pdata[1], | |
53 | }; | |
54 | ||
55 | U_BOOT_DEVICE(dm_test_info3) = { | |
56 | .name = "test_drv", | |
57 | .platdata = &test_pdata[2], | |
58 | }; | |
59 | ||
60 | static struct driver_info driver_info_manual = { | |
61 | .name = "test_manual_drv", | |
62 | .platdata = &test_pdata_manual, | |
63 | }; | |
64 | ||
00606d7e SG |
65 | static struct driver_info driver_info_pre_reloc = { |
66 | .name = "test_pre_reloc_drv", | |
f09144a2 | 67 | .platdata = &test_pdata_pre_reloc, |
00606d7e SG |
68 | }; |
69 | ||
24f927c5 SR |
70 | static struct driver_info driver_info_act_dma = { |
71 | .name = "test_act_dma_drv", | |
72 | }; | |
73 | ||
e721b882 | 74 | void dm_leak_check_start(struct unit_test_state *uts) |
756ac0bb | 75 | { |
e721b882 JH |
76 | uts->start = mallinfo(); |
77 | if (!uts->start.uordblks) | |
756ac0bb SG |
78 | puts("Warning: Please add '#define DEBUG' to the top of common/dlmalloc.c\n"); |
79 | } | |
80 | ||
e721b882 | 81 | int dm_leak_check_end(struct unit_test_state *uts) |
756ac0bb SG |
82 | { |
83 | struct mallinfo end; | |
cbfc2ff9 | 84 | int id, diff; |
756ac0bb SG |
85 | |
86 | /* Don't delete the root class, since we started with that */ | |
87 | for (id = UCLASS_ROOT + 1; id < UCLASS_COUNT; id++) { | |
88 | struct uclass *uc; | |
89 | ||
90 | uc = uclass_find(id); | |
91 | if (!uc) | |
92 | continue; | |
93 | ut_assertok(uclass_destroy(uc)); | |
94 | } | |
95 | ||
96 | end = mallinfo(); | |
cbfc2ff9 SG |
97 | diff = end.uordblks - uts->start.uordblks; |
98 | if (diff > 0) | |
99 | printf("Leak: lost %#xd bytes\n", diff); | |
100 | else if (diff < 0) | |
101 | printf("Leak: gained %#xd bytes\n", -diff); | |
e721b882 | 102 | ut_asserteq(uts->start.uordblks, end.uordblks); |
756ac0bb SG |
103 | |
104 | return 0; | |
105 | } | |
106 | ||
2e7d35d2 | 107 | /* Test that binding with platdata occurs correctly */ |
e721b882 | 108 | static int dm_test_autobind(struct unit_test_state *uts) |
2e7d35d2 | 109 | { |
e721b882 | 110 | struct dm_test_state *dms = uts->priv; |
54c5d08a | 111 | struct udevice *dev; |
2e7d35d2 SG |
112 | |
113 | /* | |
114 | * We should have a single class (UCLASS_ROOT) and a single root | |
115 | * device with no children. | |
116 | */ | |
117 | ut_assert(dms->root); | |
118 | ut_asserteq(1, list_count_items(&gd->uclass_root)); | |
119 | ut_asserteq(0, list_count_items(&gd->dm_root->child_head)); | |
120 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]); | |
121 | ||
00606d7e | 122 | ut_assertok(dm_scan_platdata(false)); |
2e7d35d2 SG |
123 | |
124 | /* We should have our test class now at least, plus more children */ | |
125 | ut_assert(1 < list_count_items(&gd->uclass_root)); | |
126 | ut_assert(0 < list_count_items(&gd->dm_root->child_head)); | |
127 | ||
128 | /* Our 3 dm_test_infox children should be bound to the test uclass */ | |
129 | ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]); | |
130 | ||
131 | /* No devices should be probed */ | |
132 | list_for_each_entry(dev, &gd->dm_root->child_head, sibling_node) | |
133 | ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); | |
134 | ||
135 | /* Our test driver should have been bound 3 times */ | |
136 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND] == 3); | |
137 | ||
138 | return 0; | |
139 | } | |
140 | DM_TEST(dm_test_autobind, 0); | |
141 | ||
754e71e8 | 142 | /* Test that binding with uclass platdata allocation occurs correctly */ |
e721b882 | 143 | static int dm_test_autobind_uclass_pdata_alloc(struct unit_test_state *uts) |
754e71e8 PM |
144 | { |
145 | struct dm_test_perdev_uc_pdata *uc_pdata; | |
146 | struct udevice *dev; | |
147 | struct uclass *uc; | |
148 | ||
149 | ut_assertok(uclass_get(UCLASS_TEST, &uc)); | |
150 | ut_assert(uc); | |
151 | ||
152 | /** | |
153 | * Test if test uclass driver requires allocation for the uclass | |
154 | * platform data and then check the dev->uclass_platdata pointer. | |
155 | */ | |
156 | ut_assert(uc->uc_drv->per_device_platdata_auto_alloc_size); | |
157 | ||
158 | for (uclass_find_first_device(UCLASS_TEST, &dev); | |
159 | dev; | |
160 | uclass_find_next_device(&dev)) { | |
7208396b | 161 | ut_assert(dev); |
754e71e8 PM |
162 | |
163 | uc_pdata = dev_get_uclass_platdata(dev); | |
164 | ut_assert(uc_pdata); | |
165 | } | |
166 | ||
167 | return 0; | |
168 | } | |
169 | DM_TEST(dm_test_autobind_uclass_pdata_alloc, DM_TESTF_SCAN_PDATA); | |
170 | ||
171 | /* Test that binding with uclass platdata setting occurs correctly */ | |
e721b882 | 172 | static int dm_test_autobind_uclass_pdata_valid(struct unit_test_state *uts) |
754e71e8 PM |
173 | { |
174 | struct dm_test_perdev_uc_pdata *uc_pdata; | |
175 | struct udevice *dev; | |
176 | ||
177 | /** | |
178 | * In the test_postbind() method of test uclass driver, the uclass | |
179 | * platform data should be set to three test int values - test it. | |
180 | */ | |
181 | for (uclass_find_first_device(UCLASS_TEST, &dev); | |
182 | dev; | |
183 | uclass_find_next_device(&dev)) { | |
7208396b | 184 | ut_assert(dev); |
754e71e8 PM |
185 | |
186 | uc_pdata = dev_get_uclass_platdata(dev); | |
187 | ut_assert(uc_pdata); | |
188 | ut_assert(uc_pdata->intval1 == TEST_UC_PDATA_INTVAL1); | |
189 | ut_assert(uc_pdata->intval2 == TEST_UC_PDATA_INTVAL2); | |
190 | ut_assert(uc_pdata->intval3 == TEST_UC_PDATA_INTVAL3); | |
191 | } | |
192 | ||
193 | return 0; | |
194 | } | |
195 | DM_TEST(dm_test_autobind_uclass_pdata_valid, DM_TESTF_SCAN_PDATA); | |
196 | ||
2e7d35d2 | 197 | /* Test that autoprobe finds all the expected devices */ |
e721b882 | 198 | static int dm_test_autoprobe(struct unit_test_state *uts) |
2e7d35d2 | 199 | { |
e721b882 | 200 | struct dm_test_state *dms = uts->priv; |
2e7d35d2 | 201 | int expected_base_add; |
54c5d08a | 202 | struct udevice *dev; |
2e7d35d2 SG |
203 | struct uclass *uc; |
204 | int i; | |
205 | ||
206 | ut_assertok(uclass_get(UCLASS_TEST, &uc)); | |
207 | ut_assert(uc); | |
208 | ||
209 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); | |
02c07b37 | 210 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_PROBE]); |
2e7d35d2 SG |
211 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]); |
212 | ||
213 | /* The root device should not be activated until needed */ | |
7497812d | 214 | ut_assert(dms->root->flags & DM_FLAG_ACTIVATED); |
2e7d35d2 SG |
215 | |
216 | /* | |
217 | * We should be able to find the three test devices, and they should | |
218 | * all be activated as they are used (lazy activation, required by | |
219 | * U-Boot) | |
220 | */ | |
221 | for (i = 0; i < 3; i++) { | |
222 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
223 | ut_assert(dev); | |
224 | ut_assertf(!(dev->flags & DM_FLAG_ACTIVATED), | |
225 | "Driver %d/%s already activated", i, dev->name); | |
226 | ||
227 | /* This should activate it */ | |
228 | ut_assertok(uclass_get_device(UCLASS_TEST, i, &dev)); | |
229 | ut_assert(dev); | |
230 | ut_assert(dev->flags & DM_FLAG_ACTIVATED); | |
231 | ||
232 | /* Activating a device should activate the root device */ | |
233 | if (!i) | |
234 | ut_assert(dms->root->flags & DM_FLAG_ACTIVATED); | |
235 | } | |
236 | ||
02c07b37 SG |
237 | /* |
238 | * Our 3 dm_test_info children should be passed to pre_probe and | |
239 | * post_probe | |
240 | */ | |
2e7d35d2 | 241 | ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]); |
02c07b37 | 242 | ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_PRE_PROBE]); |
2e7d35d2 SG |
243 | |
244 | /* Also we can check the per-device data */ | |
245 | expected_base_add = 0; | |
246 | for (i = 0; i < 3; i++) { | |
247 | struct dm_test_uclass_perdev_priv *priv; | |
248 | struct dm_test_pdata *pdata; | |
249 | ||
250 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
251 | ut_assert(dev); | |
252 | ||
e564f054 | 253 | priv = dev_get_uclass_priv(dev); |
2e7d35d2 SG |
254 | ut_assert(priv); |
255 | ut_asserteq(expected_base_add, priv->base_add); | |
256 | ||
257 | pdata = dev->platdata; | |
258 | expected_base_add += pdata->ping_add; | |
259 | } | |
260 | ||
261 | return 0; | |
262 | } | |
263 | DM_TEST(dm_test_autoprobe, DM_TESTF_SCAN_PDATA); | |
264 | ||
265 | /* Check that we see the correct platdata in each device */ | |
e721b882 | 266 | static int dm_test_platdata(struct unit_test_state *uts) |
2e7d35d2 SG |
267 | { |
268 | const struct dm_test_pdata *pdata; | |
54c5d08a | 269 | struct udevice *dev; |
2e7d35d2 SG |
270 | int i; |
271 | ||
272 | for (i = 0; i < 3; i++) { | |
273 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
274 | ut_assert(dev); | |
275 | pdata = dev->platdata; | |
276 | ut_assert(pdata->ping_add == test_pdata[i].ping_add); | |
277 | } | |
278 | ||
279 | return 0; | |
280 | } | |
281 | DM_TEST(dm_test_platdata, DM_TESTF_SCAN_PDATA); | |
282 | ||
283 | /* Test that we can bind, probe, remove, unbind a driver */ | |
e721b882 | 284 | static int dm_test_lifecycle(struct unit_test_state *uts) |
2e7d35d2 | 285 | { |
e721b882 | 286 | struct dm_test_state *dms = uts->priv; |
2e7d35d2 | 287 | int op_count[DM_TEST_OP_COUNT]; |
54c5d08a | 288 | struct udevice *dev, *test_dev; |
2e7d35d2 SG |
289 | int pingret; |
290 | int ret; | |
291 | ||
292 | memcpy(op_count, dm_testdrv_op_count, sizeof(op_count)); | |
293 | ||
00606d7e | 294 | ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, |
2e7d35d2 SG |
295 | &dev)); |
296 | ut_assert(dev); | |
297 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND] | |
298 | == op_count[DM_TEST_OP_BIND] + 1); | |
299 | ut_assert(!dev->priv); | |
300 | ||
301 | /* Probe the device - it should fail allocating private data */ | |
302 | dms->force_fail_alloc = 1; | |
303 | ret = device_probe(dev); | |
304 | ut_assert(ret == -ENOMEM); | |
305 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] | |
306 | == op_count[DM_TEST_OP_PROBE] + 1); | |
307 | ut_assert(!dev->priv); | |
308 | ||
309 | /* Try again without the alloc failure */ | |
310 | dms->force_fail_alloc = 0; | |
311 | ut_assertok(device_probe(dev)); | |
312 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] | |
313 | == op_count[DM_TEST_OP_PROBE] + 2); | |
314 | ut_assert(dev->priv); | |
315 | ||
316 | /* This should be device 3 in the uclass */ | |
317 | ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); | |
318 | ut_assert(dev == test_dev); | |
319 | ||
320 | /* Try ping */ | |
321 | ut_assertok(test_ping(dev, 100, &pingret)); | |
322 | ut_assert(pingret == 102); | |
323 | ||
324 | /* Now remove device 3 */ | |
325 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]); | |
706865af | 326 | ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); |
2e7d35d2 SG |
327 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]); |
328 | ||
329 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
330 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]); | |
331 | ut_assertok(device_unbind(dev)); | |
332 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
333 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]); | |
334 | ||
335 | return 0; | |
336 | } | |
337 | DM_TEST(dm_test_lifecycle, DM_TESTF_SCAN_PDATA | DM_TESTF_PROBE_TEST); | |
338 | ||
339 | /* Test that we can bind/unbind and the lists update correctly */ | |
e721b882 | 340 | static int dm_test_ordering(struct unit_test_state *uts) |
2e7d35d2 | 341 | { |
e721b882 | 342 | struct dm_test_state *dms = uts->priv; |
54c5d08a | 343 | struct udevice *dev, *dev_penultimate, *dev_last, *test_dev; |
2e7d35d2 SG |
344 | int pingret; |
345 | ||
00606d7e | 346 | ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, |
2e7d35d2 SG |
347 | &dev)); |
348 | ut_assert(dev); | |
349 | ||
350 | /* Bind two new devices (numbers 4 and 5) */ | |
00606d7e | 351 | ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, |
2e7d35d2 SG |
352 | &dev_penultimate)); |
353 | ut_assert(dev_penultimate); | |
00606d7e | 354 | ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, |
2e7d35d2 SG |
355 | &dev_last)); |
356 | ut_assert(dev_last); | |
357 | ||
358 | /* Now remove device 3 */ | |
706865af | 359 | ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); |
2e7d35d2 SG |
360 | ut_assertok(device_unbind(dev)); |
361 | ||
362 | /* The device numbering should have shifted down one */ | |
363 | ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); | |
364 | ut_assert(dev_penultimate == test_dev); | |
365 | ut_assertok(uclass_find_device(UCLASS_TEST, 4, &test_dev)); | |
366 | ut_assert(dev_last == test_dev); | |
367 | ||
368 | /* Add back the original device 3, now in position 5 */ | |
00606d7e SG |
369 | ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, |
370 | &dev)); | |
2e7d35d2 SG |
371 | ut_assert(dev); |
372 | ||
373 | /* Try ping */ | |
374 | ut_assertok(test_ping(dev, 100, &pingret)); | |
375 | ut_assert(pingret == 102); | |
376 | ||
377 | /* Remove 3 and 4 */ | |
706865af | 378 | ut_assertok(device_remove(dev_penultimate, DM_REMOVE_NORMAL)); |
2e7d35d2 | 379 | ut_assertok(device_unbind(dev_penultimate)); |
706865af | 380 | ut_assertok(device_remove(dev_last, DM_REMOVE_NORMAL)); |
2e7d35d2 SG |
381 | ut_assertok(device_unbind(dev_last)); |
382 | ||
383 | /* Our device should now be in position 3 */ | |
384 | ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); | |
385 | ut_assert(dev == test_dev); | |
386 | ||
387 | /* Now remove device 3 */ | |
706865af | 388 | ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); |
2e7d35d2 SG |
389 | ut_assertok(device_unbind(dev)); |
390 | ||
391 | return 0; | |
392 | } | |
393 | DM_TEST(dm_test_ordering, DM_TESTF_SCAN_PDATA); | |
394 | ||
395 | /* Check that we can perform operations on a device (do a ping) */ | |
e721b882 | 396 | int dm_check_operations(struct unit_test_state *uts, struct udevice *dev, |
2e7d35d2 SG |
397 | uint32_t base, struct dm_test_priv *priv) |
398 | { | |
399 | int expected; | |
400 | int pingret; | |
401 | ||
402 | /* Getting the child device should allocate platdata / priv */ | |
403 | ut_assertok(testfdt_ping(dev, 10, &pingret)); | |
404 | ut_assert(dev->priv); | |
405 | ut_assert(dev->platdata); | |
406 | ||
407 | expected = 10 + base; | |
408 | ut_asserteq(expected, pingret); | |
409 | ||
410 | /* Do another ping */ | |
411 | ut_assertok(testfdt_ping(dev, 20, &pingret)); | |
412 | expected = 20 + base; | |
413 | ut_asserteq(expected, pingret); | |
414 | ||
415 | /* Now check the ping_total */ | |
416 | priv = dev->priv; | |
417 | ut_asserteq(DM_TEST_START_TOTAL + 10 + 20 + base * 2, | |
418 | priv->ping_total); | |
419 | ||
420 | return 0; | |
421 | } | |
422 | ||
423 | /* Check that we can perform operations on devices */ | |
e721b882 | 424 | static int dm_test_operations(struct unit_test_state *uts) |
2e7d35d2 | 425 | { |
54c5d08a | 426 | struct udevice *dev; |
2e7d35d2 SG |
427 | int i; |
428 | ||
429 | /* | |
430 | * Now check that the ping adds are what we expect. This is using the | |
431 | * ping-add property in each node. | |
432 | */ | |
433 | for (i = 0; i < ARRAY_SIZE(test_pdata); i++) { | |
434 | uint32_t base; | |
435 | ||
436 | ut_assertok(uclass_get_device(UCLASS_TEST, i, &dev)); | |
437 | ||
438 | /* | |
439 | * Get the 'reg' property, which tells us what the ping add | |
440 | * should be. We don't use the platdata because we want | |
441 | * to test the code that sets that up (testfdt_drv_probe()). | |
442 | */ | |
443 | base = test_pdata[i].ping_add; | |
444 | debug("dev=%d, base=%d\n", i, base); | |
445 | ||
e721b882 | 446 | ut_assert(!dm_check_operations(uts, dev, base, dev->priv)); |
2e7d35d2 SG |
447 | } |
448 | ||
449 | return 0; | |
450 | } | |
451 | DM_TEST(dm_test_operations, DM_TESTF_SCAN_PDATA); | |
452 | ||
453 | /* Remove all drivers and check that things work */ | |
e721b882 | 454 | static int dm_test_remove(struct unit_test_state *uts) |
2e7d35d2 | 455 | { |
54c5d08a | 456 | struct udevice *dev; |
2e7d35d2 SG |
457 | int i; |
458 | ||
459 | for (i = 0; i < 3; i++) { | |
460 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
461 | ut_assert(dev); | |
462 | ut_assertf(dev->flags & DM_FLAG_ACTIVATED, | |
463 | "Driver %d/%s not activated", i, dev->name); | |
706865af | 464 | ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); |
2e7d35d2 SG |
465 | ut_assertf(!(dev->flags & DM_FLAG_ACTIVATED), |
466 | "Driver %d/%s should have deactivated", i, | |
467 | dev->name); | |
468 | ut_assert(!dev->priv); | |
469 | } | |
470 | ||
471 | return 0; | |
472 | } | |
473 | DM_TEST(dm_test_remove, DM_TESTF_SCAN_PDATA | DM_TESTF_PROBE_TEST); | |
474 | ||
475 | /* Remove and recreate everything, check for memory leaks */ | |
e721b882 | 476 | static int dm_test_leak(struct unit_test_state *uts) |
2e7d35d2 SG |
477 | { |
478 | int i; | |
479 | ||
480 | for (i = 0; i < 2; i++) { | |
54c5d08a | 481 | struct udevice *dev; |
2e7d35d2 SG |
482 | int ret; |
483 | int id; | |
484 | ||
e721b882 | 485 | dm_leak_check_start(uts); |
2e7d35d2 | 486 | |
00606d7e SG |
487 | ut_assertok(dm_scan_platdata(false)); |
488 | ut_assertok(dm_scan_fdt(gd->fdt_blob, false)); | |
2e7d35d2 SG |
489 | |
490 | /* Scanning the uclass is enough to probe all the devices */ | |
491 | for (id = UCLASS_ROOT; id < UCLASS_COUNT; id++) { | |
492 | for (ret = uclass_first_device(UCLASS_TEST, &dev); | |
493 | dev; | |
494 | ret = uclass_next_device(&dev)) | |
495 | ; | |
496 | ut_assertok(ret); | |
497 | } | |
498 | ||
e721b882 | 499 | ut_assertok(dm_leak_check_end(uts)); |
2e7d35d2 SG |
500 | } |
501 | ||
502 | return 0; | |
503 | } | |
504 | DM_TEST(dm_test_leak, 0); | |
505 | ||
506 | /* Test uclass init/destroy methods */ | |
e721b882 | 507 | static int dm_test_uclass(struct unit_test_state *uts) |
2e7d35d2 SG |
508 | { |
509 | struct uclass *uc; | |
510 | ||
511 | ut_assertok(uclass_get(UCLASS_TEST, &uc)); | |
512 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); | |
513 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_DESTROY]); | |
514 | ut_assert(uc->priv); | |
515 | ||
516 | ut_assertok(uclass_destroy(uc)); | |
517 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); | |
518 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_DESTROY]); | |
519 | ||
520 | return 0; | |
521 | } | |
522 | DM_TEST(dm_test_uclass, 0); | |
523 | ||
524 | /** | |
525 | * create_children() - Create children of a parent node | |
526 | * | |
527 | * @dms: Test system state | |
528 | * @parent: Parent device | |
529 | * @count: Number of children to create | |
530 | * @key: Key value to put in first child. Subsequence children | |
531 | * receive an incrementing value | |
532 | * @child: If not NULL, then the child device pointers are written into | |
533 | * this array. | |
534 | * @return 0 if OK, -ve on error | |
535 | */ | |
e721b882 | 536 | static int create_children(struct unit_test_state *uts, struct udevice *parent, |
54c5d08a | 537 | int count, int key, struct udevice *child[]) |
2e7d35d2 | 538 | { |
54c5d08a | 539 | struct udevice *dev; |
2e7d35d2 SG |
540 | int i; |
541 | ||
542 | for (i = 0; i < count; i++) { | |
543 | struct dm_test_pdata *pdata; | |
544 | ||
00606d7e SG |
545 | ut_assertok(device_bind_by_name(parent, false, |
546 | &driver_info_manual, &dev)); | |
2e7d35d2 SG |
547 | pdata = calloc(1, sizeof(*pdata)); |
548 | pdata->ping_add = key + i; | |
549 | dev->platdata = pdata; | |
550 | if (child) | |
551 | child[i] = dev; | |
552 | } | |
553 | ||
554 | return 0; | |
555 | } | |
556 | ||
557 | #define NODE_COUNT 10 | |
558 | ||
e721b882 | 559 | static int dm_test_children(struct unit_test_state *uts) |
2e7d35d2 | 560 | { |
e721b882 | 561 | struct dm_test_state *dms = uts->priv; |
54c5d08a HS |
562 | struct udevice *top[NODE_COUNT]; |
563 | struct udevice *child[NODE_COUNT]; | |
564 | struct udevice *grandchild[NODE_COUNT]; | |
565 | struct udevice *dev; | |
2e7d35d2 SG |
566 | int total; |
567 | int ret; | |
568 | int i; | |
569 | ||
570 | /* We don't care about the numbering for this test */ | |
571 | dms->skip_post_probe = 1; | |
572 | ||
573 | ut_assert(NODE_COUNT > 5); | |
574 | ||
575 | /* First create 10 top-level children */ | |
e721b882 | 576 | ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top)); |
2e7d35d2 SG |
577 | |
578 | /* Now a few have their own children */ | |
e721b882 JH |
579 | ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL)); |
580 | ut_assertok(create_children(uts, top[5], NODE_COUNT, 5, child)); | |
2e7d35d2 SG |
581 | |
582 | /* And grandchildren */ | |
583 | for (i = 0; i < NODE_COUNT; i++) | |
e721b882 | 584 | ut_assertok(create_children(uts, child[i], NODE_COUNT, 50 * i, |
2e7d35d2 SG |
585 | i == 2 ? grandchild : NULL)); |
586 | ||
587 | /* Check total number of devices */ | |
588 | total = NODE_COUNT * (3 + NODE_COUNT); | |
589 | ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_BIND]); | |
590 | ||
591 | /* Try probing one of the grandchildren */ | |
592 | ut_assertok(uclass_get_device(UCLASS_TEST, | |
593 | NODE_COUNT * 3 + 2 * NODE_COUNT, &dev)); | |
594 | ut_asserteq_ptr(grandchild[0], dev); | |
595 | ||
596 | /* | |
597 | * This should have probed the child and top node also, for a total | |
598 | * of 3 nodes. | |
599 | */ | |
600 | ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_PROBE]); | |
601 | ||
602 | /* Probe the other grandchildren */ | |
603 | for (i = 1; i < NODE_COUNT; i++) | |
604 | ut_assertok(device_probe(grandchild[i])); | |
605 | ||
606 | ut_asserteq(2 + NODE_COUNT, dm_testdrv_op_count[DM_TEST_OP_PROBE]); | |
607 | ||
608 | /* Probe everything */ | |
609 | for (ret = uclass_first_device(UCLASS_TEST, &dev); | |
610 | dev; | |
611 | ret = uclass_next_device(&dev)) | |
612 | ; | |
613 | ut_assertok(ret); | |
614 | ||
615 | ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_PROBE]); | |
616 | ||
617 | /* Remove a top-level child and check that the children are removed */ | |
706865af | 618 | ut_assertok(device_remove(top[2], DM_REMOVE_NORMAL)); |
2e7d35d2 SG |
619 | ut_asserteq(NODE_COUNT + 1, dm_testdrv_op_count[DM_TEST_OP_REMOVE]); |
620 | dm_testdrv_op_count[DM_TEST_OP_REMOVE] = 0; | |
621 | ||
622 | /* Try one with grandchildren */ | |
623 | ut_assertok(uclass_get_device(UCLASS_TEST, 5, &dev)); | |
624 | ut_asserteq_ptr(dev, top[5]); | |
706865af | 625 | ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); |
2e7d35d2 SG |
626 | ut_asserteq(1 + NODE_COUNT * (1 + NODE_COUNT), |
627 | dm_testdrv_op_count[DM_TEST_OP_REMOVE]); | |
628 | ||
629 | /* Try the same with unbind */ | |
630 | ut_assertok(device_unbind(top[2])); | |
631 | ut_asserteq(NODE_COUNT + 1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
632 | dm_testdrv_op_count[DM_TEST_OP_UNBIND] = 0; | |
633 | ||
634 | /* Try one with grandchildren */ | |
635 | ut_assertok(uclass_get_device(UCLASS_TEST, 5, &dev)); | |
636 | ut_asserteq_ptr(dev, top[6]); | |
637 | ut_assertok(device_unbind(top[5])); | |
638 | ut_asserteq(1 + NODE_COUNT * (1 + NODE_COUNT), | |
639 | dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
640 | ||
641 | return 0; | |
642 | } | |
643 | DM_TEST(dm_test_children, 0); | |
00606d7e SG |
644 | |
645 | /* Test that pre-relocation devices work as expected */ | |
e721b882 | 646 | static int dm_test_pre_reloc(struct unit_test_state *uts) |
00606d7e | 647 | { |
e721b882 | 648 | struct dm_test_state *dms = uts->priv; |
00606d7e SG |
649 | struct udevice *dev; |
650 | ||
651 | /* The normal driver should refuse to bind before relocation */ | |
652 | ut_asserteq(-EPERM, device_bind_by_name(dms->root, true, | |
653 | &driver_info_manual, &dev)); | |
654 | ||
655 | /* But this one is marked pre-reloc */ | |
656 | ut_assertok(device_bind_by_name(dms->root, true, | |
657 | &driver_info_pre_reloc, &dev)); | |
658 | ||
659 | return 0; | |
660 | } | |
661 | DM_TEST(dm_test_pre_reloc, 0); | |
c910e2e2 | 662 | |
24f927c5 SR |
663 | /* |
664 | * Test that removal of devices, either via the "normal" device_remove() | |
665 | * API or via the device driver selective flag works as expected | |
666 | */ | |
667 | static int dm_test_remove_active_dma(struct unit_test_state *uts) | |
668 | { | |
669 | struct dm_test_state *dms = uts->priv; | |
670 | struct udevice *dev; | |
671 | ||
672 | ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma, | |
673 | &dev)); | |
674 | ut_assert(dev); | |
675 | ||
676 | /* Probe the device */ | |
677 | ut_assertok(device_probe(dev)); | |
678 | ||
679 | /* Test if device is active right now */ | |
680 | ut_asserteq(true, device_active(dev)); | |
681 | ||
682 | /* Remove the device via selective remove flag */ | |
683 | dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); | |
684 | ||
685 | /* Test if device is inactive right now */ | |
686 | ut_asserteq(false, device_active(dev)); | |
687 | ||
688 | /* Probe the device again */ | |
689 | ut_assertok(device_probe(dev)); | |
690 | ||
691 | /* Test if device is active right now */ | |
692 | ut_asserteq(true, device_active(dev)); | |
693 | ||
694 | /* Remove the device via "normal" remove API */ | |
695 | ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); | |
696 | ||
697 | /* Test if device is inactive right now */ | |
698 | ut_asserteq(false, device_active(dev)); | |
699 | ||
700 | /* | |
701 | * Test if a device without the active DMA flags is not removed upon | |
702 | * the active DMA remove call | |
703 | */ | |
704 | ut_assertok(device_unbind(dev)); | |
705 | ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual, | |
706 | &dev)); | |
707 | ut_assert(dev); | |
708 | ||
709 | /* Probe the device */ | |
710 | ut_assertok(device_probe(dev)); | |
711 | ||
712 | /* Test if device is active right now */ | |
713 | ut_asserteq(true, device_active(dev)); | |
714 | ||
715 | /* Remove the device via selective remove flag */ | |
716 | dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); | |
717 | ||
718 | /* Test if device is still active right now */ | |
719 | ut_asserteq(true, device_active(dev)); | |
720 | ||
721 | return 0; | |
722 | } | |
723 | DM_TEST(dm_test_remove_active_dma, 0); | |
724 | ||
e721b882 | 725 | static int dm_test_uclass_before_ready(struct unit_test_state *uts) |
c910e2e2 SG |
726 | { |
727 | struct uclass *uc; | |
728 | ||
729 | ut_assertok(uclass_get(UCLASS_TEST, &uc)); | |
730 | ||
f9fd4558 SG |
731 | gd->dm_root = NULL; |
732 | gd->dm_root_f = NULL; | |
733 | memset(&gd->uclass_root, '\0', sizeof(gd->uclass_root)); | |
734 | ||
c910e2e2 SG |
735 | ut_asserteq_ptr(NULL, uclass_find(UCLASS_TEST)); |
736 | ||
737 | return 0; | |
738 | } | |
c910e2e2 | 739 | DM_TEST(dm_test_uclass_before_ready, 0); |
b3670531 | 740 | |
e721b882 | 741 | static int dm_test_uclass_devices_find(struct unit_test_state *uts) |
9e85f13d PM |
742 | { |
743 | struct udevice *dev; | |
744 | int ret; | |
745 | ||
746 | for (ret = uclass_find_first_device(UCLASS_TEST, &dev); | |
747 | dev; | |
748 | ret = uclass_find_next_device(&dev)) { | |
749 | ut_assert(!ret); | |
7208396b | 750 | ut_assert(dev); |
9e85f13d PM |
751 | } |
752 | ||
4805a7af | 753 | ut_assertok(uclass_find_first_device(UCLASS_TEST_DUMMY, &dev)); |
7208396b | 754 | ut_assert(!dev); |
f3885649 | 755 | |
9e85f13d PM |
756 | return 0; |
757 | } | |
758 | DM_TEST(dm_test_uclass_devices_find, DM_TESTF_SCAN_PDATA); | |
759 | ||
e721b882 | 760 | static int dm_test_uclass_devices_find_by_name(struct unit_test_state *uts) |
6e0c4880 PM |
761 | { |
762 | struct udevice *finddev; | |
763 | struct udevice *testdev; | |
764 | int findret, ret; | |
765 | ||
766 | /* | |
767 | * For each test device found in fdt like: "a-test", "b-test", etc., | |
768 | * use its name and try to find it by uclass_find_device_by_name(). | |
769 | * Then, on success check if: | |
770 | * - current 'testdev' name is equal to the returned 'finddev' name | |
771 | * - current 'testdev' pointer is equal to the returned 'finddev' | |
772 | * | |
773 | * We assume that, each uclass's device name is unique, so if not, then | |
774 | * this will fail on checking condition: testdev == finddev, since the | |
775 | * uclass_find_device_by_name(), returns the first device by given name. | |
776 | */ | |
777 | for (ret = uclass_find_first_device(UCLASS_TEST_FDT, &testdev); | |
778 | testdev; | |
779 | ret = uclass_find_next_device(&testdev)) { | |
780 | ut_assertok(ret); | |
7208396b | 781 | ut_assert(testdev); |
6e0c4880 PM |
782 | |
783 | findret = uclass_find_device_by_name(UCLASS_TEST_FDT, | |
784 | testdev->name, | |
785 | &finddev); | |
786 | ||
787 | ut_assertok(findret); | |
788 | ut_assert(testdev); | |
789 | ut_asserteq_str(testdev->name, finddev->name); | |
790 | ut_asserteq_ptr(testdev, finddev); | |
791 | } | |
792 | ||
793 | return 0; | |
794 | } | |
795 | DM_TEST(dm_test_uclass_devices_find_by_name, DM_TESTF_SCAN_FDT); | |
796 | ||
e721b882 | 797 | static int dm_test_uclass_devices_get(struct unit_test_state *uts) |
9e85f13d PM |
798 | { |
799 | struct udevice *dev; | |
800 | int ret; | |
801 | ||
802 | for (ret = uclass_first_device(UCLASS_TEST, &dev); | |
803 | dev; | |
804 | ret = uclass_next_device(&dev)) { | |
805 | ut_assert(!ret); | |
806 | ut_assert(dev); | |
807 | ut_assert(device_active(dev)); | |
808 | } | |
809 | ||
810 | return 0; | |
811 | } | |
812 | DM_TEST(dm_test_uclass_devices_get, DM_TESTF_SCAN_PDATA); | |
813 | ||
e721b882 | 814 | static int dm_test_uclass_devices_get_by_name(struct unit_test_state *uts) |
6e0c4880 PM |
815 | { |
816 | struct udevice *finddev; | |
817 | struct udevice *testdev; | |
818 | int ret, findret; | |
819 | ||
820 | /* | |
821 | * For each test device found in fdt like: "a-test", "b-test", etc., | |
822 | * use its name and try to get it by uclass_get_device_by_name(). | |
823 | * On success check if: | |
824 | * - returned finddev' is active | |
825 | * - current 'testdev' name is equal to the returned 'finddev' name | |
826 | * - current 'testdev' pointer is equal to the returned 'finddev' | |
827 | * | |
828 | * We asserts that the 'testdev' is active on each loop entry, so we | |
829 | * could be sure that the 'finddev' is activated too, but for sure | |
830 | * we check it again. | |
831 | * | |
832 | * We assume that, each uclass's device name is unique, so if not, then | |
833 | * this will fail on checking condition: testdev == finddev, since the | |
834 | * uclass_get_device_by_name(), returns the first device by given name. | |
835 | */ | |
836 | for (ret = uclass_first_device(UCLASS_TEST_FDT, &testdev); | |
837 | testdev; | |
838 | ret = uclass_next_device(&testdev)) { | |
839 | ut_assertok(ret); | |
840 | ut_assert(testdev); | |
841 | ut_assert(device_active(testdev)); | |
842 | ||
843 | findret = uclass_get_device_by_name(UCLASS_TEST_FDT, | |
844 | testdev->name, | |
845 | &finddev); | |
846 | ||
847 | ut_assertok(findret); | |
848 | ut_assert(finddev); | |
849 | ut_assert(device_active(finddev)); | |
850 | ut_asserteq_str(testdev->name, finddev->name); | |
851 | ut_asserteq_ptr(testdev, finddev); | |
852 | } | |
853 | ||
854 | return 0; | |
855 | } | |
856 | DM_TEST(dm_test_uclass_devices_get_by_name, DM_TESTF_SCAN_FDT); | |
857 | ||
e721b882 | 858 | static int dm_test_device_get_uclass_id(struct unit_test_state *uts) |
b3670531 SG |
859 | { |
860 | struct udevice *dev; | |
861 | ||
862 | ut_assertok(uclass_get_device(UCLASS_TEST, 0, &dev)); | |
863 | ut_asserteq(UCLASS_TEST, device_get_uclass_id(dev)); | |
864 | ||
865 | return 0; | |
866 | } | |
867 | DM_TEST(dm_test_device_get_uclass_id, DM_TESTF_SCAN_PDATA); | |
6e43d1b1 SG |
868 | |
869 | static int dm_test_uclass_names(struct unit_test_state *uts) | |
870 | { | |
871 | ut_asserteq_str("test", uclass_get_name(UCLASS_TEST)); | |
872 | ut_asserteq(UCLASS_TEST, uclass_get_by_name("test")); | |
873 | ||
874 | return 0; | |
875 | } | |
876 | DM_TEST(dm_test_uclass_names, DM_TESTF_SCAN_PDATA); | |
cdb6aa0a SG |
877 | |
878 | static int dm_test_inactive_child(struct unit_test_state *uts) | |
879 | { | |
880 | struct dm_test_state *dms = uts->priv; | |
881 | struct udevice *parent, *dev1, *dev2; | |
882 | ||
883 | /* Skip the behaviour in test_post_probe() */ | |
884 | dms->skip_post_probe = 1; | |
885 | ||
886 | ut_assertok(uclass_first_device_err(UCLASS_TEST, &parent)); | |
887 | ||
888 | /* | |
889 | * Create a child but do not activate it. Calling the function again | |
890 | * should return the same child. | |
891 | */ | |
892 | ut_asserteq(-ENODEV, device_find_first_inactive_child(parent, | |
893 | UCLASS_TEST, &dev1)); | |
894 | ut_assertok(device_bind_ofnode(parent, DM_GET_DRIVER(test_drv), | |
895 | "test_child", 0, ofnode_null(), &dev1)); | |
896 | ||
897 | ut_assertok(device_find_first_inactive_child(parent, UCLASS_TEST, | |
898 | &dev2)); | |
899 | ut_asserteq_ptr(dev1, dev2); | |
900 | ||
901 | ut_assertok(device_probe(dev1)); | |
902 | ut_asserteq(-ENODEV, device_find_first_inactive_child(parent, | |
903 | UCLASS_TEST, &dev2)); | |
904 | ||
905 | return 0; | |
906 | } | |
907 | DM_TEST(dm_test_inactive_child, DM_TESTF_SCAN_PDATA); |