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