]>
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> | |
16 | #include <dm/ut.h> | |
17 | #include <dm/util.h> | |
18 | #include <dm/test.h> | |
19 | #include <dm/uclass-internal.h> | |
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, | |
28 | }; | |
29 | ||
30 | static const struct dm_test_pdata test_pdata[] = { | |
31 | { .ping_add = TEST_INTVAL1, }, | |
32 | { .ping_add = TEST_INTVAL2, }, | |
33 | { .ping_add = TEST_INTVAL3, }, | |
34 | }; | |
35 | ||
36 | static const struct dm_test_pdata test_pdata_manual = { | |
37 | .ping_add = TEST_INTVAL_MANUAL, | |
38 | }; | |
39 | ||
40 | U_BOOT_DEVICE(dm_test_info1) = { | |
41 | .name = "test_drv", | |
42 | .platdata = &test_pdata[0], | |
43 | }; | |
44 | ||
45 | U_BOOT_DEVICE(dm_test_info2) = { | |
46 | .name = "test_drv", | |
47 | .platdata = &test_pdata[1], | |
48 | }; | |
49 | ||
50 | U_BOOT_DEVICE(dm_test_info3) = { | |
51 | .name = "test_drv", | |
52 | .platdata = &test_pdata[2], | |
53 | }; | |
54 | ||
55 | static struct driver_info driver_info_manual = { | |
56 | .name = "test_manual_drv", | |
57 | .platdata = &test_pdata_manual, | |
58 | }; | |
59 | ||
60 | /* Test that binding with platdata occurs correctly */ | |
61 | static int dm_test_autobind(struct dm_test_state *dms) | |
62 | { | |
54c5d08a | 63 | struct udevice *dev; |
2e7d35d2 SG |
64 | |
65 | /* | |
66 | * We should have a single class (UCLASS_ROOT) and a single root | |
67 | * device with no children. | |
68 | */ | |
69 | ut_assert(dms->root); | |
70 | ut_asserteq(1, list_count_items(&gd->uclass_root)); | |
71 | ut_asserteq(0, list_count_items(&gd->dm_root->child_head)); | |
72 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]); | |
73 | ||
74 | ut_assertok(dm_scan_platdata()); | |
75 | ||
76 | /* We should have our test class now at least, plus more children */ | |
77 | ut_assert(1 < list_count_items(&gd->uclass_root)); | |
78 | ut_assert(0 < list_count_items(&gd->dm_root->child_head)); | |
79 | ||
80 | /* Our 3 dm_test_infox children should be bound to the test uclass */ | |
81 | ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]); | |
82 | ||
83 | /* No devices should be probed */ | |
84 | list_for_each_entry(dev, &gd->dm_root->child_head, sibling_node) | |
85 | ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); | |
86 | ||
87 | /* Our test driver should have been bound 3 times */ | |
88 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND] == 3); | |
89 | ||
90 | return 0; | |
91 | } | |
92 | DM_TEST(dm_test_autobind, 0); | |
93 | ||
94 | /* Test that autoprobe finds all the expected devices */ | |
95 | static int dm_test_autoprobe(struct dm_test_state *dms) | |
96 | { | |
97 | int expected_base_add; | |
54c5d08a | 98 | struct udevice *dev; |
2e7d35d2 SG |
99 | struct uclass *uc; |
100 | int i; | |
101 | ||
102 | ut_assertok(uclass_get(UCLASS_TEST, &uc)); | |
103 | ut_assert(uc); | |
104 | ||
105 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); | |
106 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]); | |
107 | ||
108 | /* The root device should not be activated until needed */ | |
7497812d | 109 | ut_assert(dms->root->flags & DM_FLAG_ACTIVATED); |
2e7d35d2 SG |
110 | |
111 | /* | |
112 | * We should be able to find the three test devices, and they should | |
113 | * all be activated as they are used (lazy activation, required by | |
114 | * U-Boot) | |
115 | */ | |
116 | for (i = 0; i < 3; i++) { | |
117 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
118 | ut_assert(dev); | |
119 | ut_assertf(!(dev->flags & DM_FLAG_ACTIVATED), | |
120 | "Driver %d/%s already activated", i, dev->name); | |
121 | ||
122 | /* This should activate it */ | |
123 | ut_assertok(uclass_get_device(UCLASS_TEST, i, &dev)); | |
124 | ut_assert(dev); | |
125 | ut_assert(dev->flags & DM_FLAG_ACTIVATED); | |
126 | ||
127 | /* Activating a device should activate the root device */ | |
128 | if (!i) | |
129 | ut_assert(dms->root->flags & DM_FLAG_ACTIVATED); | |
130 | } | |
131 | ||
132 | /* Our 3 dm_test_infox children should be passed to post_probe */ | |
133 | ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]); | |
134 | ||
135 | /* Also we can check the per-device data */ | |
136 | expected_base_add = 0; | |
137 | for (i = 0; i < 3; i++) { | |
138 | struct dm_test_uclass_perdev_priv *priv; | |
139 | struct dm_test_pdata *pdata; | |
140 | ||
141 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
142 | ut_assert(dev); | |
143 | ||
144 | priv = dev->uclass_priv; | |
145 | ut_assert(priv); | |
146 | ut_asserteq(expected_base_add, priv->base_add); | |
147 | ||
148 | pdata = dev->platdata; | |
149 | expected_base_add += pdata->ping_add; | |
150 | } | |
151 | ||
152 | return 0; | |
153 | } | |
154 | DM_TEST(dm_test_autoprobe, DM_TESTF_SCAN_PDATA); | |
155 | ||
156 | /* Check that we see the correct platdata in each device */ | |
157 | static int dm_test_platdata(struct dm_test_state *dms) | |
158 | { | |
159 | const struct dm_test_pdata *pdata; | |
54c5d08a | 160 | struct udevice *dev; |
2e7d35d2 SG |
161 | int i; |
162 | ||
163 | for (i = 0; i < 3; i++) { | |
164 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
165 | ut_assert(dev); | |
166 | pdata = dev->platdata; | |
167 | ut_assert(pdata->ping_add == test_pdata[i].ping_add); | |
168 | } | |
169 | ||
170 | return 0; | |
171 | } | |
172 | DM_TEST(dm_test_platdata, DM_TESTF_SCAN_PDATA); | |
173 | ||
174 | /* Test that we can bind, probe, remove, unbind a driver */ | |
175 | static int dm_test_lifecycle(struct dm_test_state *dms) | |
176 | { | |
177 | int op_count[DM_TEST_OP_COUNT]; | |
54c5d08a | 178 | struct udevice *dev, *test_dev; |
2e7d35d2 SG |
179 | int pingret; |
180 | int ret; | |
181 | ||
182 | memcpy(op_count, dm_testdrv_op_count, sizeof(op_count)); | |
183 | ||
184 | ut_assertok(device_bind_by_name(dms->root, &driver_info_manual, | |
185 | &dev)); | |
186 | ut_assert(dev); | |
187 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND] | |
188 | == op_count[DM_TEST_OP_BIND] + 1); | |
189 | ut_assert(!dev->priv); | |
190 | ||
191 | /* Probe the device - it should fail allocating private data */ | |
192 | dms->force_fail_alloc = 1; | |
193 | ret = device_probe(dev); | |
194 | ut_assert(ret == -ENOMEM); | |
195 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] | |
196 | == op_count[DM_TEST_OP_PROBE] + 1); | |
197 | ut_assert(!dev->priv); | |
198 | ||
199 | /* Try again without the alloc failure */ | |
200 | dms->force_fail_alloc = 0; | |
201 | ut_assertok(device_probe(dev)); | |
202 | ut_assert(dm_testdrv_op_count[DM_TEST_OP_PROBE] | |
203 | == op_count[DM_TEST_OP_PROBE] + 2); | |
204 | ut_assert(dev->priv); | |
205 | ||
206 | /* This should be device 3 in the uclass */ | |
207 | ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); | |
208 | ut_assert(dev == test_dev); | |
209 | ||
210 | /* Try ping */ | |
211 | ut_assertok(test_ping(dev, 100, &pingret)); | |
212 | ut_assert(pingret == 102); | |
213 | ||
214 | /* Now remove device 3 */ | |
215 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]); | |
216 | ut_assertok(device_remove(dev)); | |
217 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_REMOVE]); | |
218 | ||
219 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
220 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]); | |
221 | ut_assertok(device_unbind(dev)); | |
222 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
223 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]); | |
224 | ||
225 | return 0; | |
226 | } | |
227 | DM_TEST(dm_test_lifecycle, DM_TESTF_SCAN_PDATA | DM_TESTF_PROBE_TEST); | |
228 | ||
229 | /* Test that we can bind/unbind and the lists update correctly */ | |
230 | static int dm_test_ordering(struct dm_test_state *dms) | |
231 | { | |
54c5d08a | 232 | struct udevice *dev, *dev_penultimate, *dev_last, *test_dev; |
2e7d35d2 SG |
233 | int pingret; |
234 | ||
235 | ut_assertok(device_bind_by_name(dms->root, &driver_info_manual, | |
236 | &dev)); | |
237 | ut_assert(dev); | |
238 | ||
239 | /* Bind two new devices (numbers 4 and 5) */ | |
240 | ut_assertok(device_bind_by_name(dms->root, &driver_info_manual, | |
241 | &dev_penultimate)); | |
242 | ut_assert(dev_penultimate); | |
243 | ut_assertok(device_bind_by_name(dms->root, &driver_info_manual, | |
244 | &dev_last)); | |
245 | ut_assert(dev_last); | |
246 | ||
247 | /* Now remove device 3 */ | |
248 | ut_assertok(device_remove(dev)); | |
249 | ut_assertok(device_unbind(dev)); | |
250 | ||
251 | /* The device numbering should have shifted down one */ | |
252 | ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); | |
253 | ut_assert(dev_penultimate == test_dev); | |
254 | ut_assertok(uclass_find_device(UCLASS_TEST, 4, &test_dev)); | |
255 | ut_assert(dev_last == test_dev); | |
256 | ||
257 | /* Add back the original device 3, now in position 5 */ | |
258 | ut_assertok(device_bind_by_name(dms->root, &driver_info_manual, &dev)); | |
259 | ut_assert(dev); | |
260 | ||
261 | /* Try ping */ | |
262 | ut_assertok(test_ping(dev, 100, &pingret)); | |
263 | ut_assert(pingret == 102); | |
264 | ||
265 | /* Remove 3 and 4 */ | |
266 | ut_assertok(device_remove(dev_penultimate)); | |
267 | ut_assertok(device_unbind(dev_penultimate)); | |
268 | ut_assertok(device_remove(dev_last)); | |
269 | ut_assertok(device_unbind(dev_last)); | |
270 | ||
271 | /* Our device should now be in position 3 */ | |
272 | ut_assertok(uclass_find_device(UCLASS_TEST, 3, &test_dev)); | |
273 | ut_assert(dev == test_dev); | |
274 | ||
275 | /* Now remove device 3 */ | |
276 | ut_assertok(device_remove(dev)); | |
277 | ut_assertok(device_unbind(dev)); | |
278 | ||
279 | return 0; | |
280 | } | |
281 | DM_TEST(dm_test_ordering, DM_TESTF_SCAN_PDATA); | |
282 | ||
283 | /* Check that we can perform operations on a device (do a ping) */ | |
54c5d08a | 284 | int dm_check_operations(struct dm_test_state *dms, struct udevice *dev, |
2e7d35d2 SG |
285 | uint32_t base, struct dm_test_priv *priv) |
286 | { | |
287 | int expected; | |
288 | int pingret; | |
289 | ||
290 | /* Getting the child device should allocate platdata / priv */ | |
291 | ut_assertok(testfdt_ping(dev, 10, &pingret)); | |
292 | ut_assert(dev->priv); | |
293 | ut_assert(dev->platdata); | |
294 | ||
295 | expected = 10 + base; | |
296 | ut_asserteq(expected, pingret); | |
297 | ||
298 | /* Do another ping */ | |
299 | ut_assertok(testfdt_ping(dev, 20, &pingret)); | |
300 | expected = 20 + base; | |
301 | ut_asserteq(expected, pingret); | |
302 | ||
303 | /* Now check the ping_total */ | |
304 | priv = dev->priv; | |
305 | ut_asserteq(DM_TEST_START_TOTAL + 10 + 20 + base * 2, | |
306 | priv->ping_total); | |
307 | ||
308 | return 0; | |
309 | } | |
310 | ||
311 | /* Check that we can perform operations on devices */ | |
312 | static int dm_test_operations(struct dm_test_state *dms) | |
313 | { | |
54c5d08a | 314 | struct udevice *dev; |
2e7d35d2 SG |
315 | int i; |
316 | ||
317 | /* | |
318 | * Now check that the ping adds are what we expect. This is using the | |
319 | * ping-add property in each node. | |
320 | */ | |
321 | for (i = 0; i < ARRAY_SIZE(test_pdata); i++) { | |
322 | uint32_t base; | |
323 | ||
324 | ut_assertok(uclass_get_device(UCLASS_TEST, i, &dev)); | |
325 | ||
326 | /* | |
327 | * Get the 'reg' property, which tells us what the ping add | |
328 | * should be. We don't use the platdata because we want | |
329 | * to test the code that sets that up (testfdt_drv_probe()). | |
330 | */ | |
331 | base = test_pdata[i].ping_add; | |
332 | debug("dev=%d, base=%d\n", i, base); | |
333 | ||
334 | ut_assert(!dm_check_operations(dms, dev, base, dev->priv)); | |
335 | } | |
336 | ||
337 | return 0; | |
338 | } | |
339 | DM_TEST(dm_test_operations, DM_TESTF_SCAN_PDATA); | |
340 | ||
341 | /* Remove all drivers and check that things work */ | |
342 | static int dm_test_remove(struct dm_test_state *dms) | |
343 | { | |
54c5d08a | 344 | struct udevice *dev; |
2e7d35d2 SG |
345 | int i; |
346 | ||
347 | for (i = 0; i < 3; i++) { | |
348 | ut_assertok(uclass_find_device(UCLASS_TEST, i, &dev)); | |
349 | ut_assert(dev); | |
350 | ut_assertf(dev->flags & DM_FLAG_ACTIVATED, | |
351 | "Driver %d/%s not activated", i, dev->name); | |
352 | ut_assertok(device_remove(dev)); | |
353 | ut_assertf(!(dev->flags & DM_FLAG_ACTIVATED), | |
354 | "Driver %d/%s should have deactivated", i, | |
355 | dev->name); | |
356 | ut_assert(!dev->priv); | |
357 | } | |
358 | ||
359 | return 0; | |
360 | } | |
361 | DM_TEST(dm_test_remove, DM_TESTF_SCAN_PDATA | DM_TESTF_PROBE_TEST); | |
362 | ||
363 | /* Remove and recreate everything, check for memory leaks */ | |
364 | static int dm_test_leak(struct dm_test_state *dms) | |
365 | { | |
366 | int i; | |
367 | ||
368 | for (i = 0; i < 2; i++) { | |
369 | struct mallinfo start, end; | |
54c5d08a | 370 | struct udevice *dev; |
2e7d35d2 SG |
371 | int ret; |
372 | int id; | |
373 | ||
374 | start = mallinfo(); | |
375 | if (!start.uordblks) | |
376 | puts("Warning: Please add '#define DEBUG' to the top of common/dlmalloc.c\n"); | |
377 | ||
378 | ut_assertok(dm_scan_platdata()); | |
379 | ut_assertok(dm_scan_fdt(gd->fdt_blob)); | |
380 | ||
381 | /* Scanning the uclass is enough to probe all the devices */ | |
382 | for (id = UCLASS_ROOT; id < UCLASS_COUNT; id++) { | |
383 | for (ret = uclass_first_device(UCLASS_TEST, &dev); | |
384 | dev; | |
385 | ret = uclass_next_device(&dev)) | |
386 | ; | |
387 | ut_assertok(ret); | |
388 | } | |
389 | ||
390 | /* Don't delete the root class, since we started with that */ | |
391 | for (id = UCLASS_ROOT + 1; id < UCLASS_COUNT; id++) { | |
392 | struct uclass *uc; | |
393 | ||
394 | uc = uclass_find(id); | |
395 | if (!uc) | |
396 | continue; | |
397 | ut_assertok(uclass_destroy(uc)); | |
398 | } | |
399 | ||
400 | end = mallinfo(); | |
401 | ut_asserteq(start.uordblks, end.uordblks); | |
402 | } | |
403 | ||
404 | return 0; | |
405 | } | |
406 | DM_TEST(dm_test_leak, 0); | |
407 | ||
408 | /* Test uclass init/destroy methods */ | |
409 | static int dm_test_uclass(struct dm_test_state *dms) | |
410 | { | |
411 | struct uclass *uc; | |
412 | ||
413 | ut_assertok(uclass_get(UCLASS_TEST, &uc)); | |
414 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); | |
415 | ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_DESTROY]); | |
416 | ut_assert(uc->priv); | |
417 | ||
418 | ut_assertok(uclass_destroy(uc)); | |
419 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); | |
420 | ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_DESTROY]); | |
421 | ||
422 | return 0; | |
423 | } | |
424 | DM_TEST(dm_test_uclass, 0); | |
425 | ||
426 | /** | |
427 | * create_children() - Create children of a parent node | |
428 | * | |
429 | * @dms: Test system state | |
430 | * @parent: Parent device | |
431 | * @count: Number of children to create | |
432 | * @key: Key value to put in first child. Subsequence children | |
433 | * receive an incrementing value | |
434 | * @child: If not NULL, then the child device pointers are written into | |
435 | * this array. | |
436 | * @return 0 if OK, -ve on error | |
437 | */ | |
54c5d08a HS |
438 | static int create_children(struct dm_test_state *dms, struct udevice *parent, |
439 | int count, int key, struct udevice *child[]) | |
2e7d35d2 | 440 | { |
54c5d08a | 441 | struct udevice *dev; |
2e7d35d2 SG |
442 | int i; |
443 | ||
444 | for (i = 0; i < count; i++) { | |
445 | struct dm_test_pdata *pdata; | |
446 | ||
447 | ut_assertok(device_bind_by_name(parent, &driver_info_manual, | |
448 | &dev)); | |
449 | pdata = calloc(1, sizeof(*pdata)); | |
450 | pdata->ping_add = key + i; | |
451 | dev->platdata = pdata; | |
452 | if (child) | |
453 | child[i] = dev; | |
454 | } | |
455 | ||
456 | return 0; | |
457 | } | |
458 | ||
459 | #define NODE_COUNT 10 | |
460 | ||
461 | static int dm_test_children(struct dm_test_state *dms) | |
462 | { | |
54c5d08a HS |
463 | struct udevice *top[NODE_COUNT]; |
464 | struct udevice *child[NODE_COUNT]; | |
465 | struct udevice *grandchild[NODE_COUNT]; | |
466 | struct udevice *dev; | |
2e7d35d2 SG |
467 | int total; |
468 | int ret; | |
469 | int i; | |
470 | ||
471 | /* We don't care about the numbering for this test */ | |
472 | dms->skip_post_probe = 1; | |
473 | ||
474 | ut_assert(NODE_COUNT > 5); | |
475 | ||
476 | /* First create 10 top-level children */ | |
477 | ut_assertok(create_children(dms, dms->root, NODE_COUNT, 0, top)); | |
478 | ||
479 | /* Now a few have their own children */ | |
480 | ut_assertok(create_children(dms, top[2], NODE_COUNT, 2, NULL)); | |
481 | ut_assertok(create_children(dms, top[5], NODE_COUNT, 5, child)); | |
482 | ||
483 | /* And grandchildren */ | |
484 | for (i = 0; i < NODE_COUNT; i++) | |
485 | ut_assertok(create_children(dms, child[i], NODE_COUNT, 50 * i, | |
486 | i == 2 ? grandchild : NULL)); | |
487 | ||
488 | /* Check total number of devices */ | |
489 | total = NODE_COUNT * (3 + NODE_COUNT); | |
490 | ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_BIND]); | |
491 | ||
492 | /* Try probing one of the grandchildren */ | |
493 | ut_assertok(uclass_get_device(UCLASS_TEST, | |
494 | NODE_COUNT * 3 + 2 * NODE_COUNT, &dev)); | |
495 | ut_asserteq_ptr(grandchild[0], dev); | |
496 | ||
497 | /* | |
498 | * This should have probed the child and top node also, for a total | |
499 | * of 3 nodes. | |
500 | */ | |
501 | ut_asserteq(3, dm_testdrv_op_count[DM_TEST_OP_PROBE]); | |
502 | ||
503 | /* Probe the other grandchildren */ | |
504 | for (i = 1; i < NODE_COUNT; i++) | |
505 | ut_assertok(device_probe(grandchild[i])); | |
506 | ||
507 | ut_asserteq(2 + NODE_COUNT, dm_testdrv_op_count[DM_TEST_OP_PROBE]); | |
508 | ||
509 | /* Probe everything */ | |
510 | for (ret = uclass_first_device(UCLASS_TEST, &dev); | |
511 | dev; | |
512 | ret = uclass_next_device(&dev)) | |
513 | ; | |
514 | ut_assertok(ret); | |
515 | ||
516 | ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_PROBE]); | |
517 | ||
518 | /* Remove a top-level child and check that the children are removed */ | |
519 | ut_assertok(device_remove(top[2])); | |
520 | ut_asserteq(NODE_COUNT + 1, dm_testdrv_op_count[DM_TEST_OP_REMOVE]); | |
521 | dm_testdrv_op_count[DM_TEST_OP_REMOVE] = 0; | |
522 | ||
523 | /* Try one with grandchildren */ | |
524 | ut_assertok(uclass_get_device(UCLASS_TEST, 5, &dev)); | |
525 | ut_asserteq_ptr(dev, top[5]); | |
526 | ut_assertok(device_remove(dev)); | |
527 | ut_asserteq(1 + NODE_COUNT * (1 + NODE_COUNT), | |
528 | dm_testdrv_op_count[DM_TEST_OP_REMOVE]); | |
529 | ||
530 | /* Try the same with unbind */ | |
531 | ut_assertok(device_unbind(top[2])); | |
532 | ut_asserteq(NODE_COUNT + 1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
533 | dm_testdrv_op_count[DM_TEST_OP_UNBIND] = 0; | |
534 | ||
535 | /* Try one with grandchildren */ | |
536 | ut_assertok(uclass_get_device(UCLASS_TEST, 5, &dev)); | |
537 | ut_asserteq_ptr(dev, top[6]); | |
538 | ut_assertok(device_unbind(top[5])); | |
539 | ut_asserteq(1 + NODE_COUNT * (1 + NODE_COUNT), | |
540 | dm_testdrv_op_count[DM_TEST_OP_UNBIND]); | |
541 | ||
542 | return 0; | |
543 | } | |
544 | DM_TEST(dm_test_children, 0); |