bus.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Copyright (c) 2014 Google, Inc
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <dm/device-internal.h>
  9. #include <dm/root.h>
  10. #include <dm/test.h>
  11. #include <dm/ut.h>
  12. #include <dm/util.h>
  13. DECLARE_GLOBAL_DATA_PTR;
  14. enum {
  15. FLAG_CHILD_PROBED = 10,
  16. FLAG_CHILD_REMOVED = -7,
  17. };
  18. static struct dm_test_state *test_state;
  19. static int testbus_drv_probe(struct udevice *dev)
  20. {
  21. return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
  22. }
  23. static int testbus_child_pre_probe(struct udevice *dev)
  24. {
  25. struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
  26. parent_data->flag += FLAG_CHILD_PROBED;
  27. return 0;
  28. }
  29. static int testbus_child_post_remove(struct udevice *dev)
  30. {
  31. struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
  32. struct dm_test_state *dms = test_state;
  33. parent_data->flag += FLAG_CHILD_REMOVED;
  34. if (dms)
  35. dms->removed = dev;
  36. return 0;
  37. }
  38. static const struct udevice_id testbus_ids[] = {
  39. {
  40. .compatible = "denx,u-boot-test-bus",
  41. .data = DM_TEST_TYPE_FIRST },
  42. { }
  43. };
  44. U_BOOT_DRIVER(testbus_drv) = {
  45. .name = "testbus_drv",
  46. .of_match = testbus_ids,
  47. .id = UCLASS_TEST_BUS,
  48. .probe = testbus_drv_probe,
  49. .priv_auto_alloc_size = sizeof(struct dm_test_priv),
  50. .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
  51. .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
  52. .child_pre_probe = testbus_child_pre_probe,
  53. .child_post_remove = testbus_child_post_remove,
  54. };
  55. UCLASS_DRIVER(testbus) = {
  56. .name = "testbus",
  57. .id = UCLASS_TEST_BUS,
  58. };
  59. /* Test that we can probe for children */
  60. static int dm_test_bus_children(struct dm_test_state *dms)
  61. {
  62. int num_devices = 4;
  63. struct udevice *bus;
  64. struct uclass *uc;
  65. ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
  66. ut_asserteq(num_devices, list_count_items(&uc->dev_head));
  67. /* Probe the bus, which should yield 3 more devices */
  68. ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
  69. num_devices += 3;
  70. ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
  71. ut_asserteq(num_devices, list_count_items(&uc->dev_head));
  72. ut_assert(!dm_check_devices(dms, num_devices));
  73. return 0;
  74. }
  75. DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  76. /* Test our functions for accessing children */
  77. static int dm_test_bus_children_funcs(struct dm_test_state *dms)
  78. {
  79. const void *blob = gd->fdt_blob;
  80. struct udevice *bus, *dev;
  81. int node;
  82. ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
  83. /* device_get_child() */
  84. ut_assertok(device_get_child(bus, 0, &dev));
  85. ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
  86. ut_assertok(device_get_child_by_seq(bus, 5, &dev));
  87. ut_assert(dev->flags & DM_FLAG_ACTIVATED);
  88. ut_asserteq_str("c-test@5", dev->name);
  89. /* Device with sequence number 0 should be accessible */
  90. ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
  91. ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
  92. ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
  93. ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
  94. ut_assertok(device_get_child_by_seq(bus, 0, &dev));
  95. ut_assert(dev->flags & DM_FLAG_ACTIVATED);
  96. /* There is no device with sequence number 2 */
  97. ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
  98. ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
  99. ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
  100. /* Looking for something that is not a child */
  101. node = fdt_path_offset(blob, "/junk");
  102. ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
  103. node = fdt_path_offset(blob, "/d-test");
  104. ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
  105. /* Find a valid child */
  106. node = fdt_path_offset(blob, "/some-bus/c-test@1");
  107. ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
  108. ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
  109. ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
  110. ut_assert(dev->flags & DM_FLAG_ACTIVATED);
  111. return 0;
  112. }
  113. DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  114. /* Test that the bus can store data about each child */
  115. static int dm_test_bus_parent_data(struct dm_test_state *dms)
  116. {
  117. struct dm_test_parent_data *parent_data;
  118. struct udevice *bus, *dev;
  119. struct uclass *uc;
  120. int value;
  121. ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
  122. /* Check that parent data is allocated */
  123. ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
  124. ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
  125. ut_assertok(device_get_child_by_seq(bus, 0, &dev));
  126. parent_data = dev_get_parentdata(dev);
  127. ut_assert(NULL != parent_data);
  128. /* Check that it starts at 0 and goes away when device is removed */
  129. parent_data->sum += 5;
  130. ut_asserteq(5, parent_data->sum);
  131. device_remove(dev);
  132. ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
  133. /* Check that we can do this twice */
  134. ut_assertok(device_get_child_by_seq(bus, 0, &dev));
  135. parent_data = dev_get_parentdata(dev);
  136. ut_assert(NULL != parent_data);
  137. parent_data->sum += 5;
  138. ut_asserteq(5, parent_data->sum);
  139. /* Add parent data to all children */
  140. ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
  141. value = 5;
  142. uclass_foreach_dev(dev, uc) {
  143. /* Ignore these if they are not on this bus */
  144. if (dev->parent != bus) {
  145. ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
  146. continue;
  147. }
  148. ut_assertok(device_probe(dev));
  149. parent_data = dev_get_parentdata(dev);
  150. parent_data->sum = value;
  151. value += 5;
  152. }
  153. /* Check it is still there */
  154. value = 5;
  155. uclass_foreach_dev(dev, uc) {
  156. /* Ignore these if they are not on this bus */
  157. if (dev->parent != bus)
  158. continue;
  159. parent_data = dev_get_parentdata(dev);
  160. ut_asserteq(value, parent_data->sum);
  161. value += 5;
  162. }
  163. return 0;
  164. }
  165. DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
  166. /* Test that the bus ops are called when a child is probed/removed */
  167. static int dm_test_bus_parent_ops(struct dm_test_state *dms)
  168. {
  169. struct dm_test_parent_data *parent_data;
  170. struct udevice *bus, *dev;
  171. struct uclass *uc;
  172. test_state = dms;
  173. ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
  174. ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
  175. uclass_foreach_dev(dev, uc) {
  176. /* Ignore these if they are not on this bus */
  177. if (dev->parent != bus)
  178. continue;
  179. ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
  180. ut_assertok(device_probe(dev));
  181. parent_data = dev_get_parentdata(dev);
  182. ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
  183. }
  184. uclass_foreach_dev(dev, uc) {
  185. /* Ignore these if they are not on this bus */
  186. if (dev->parent != bus)
  187. continue;
  188. parent_data = dev_get_parentdata(dev);
  189. ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
  190. ut_assertok(device_remove(dev));
  191. ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
  192. ut_asserteq_ptr(dms->removed, dev);
  193. }
  194. test_state = NULL;
  195. return 0;
  196. }
  197. DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);