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/ut.h> 13 #include <dm/util.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 enum { 18 FLAG_CHILD_PROBED = 10, 19 FLAG_CHILD_REMOVED = -7, 20 }; 21 22 static struct dm_test_state *test_state; 23 24 static int testbus_drv_probe(struct udevice *dev) 25 { 26 return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); 27 } 28 29 static int testbus_child_pre_probe(struct udevice *dev) 30 { 31 struct dm_test_parent_data *parent_data = dev_get_parentdata(dev); 32 33 parent_data->flag += FLAG_CHILD_PROBED; 34 35 return 0; 36 } 37 38 static int testbus_child_post_remove(struct udevice *dev) 39 { 40 struct dm_test_parent_data *parent_data = dev_get_parentdata(dev); 41 struct dm_test_state *dms = test_state; 42 43 parent_data->flag += FLAG_CHILD_REMOVED; 44 if (dms) 45 dms->removed = dev; 46 47 return 0; 48 } 49 50 static const struct udevice_id testbus_ids[] = { 51 { 52 .compatible = "denx,u-boot-test-bus", 53 .data = DM_TEST_TYPE_FIRST }, 54 { } 55 }; 56 57 U_BOOT_DRIVER(testbus_drv) = { 58 .name = "testbus_drv", 59 .of_match = testbus_ids, 60 .id = UCLASS_TEST_BUS, 61 .probe = testbus_drv_probe, 62 .priv_auto_alloc_size = sizeof(struct dm_test_priv), 63 .platdata_auto_alloc_size = sizeof(struct dm_test_pdata), 64 .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data), 65 .child_pre_probe = testbus_child_pre_probe, 66 .child_post_remove = testbus_child_post_remove, 67 }; 68 69 UCLASS_DRIVER(testbus) = { 70 .name = "testbus", 71 .id = UCLASS_TEST_BUS, 72 }; 73 74 /* Test that we can probe for children */ 75 static int dm_test_bus_children(struct dm_test_state *dms) 76 { 77 int num_devices = 4; 78 struct udevice *bus; 79 struct uclass *uc; 80 81 ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc)); 82 ut_asserteq(num_devices, list_count_items(&uc->dev_head)); 83 84 /* Probe the bus, which should yield 3 more devices */ 85 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); 86 num_devices += 3; 87 88 ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc)); 89 ut_asserteq(num_devices, list_count_items(&uc->dev_head)); 90 91 ut_assert(!dm_check_devices(dms, num_devices)); 92 93 return 0; 94 } 95 DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 96 97 /* Test our functions for accessing children */ 98 static int dm_test_bus_children_funcs(struct dm_test_state *dms) 99 { 100 const void *blob = gd->fdt_blob; 101 struct udevice *bus, *dev; 102 int node; 103 104 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); 105 106 /* device_get_child() */ 107 ut_assertok(device_get_child(bus, 0, &dev)); 108 ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev)); 109 ut_assertok(device_get_child_by_seq(bus, 5, &dev)); 110 ut_assert(dev->flags & DM_FLAG_ACTIVATED); 111 ut_asserteq_str("c-test@5", dev->name); 112 113 /* Device with sequence number 0 should be accessible */ 114 ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev)); 115 ut_assertok(device_find_child_by_seq(bus, 0, true, &dev)); 116 ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); 117 ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev)); 118 ut_assertok(device_get_child_by_seq(bus, 0, &dev)); 119 ut_assert(dev->flags & DM_FLAG_ACTIVATED); 120 121 /* There is no device with sequence number 2 */ 122 ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev)); 123 ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev)); 124 ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev)); 125 126 /* Looking for something that is not a child */ 127 node = fdt_path_offset(blob, "/junk"); 128 ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev)); 129 node = fdt_path_offset(blob, "/d-test"); 130 ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev)); 131 132 /* Find a valid child */ 133 node = fdt_path_offset(blob, "/some-bus/c-test@1"); 134 ut_assertok(device_find_child_by_of_offset(bus, node, &dev)); 135 ut_assert(!(dev->flags & DM_FLAG_ACTIVATED)); 136 ut_assertok(device_get_child_by_of_offset(bus, node, &dev)); 137 ut_assert(dev->flags & DM_FLAG_ACTIVATED); 138 139 return 0; 140 } 141 DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 142 143 /* Test that we can iterate through children */ 144 static int dm_test_bus_children_iterators(struct dm_test_state *dms) 145 { 146 struct udevice *bus, *dev, *child; 147 148 /* Walk through the children one by one */ 149 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); 150 ut_assertok(device_find_first_child(bus, &dev)); 151 ut_asserteq_str("c-test@5", dev->name); 152 ut_assertok(device_find_next_child(&dev)); 153 ut_asserteq_str("c-test@0", dev->name); 154 ut_assertok(device_find_next_child(&dev)); 155 ut_asserteq_str("c-test@1", dev->name); 156 ut_assertok(device_find_next_child(&dev)); 157 ut_asserteq_ptr(dev, NULL); 158 159 /* Move to the next child without using device_find_first_child() */ 160 ut_assertok(device_find_child_by_seq(bus, 5, true, &dev)); 161 ut_asserteq_str("c-test@5", dev->name); 162 ut_assertok(device_find_next_child(&dev)); 163 ut_asserteq_str("c-test@0", dev->name); 164 165 /* Try a device with no children */ 166 ut_assertok(device_find_first_child(dev, &child)); 167 ut_asserteq_ptr(child, NULL); 168 169 return 0; 170 } 171 DM_TEST(dm_test_bus_children_iterators, 172 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 173 174 /* Test that the bus can store data about each child */ 175 static int dm_test_bus_parent_data(struct dm_test_state *dms) 176 { 177 struct dm_test_parent_data *parent_data; 178 struct udevice *bus, *dev; 179 struct uclass *uc; 180 int value; 181 182 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); 183 184 /* Check that parent data is allocated */ 185 ut_assertok(device_find_child_by_seq(bus, 0, true, &dev)); 186 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 187 ut_assertok(device_get_child_by_seq(bus, 0, &dev)); 188 parent_data = dev_get_parentdata(dev); 189 ut_assert(NULL != parent_data); 190 191 /* Check that it starts at 0 and goes away when device is removed */ 192 parent_data->sum += 5; 193 ut_asserteq(5, parent_data->sum); 194 device_remove(dev); 195 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 196 197 /* Check that we can do this twice */ 198 ut_assertok(device_get_child_by_seq(bus, 0, &dev)); 199 parent_data = dev_get_parentdata(dev); 200 ut_assert(NULL != parent_data); 201 parent_data->sum += 5; 202 ut_asserteq(5, parent_data->sum); 203 204 /* Add parent data to all children */ 205 ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc)); 206 value = 5; 207 uclass_foreach_dev(dev, uc) { 208 /* Ignore these if they are not on this bus */ 209 if (dev->parent != bus) { 210 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 211 continue; 212 } 213 ut_assertok(device_probe(dev)); 214 parent_data = dev_get_parentdata(dev); 215 216 parent_data->sum = value; 217 value += 5; 218 } 219 220 /* Check it is still there */ 221 value = 5; 222 uclass_foreach_dev(dev, uc) { 223 /* Ignore these if they are not on this bus */ 224 if (dev->parent != bus) 225 continue; 226 parent_data = dev_get_parentdata(dev); 227 228 ut_asserteq(value, parent_data->sum); 229 value += 5; 230 } 231 232 return 0; 233 } 234 235 DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 236 237 /* Test that the bus ops are called when a child is probed/removed */ 238 static int dm_test_bus_parent_ops(struct dm_test_state *dms) 239 { 240 struct dm_test_parent_data *parent_data; 241 struct udevice *bus, *dev; 242 struct uclass *uc; 243 244 test_state = dms; 245 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); 246 ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc)); 247 248 uclass_foreach_dev(dev, uc) { 249 /* Ignore these if they are not on this bus */ 250 if (dev->parent != bus) 251 continue; 252 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 253 254 ut_assertok(device_probe(dev)); 255 parent_data = dev_get_parentdata(dev); 256 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag); 257 } 258 259 uclass_foreach_dev(dev, uc) { 260 /* Ignore these if they are not on this bus */ 261 if (dev->parent != bus) 262 continue; 263 parent_data = dev_get_parentdata(dev); 264 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag); 265 ut_assertok(device_remove(dev)); 266 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 267 ut_asserteq_ptr(dms->removed, dev); 268 } 269 test_state = NULL; 270 271 return 0; 272 } 273 DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 274