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