xref: /openbmc/u-boot/test/dm/bus.c (revision 081f2fcb)
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);
472