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 the bus can store data about each child */ 144 static int dm_test_bus_parent_data(struct dm_test_state *dms) 145 { 146 struct dm_test_parent_data *parent_data; 147 struct udevice *bus, *dev; 148 struct uclass *uc; 149 int value; 150 151 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); 152 153 /* Check that parent data is allocated */ 154 ut_assertok(device_find_child_by_seq(bus, 0, true, &dev)); 155 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 156 ut_assertok(device_get_child_by_seq(bus, 0, &dev)); 157 parent_data = dev_get_parentdata(dev); 158 ut_assert(NULL != parent_data); 159 160 /* Check that it starts at 0 and goes away when device is removed */ 161 parent_data->sum += 5; 162 ut_asserteq(5, parent_data->sum); 163 device_remove(dev); 164 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 165 166 /* Check that we can do this twice */ 167 ut_assertok(device_get_child_by_seq(bus, 0, &dev)); 168 parent_data = dev_get_parentdata(dev); 169 ut_assert(NULL != parent_data); 170 parent_data->sum += 5; 171 ut_asserteq(5, parent_data->sum); 172 173 /* Add parent data to all children */ 174 ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc)); 175 value = 5; 176 uclass_foreach_dev(dev, uc) { 177 /* Ignore these if they are not on this bus */ 178 if (dev->parent != bus) { 179 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 180 continue; 181 } 182 ut_assertok(device_probe(dev)); 183 parent_data = dev_get_parentdata(dev); 184 185 parent_data->sum = value; 186 value += 5; 187 } 188 189 /* Check it is still there */ 190 value = 5; 191 uclass_foreach_dev(dev, uc) { 192 /* Ignore these if they are not on this bus */ 193 if (dev->parent != bus) 194 continue; 195 parent_data = dev_get_parentdata(dev); 196 197 ut_asserteq(value, parent_data->sum); 198 value += 5; 199 } 200 201 return 0; 202 } 203 204 DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 205 206 /* Test that the bus ops are called when a child is probed/removed */ 207 static int dm_test_bus_parent_ops(struct dm_test_state *dms) 208 { 209 struct dm_test_parent_data *parent_data; 210 struct udevice *bus, *dev; 211 struct uclass *uc; 212 213 test_state = dms; 214 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus)); 215 ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc)); 216 217 uclass_foreach_dev(dev, uc) { 218 /* Ignore these if they are not on this bus */ 219 if (dev->parent != bus) 220 continue; 221 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 222 223 ut_assertok(device_probe(dev)); 224 parent_data = dev_get_parentdata(dev); 225 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag); 226 } 227 228 uclass_foreach_dev(dev, uc) { 229 /* Ignore these if they are not on this bus */ 230 if (dev->parent != bus) 231 continue; 232 parent_data = dev_get_parentdata(dev); 233 ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag); 234 ut_assertok(device_remove(dev)); 235 ut_asserteq_ptr(NULL, dev_get_parentdata(dev)); 236 ut_asserteq_ptr(dms->removed, dev); 237 } 238 test_state = NULL; 239 240 return 0; 241 } 242 DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 243