]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - test/dm/bus.c
c123ed7931092e77fc7470767d53a953c4341080
[karo-tx-uboot.git] / test / dm / bus.c
1 /*
2  * Copyright (c) 2014 Google, Inc
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <dm/device-internal.h>
10 #include <dm/root.h>
11 #include <dm/test.h>
12 #include <dm/uclass-internal.h>
13 #include <dm/ut.h>
14 #include <dm/util.h>
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 struct dm_test_parent_platdata {
19         int count;
20         int bind_flag;
21         int uclass_bind_flag;
22 };
23
24 enum {
25         FLAG_CHILD_PROBED       = 10,
26         FLAG_CHILD_REMOVED      = -7,
27 };
28
29 static struct dm_test_state *test_state;
30
31 static int testbus_drv_probe(struct udevice *dev)
32 {
33         return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
34 }
35
36 static int testbus_child_post_bind(struct udevice *dev)
37 {
38         struct dm_test_parent_platdata *plat;
39
40         plat = dev_get_parent_platdata(dev);
41         plat->bind_flag = 1;
42         plat->uclass_bind_flag = 2;
43
44         return 0;
45 }
46
47 static int testbus_child_pre_probe(struct udevice *dev)
48 {
49         struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
50
51         parent_data->flag += FLAG_CHILD_PROBED;
52
53         return 0;
54 }
55
56 static int testbus_child_post_remove(struct udevice *dev)
57 {
58         struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
59         struct dm_test_state *dms = test_state;
60
61         parent_data->flag += FLAG_CHILD_REMOVED;
62         if (dms)
63                 dms->removed = dev;
64
65         return 0;
66 }
67
68 static const struct udevice_id testbus_ids[] = {
69         {
70                 .compatible = "denx,u-boot-test-bus",
71                 .data = DM_TEST_TYPE_FIRST },
72         { }
73 };
74
75 U_BOOT_DRIVER(testbus_drv) = {
76         .name   = "testbus_drv",
77         .of_match       = testbus_ids,
78         .id     = UCLASS_TEST_BUS,
79         .probe  = testbus_drv_probe,
80         .child_post_bind = testbus_child_post_bind,
81         .priv_auto_alloc_size = sizeof(struct dm_test_priv),
82         .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
83         .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
84         .per_child_platdata_auto_alloc_size =
85                         sizeof(struct dm_test_parent_platdata),
86         .child_pre_probe = testbus_child_pre_probe,
87         .child_post_remove = testbus_child_post_remove,
88 };
89
90 UCLASS_DRIVER(testbus) = {
91         .name           = "testbus",
92         .id             = UCLASS_TEST_BUS,
93         .flags          = DM_UC_FLAG_SEQ_ALIAS,
94 };
95
96 /* Test that we can probe for children */
97 static int dm_test_bus_children(struct dm_test_state *dms)
98 {
99         int num_devices = 6;
100         struct udevice *bus;
101         struct uclass *uc;
102
103         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
104         ut_asserteq(num_devices, list_count_items(&uc->dev_head));
105
106         /* Probe the bus, which should yield 3 more devices */
107         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
108         num_devices += 3;
109
110         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
111         ut_asserteq(num_devices, list_count_items(&uc->dev_head));
112
113         ut_assert(!dm_check_devices(dms, num_devices));
114
115         return 0;
116 }
117 DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
118
119 /* Test our functions for accessing children */
120 static int dm_test_bus_children_funcs(struct dm_test_state *dms)
121 {
122         const void *blob = gd->fdt_blob;
123         struct udevice *bus, *dev;
124         int node;
125
126         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
127
128         /* device_get_child() */
129         ut_assertok(device_get_child(bus, 0, &dev));
130         ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
131         ut_assertok(device_get_child_by_seq(bus, 5, &dev));
132         ut_assert(dev->flags & DM_FLAG_ACTIVATED);
133         ut_asserteq_str("c-test@5", dev->name);
134
135         /* Device with sequence number 0 should be accessible */
136         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
137         ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
138         ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
139         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
140         ut_assertok(device_get_child_by_seq(bus, 0, &dev));
141         ut_assert(dev->flags & DM_FLAG_ACTIVATED);
142
143         /* There is no device with sequence number 2 */
144         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
145         ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
146         ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
147
148         /* Looking for something that is not a child */
149         node = fdt_path_offset(blob, "/junk");
150         ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
151         node = fdt_path_offset(blob, "/d-test");
152         ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
153
154         /* Find a valid child */
155         node = fdt_path_offset(blob, "/some-bus/c-test@1");
156         ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
157         ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
158         ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
159         ut_assert(dev->flags & DM_FLAG_ACTIVATED);
160
161         return 0;
162 }
163 DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
164
165 /* Test that we can iterate through children */
166 static int dm_test_bus_children_iterators(struct dm_test_state *dms)
167 {
168         struct udevice *bus, *dev, *child;
169
170         /* Walk through the children one by one */
171         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
172         ut_assertok(device_find_first_child(bus, &dev));
173         ut_asserteq_str("c-test@5", dev->name);
174         ut_assertok(device_find_next_child(&dev));
175         ut_asserteq_str("c-test@0", dev->name);
176         ut_assertok(device_find_next_child(&dev));
177         ut_asserteq_str("c-test@1", dev->name);
178         ut_assertok(device_find_next_child(&dev));
179         ut_asserteq_ptr(dev, NULL);
180
181         /* Move to the next child without using device_find_first_child() */
182         ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
183         ut_asserteq_str("c-test@5", dev->name);
184         ut_assertok(device_find_next_child(&dev));
185         ut_asserteq_str("c-test@0", dev->name);
186
187         /* Try a device with no children */
188         ut_assertok(device_find_first_child(dev, &child));
189         ut_asserteq_ptr(child, NULL);
190
191         return 0;
192 }
193 DM_TEST(dm_test_bus_children_iterators,
194         DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
195
196 /* Test that the bus can store data about each child */
197 static int test_bus_parent_data(struct dm_test_state *dms)
198 {
199         struct dm_test_parent_data *parent_data;
200         struct udevice *bus, *dev;
201         struct uclass *uc;
202         int value;
203
204         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
205
206         /* Check that parent data is allocated */
207         ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
208         ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
209         ut_assertok(device_get_child_by_seq(bus, 0, &dev));
210         parent_data = dev_get_parentdata(dev);
211         ut_assert(NULL != parent_data);
212
213         /* Check that it starts at 0 and goes away when device is removed */
214         parent_data->sum += 5;
215         ut_asserteq(5, parent_data->sum);
216         device_remove(dev);
217         ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
218
219         /* Check that we can do this twice */
220         ut_assertok(device_get_child_by_seq(bus, 0, &dev));
221         parent_data = dev_get_parentdata(dev);
222         ut_assert(NULL != parent_data);
223         parent_data->sum += 5;
224         ut_asserteq(5, parent_data->sum);
225
226         /* Add parent data to all children */
227         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
228         value = 5;
229         uclass_foreach_dev(dev, uc) {
230                 /* Ignore these if they are not on this bus */
231                 if (dev->parent != bus) {
232                         ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
233                         continue;
234                 }
235                 ut_assertok(device_probe(dev));
236                 parent_data = dev_get_parentdata(dev);
237
238                 parent_data->sum = value;
239                 value += 5;
240         }
241
242         /* Check it is still there */
243         value = 5;
244         uclass_foreach_dev(dev, uc) {
245                 /* Ignore these if they are not on this bus */
246                 if (dev->parent != bus)
247                         continue;
248                 parent_data = dev_get_parentdata(dev);
249
250                 ut_asserteq(value, parent_data->sum);
251                 value += 5;
252         }
253
254         return 0;
255 }
256 /* Test that the bus can store data about each child */
257 static int dm_test_bus_parent_data(struct dm_test_state *dms)
258 {
259         return test_bus_parent_data(dms);
260 }
261 DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
262
263 /* As above but the size is controlled by the uclass */
264 static int dm_test_bus_parent_data_uclass(struct dm_test_state *dms)
265 {
266         struct udevice *bus;
267         int size;
268         int ret;
269
270         /* Set the driver size to 0 so that the uclass size is used */
271         ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
272         size = bus->driver->per_child_auto_alloc_size;
273         bus->uclass->uc_drv->per_child_auto_alloc_size = size;
274         bus->driver->per_child_auto_alloc_size = 0;
275         ret = test_bus_parent_data(dms);
276         if (ret)
277                 return ret;
278         bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
279         bus->driver->per_child_auto_alloc_size = size;
280
281         return 0;
282 }
283 DM_TEST(dm_test_bus_parent_data_uclass,
284         DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
285
286 /* Test that the bus ops are called when a child is probed/removed */
287 static int dm_test_bus_parent_ops(struct dm_test_state *dms)
288 {
289         struct dm_test_parent_data *parent_data;
290         struct udevice *bus, *dev;
291         struct uclass *uc;
292
293         test_state = dms;
294         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
295         ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
296
297         uclass_foreach_dev(dev, uc) {
298                 /* Ignore these if they are not on this bus */
299                 if (dev->parent != bus)
300                         continue;
301                 ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
302
303                 ut_assertok(device_probe(dev));
304                 parent_data = dev_get_parentdata(dev);
305                 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
306         }
307
308         uclass_foreach_dev(dev, uc) {
309                 /* Ignore these if they are not on this bus */
310                 if (dev->parent != bus)
311                         continue;
312                 parent_data = dev_get_parentdata(dev);
313                 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
314                 ut_assertok(device_remove(dev));
315                 ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
316                 ut_asserteq_ptr(dms->removed, dev);
317         }
318         test_state = NULL;
319
320         return 0;
321 }
322 DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
323
324 static int test_bus_parent_platdata(struct dm_test_state *dms)
325 {
326         struct dm_test_parent_platdata *plat;
327         struct udevice *bus, *dev;
328         int child_count;
329
330         /* Check that the bus has no children */
331         ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
332         device_find_first_child(bus, &dev);
333         ut_asserteq_ptr(NULL, dev);
334
335         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
336
337         for (device_find_first_child(bus, &dev), child_count = 0;
338              dev;
339              device_find_next_child(&dev)) {
340                 /* Check that platform data is allocated */
341                 plat = dev_get_parent_platdata(dev);
342                 ut_assert(plat != NULL);
343
344                 /*
345                  * Check that it is not affected by the device being
346                  * probed/removed
347                  */
348                 plat->count++;
349                 ut_asserteq(1, plat->count);
350                 device_probe(dev);
351                 device_remove(dev);
352
353                 ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
354                 ut_asserteq(1, plat->count);
355                 ut_assertok(device_probe(dev));
356                 child_count++;
357         }
358         ut_asserteq(3, child_count);
359
360         /* Removing the bus should also have no effect (it is still bound) */
361         device_remove(bus);
362         for (device_find_first_child(bus, &dev), child_count = 0;
363              dev;
364              device_find_next_child(&dev)) {
365                 /* Check that platform data is allocated */
366                 plat = dev_get_parent_platdata(dev);
367                 ut_assert(plat != NULL);
368                 ut_asserteq(1, plat->count);
369                 child_count++;
370         }
371         ut_asserteq(3, child_count);
372
373         /* Unbind all the children */
374         do {
375                 device_find_first_child(bus, &dev);
376                 if (dev)
377                         device_unbind(dev);
378         } while (dev);
379
380         /* Now the child platdata should be removed and re-added */
381         device_probe(bus);
382         for (device_find_first_child(bus, &dev), child_count = 0;
383              dev;
384              device_find_next_child(&dev)) {
385                 /* Check that platform data is allocated */
386                 plat = dev_get_parent_platdata(dev);
387                 ut_assert(plat != NULL);
388                 ut_asserteq(0, plat->count);
389                 child_count++;
390         }
391         ut_asserteq(3, child_count);
392
393         return 0;
394 }
395
396 /* Test that the bus can store platform data about each child */
397 static int dm_test_bus_parent_platdata(struct dm_test_state *dms)
398 {
399         return test_bus_parent_platdata(dms);
400 }
401 DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
402
403 /* As above but the size is controlled by the uclass */
404 static int dm_test_bus_parent_platdata_uclass(struct dm_test_state *dms)
405 {
406         struct udevice *bus;
407         int size;
408         int ret;
409
410         /* Set the driver size to 0 so that the uclass size is used */
411         ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
412         size = bus->driver->per_child_platdata_auto_alloc_size;
413         bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size;
414         bus->driver->per_child_platdata_auto_alloc_size = 0;
415         ret = test_bus_parent_platdata(dms);
416         if (ret)
417                 return ret;
418         bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = 0;
419         bus->driver->per_child_platdata_auto_alloc_size = size;
420
421         return 0;
422 }
423 DM_TEST(dm_test_bus_parent_platdata_uclass,
424         DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
425
426 /* Test that the child post_bind method is called */
427 static int dm_test_bus_child_post_bind(struct dm_test_state *dms)
428 {
429         struct dm_test_parent_platdata *plat;
430         struct udevice *bus, *dev;
431         int child_count;
432
433         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
434         for (device_find_first_child(bus, &dev), child_count = 0;
435              dev;
436              device_find_next_child(&dev)) {
437                 /* Check that platform data is allocated */
438                 plat = dev_get_parent_platdata(dev);
439                 ut_assert(plat != NULL);
440                 ut_asserteq(1, plat->bind_flag);
441                 child_count++;
442         }
443         ut_asserteq(3, child_count);
444
445         return 0;
446 }
447 DM_TEST(dm_test_bus_child_post_bind, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
448
449 /* Test that the child post_bind method is called */
450 static int dm_test_bus_child_post_bind_uclass(struct dm_test_state *dms)
451 {
452         struct dm_test_parent_platdata *plat;
453         struct udevice *bus, *dev;
454         int child_count;
455
456         ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
457         for (device_find_first_child(bus, &dev), child_count = 0;
458              dev;
459              device_find_next_child(&dev)) {
460                 /* Check that platform data is allocated */
461                 plat = dev_get_parent_platdata(dev);
462                 ut_assert(plat != NULL);
463                 ut_asserteq(2, plat->uclass_bind_flag);
464                 child_count++;
465         }
466         ut_asserteq(3, child_count);
467
468         return 0;
469 }
470 DM_TEST(dm_test_bus_child_post_bind_uclass,
471         DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);