dm: core: Test uclass_first/next_device() on probe failure
[oweals/u-boot.git] / test / dm / test-fdt.c
1 /*
2  * Copyright (c) 2013 Google, Inc
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <fdtdec.h>
11 #include <malloc.h>
12 #include <asm/io.h>
13 #include <dm/test.h>
14 #include <dm/root.h>
15 #include <dm/device-internal.h>
16 #include <dm/uclass-internal.h>
17 #include <dm/util.h>
18 #include <test/ut.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
23 {
24         const struct dm_test_pdata *pdata = dev->platdata;
25         struct dm_test_priv *priv = dev_get_priv(dev);
26
27         *pingret = pingval + pdata->ping_add;
28         priv->ping_total += *pingret;
29
30         return 0;
31 }
32
33 static const struct test_ops test_ops = {
34         .ping = testfdt_drv_ping,
35 };
36
37 static int testfdt_ofdata_to_platdata(struct udevice *dev)
38 {
39         struct dm_test_pdata *pdata = dev_get_platdata(dev);
40
41         pdata->ping_add = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
42                                         "ping-add", -1);
43         pdata->base = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev),
44                                       "ping-expect");
45
46         return 0;
47 }
48
49 static int testfdt_drv_probe(struct udevice *dev)
50 {
51         struct dm_test_priv *priv = dev_get_priv(dev);
52
53         priv->ping_total += DM_TEST_START_TOTAL;
54
55         /*
56          * If this device is on a bus, the uclass_flag will be set before
57          * calling this function. This is used by
58          * dm_test_bus_child_pre_probe_uclass().
59          */
60         priv->uclass_total += priv->uclass_flag;
61
62         return 0;
63 }
64
65 static const struct udevice_id testfdt_ids[] = {
66         {
67                 .compatible = "denx,u-boot-fdt-test",
68                 .data = DM_TEST_TYPE_FIRST },
69         {
70                 .compatible = "google,another-fdt-test",
71                 .data = DM_TEST_TYPE_SECOND },
72         { }
73 };
74
75 U_BOOT_DRIVER(testfdt_drv) = {
76         .name   = "testfdt_drv",
77         .of_match       = testfdt_ids,
78         .id     = UCLASS_TEST_FDT,
79         .ofdata_to_platdata = testfdt_ofdata_to_platdata,
80         .probe  = testfdt_drv_probe,
81         .ops    = &test_ops,
82         .priv_auto_alloc_size = sizeof(struct dm_test_priv),
83         .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
84 };
85
86 /* From here is the testfdt uclass code */
87 int testfdt_ping(struct udevice *dev, int pingval, int *pingret)
88 {
89         const struct test_ops *ops = device_get_ops(dev);
90
91         if (!ops->ping)
92                 return -ENOSYS;
93
94         return ops->ping(dev, pingval, pingret);
95 }
96
97 UCLASS_DRIVER(testfdt) = {
98         .name           = "testfdt",
99         .id             = UCLASS_TEST_FDT,
100         .flags          = DM_UC_FLAG_SEQ_ALIAS,
101 };
102
103 struct dm_testprobe_pdata {
104         int probe_err;
105 };
106
107 static int testprobe_drv_probe(struct udevice *dev)
108 {
109         struct dm_testprobe_pdata *pdata = dev_get_platdata(dev);
110
111         return pdata->probe_err;
112 }
113
114 static const struct udevice_id testprobe_ids[] = {
115         { .compatible = "denx,u-boot-probe-test" },
116         { }
117 };
118
119 U_BOOT_DRIVER(testprobe_drv) = {
120         .name   = "testprobe_drv",
121         .of_match       = testprobe_ids,
122         .id     = UCLASS_TEST_PROBE,
123         .probe  = testprobe_drv_probe,
124         .platdata_auto_alloc_size       = sizeof(struct dm_testprobe_pdata),
125 };
126
127 UCLASS_DRIVER(testprobe) = {
128         .name           = "testprobe",
129         .id             = UCLASS_TEST_PROBE,
130         .flags          = DM_UC_FLAG_SEQ_ALIAS,
131 };
132
133 int dm_check_devices(struct unit_test_state *uts, int num_devices)
134 {
135         struct udevice *dev;
136         int ret;
137         int i;
138
139         /*
140          * Now check that the ping adds are what we expect. This is using the
141          * ping-add property in each node.
142          */
143         for (i = 0; i < num_devices; i++) {
144                 uint32_t base;
145
146                 ret = uclass_get_device(UCLASS_TEST_FDT, i, &dev);
147                 ut_assert(!ret);
148
149                 /*
150                  * Get the 'ping-expect' property, which tells us what the
151                  * ping add should be. We don't use the platdata because we
152                  * want to test the code that sets that up
153                  * (testfdt_drv_probe()).
154                  */
155                 base = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev),
156                                        "ping-expect");
157                 debug("dev=%d, base=%d: %s\n", i, base,
158                       fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL));
159
160                 ut_assert(!dm_check_operations(uts, dev, base,
161                                                dev_get_priv(dev)));
162         }
163
164         return 0;
165 }
166
167 /* Test that FDT-based binding works correctly */
168 static int dm_test_fdt(struct unit_test_state *uts)
169 {
170         const int num_devices = 6;
171         struct udevice *dev;
172         struct uclass *uc;
173         int ret;
174         int i;
175
176         ret = dm_scan_fdt(gd->fdt_blob, false);
177         ut_assert(!ret);
178
179         ret = uclass_get(UCLASS_TEST_FDT, &uc);
180         ut_assert(!ret);
181
182         /* These are num_devices compatible root-level device tree nodes */
183         ut_asserteq(num_devices, list_count_items(&uc->dev_head));
184
185         /* Each should have platform data but no private data */
186         for (i = 0; i < num_devices; i++) {
187                 ret = uclass_find_device(UCLASS_TEST_FDT, i, &dev);
188                 ut_assert(!ret);
189                 ut_assert(!dev_get_priv(dev));
190                 ut_assert(dev->platdata);
191         }
192
193         ut_assertok(dm_check_devices(uts, num_devices));
194
195         return 0;
196 }
197 DM_TEST(dm_test_fdt, 0);
198
199 static int dm_test_fdt_pre_reloc(struct unit_test_state *uts)
200 {
201         struct uclass *uc;
202         int ret;
203
204         ret = dm_scan_fdt(gd->fdt_blob, true);
205         ut_assert(!ret);
206
207         ret = uclass_get(UCLASS_TEST_FDT, &uc);
208         ut_assert(!ret);
209
210         /* These is only one pre-reloc device */
211         ut_asserteq(1, list_count_items(&uc->dev_head));
212
213         return 0;
214 }
215 DM_TEST(dm_test_fdt_pre_reloc, 0);
216
217 /* Test that sequence numbers are allocated properly */
218 static int dm_test_fdt_uclass_seq(struct unit_test_state *uts)
219 {
220         struct udevice *dev;
221
222         /* A few basic santiy tests */
223         ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 3, true, &dev));
224         ut_asserteq_str("b-test", dev->name);
225
226         ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 8, true, &dev));
227         ut_asserteq_str("a-test", dev->name);
228
229         ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5,
230                                                        true, &dev));
231         ut_asserteq_ptr(NULL, dev);
232
233         /* Test aliases */
234         ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 6, &dev));
235         ut_asserteq_str("e-test", dev->name);
236
237         ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 7,
238                                                        true, &dev));
239
240         /*
241          * Note that c-test nodes are not probed since it is not a top-level
242          * node
243          */
244         ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 3, &dev));
245         ut_asserteq_str("b-test", dev->name);
246
247         /*
248          * d-test wants sequence number 3 also, but it can't have it because
249          * b-test gets it first.
250          */
251         ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 2, &dev));
252         ut_asserteq_str("d-test", dev->name);
253
254         /* d-test actually gets 0 */
255         ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 0, &dev));
256         ut_asserteq_str("d-test", dev->name);
257
258         /* initially no one wants seq 1 */
259         ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_TEST_FDT, 1,
260                                                       &dev));
261         ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
262         ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 4, &dev));
263
264         /* But now that it is probed, we can find it */
265         ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev));
266         ut_asserteq_str("f-test", dev->name);
267
268         return 0;
269 }
270 DM_TEST(dm_test_fdt_uclass_seq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
271
272 /* Test that we can find a device by device tree offset */
273 static int dm_test_fdt_offset(struct unit_test_state *uts)
274 {
275         const void *blob = gd->fdt_blob;
276         struct udevice *dev;
277         int node;
278
279         node = fdt_path_offset(blob, "/e-test");
280         ut_assert(node > 0);
281         ut_assertok(uclass_get_device_by_of_offset(UCLASS_TEST_FDT, node,
282                                                    &dev));
283         ut_asserteq_str("e-test", dev->name);
284
285         /* This node should not be bound */
286         node = fdt_path_offset(blob, "/junk");
287         ut_assert(node > 0);
288         ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT,
289                                                             node, &dev));
290
291         /* This is not a top level node so should not be probed */
292         node = fdt_path_offset(blob, "/some-bus/c-test@5");
293         ut_assert(node > 0);
294         ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT,
295                                                             node, &dev));
296
297         return 0;
298 }
299 DM_TEST(dm_test_fdt_offset,
300         DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);
301
302 /**
303  * Test various error conditions with uclass_first_device() and
304  * uclass_next_device()
305  */
306 static int dm_test_first_next_device(struct unit_test_state *uts)
307 {
308         struct dm_testprobe_pdata *pdata;
309         struct udevice *dev, *parent = NULL;
310         int count;
311         int ret;
312
313         /* There should be 4 devices */
314         for (ret = uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
315              dev;
316              ret = uclass_next_device(&dev)) {
317                 count++;
318                 parent = dev_get_parent(dev);
319                 }
320         ut_assertok(ret);
321         ut_asserteq(4, count);
322
323         /* Remove them and try again, with an error on the second one */
324         ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 1, &dev));
325         pdata = dev_get_platdata(dev);
326         pdata->probe_err = -ENOMEM;
327         device_remove(parent, DM_REMOVE_NORMAL);
328         ut_assertok(uclass_first_device(UCLASS_TEST_PROBE, &dev));
329         ut_asserteq(-ENOMEM, uclass_next_device(&dev));
330         ut_asserteq_ptr(dev, NULL);
331
332         /* Now an error on the first one */
333         ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 0, &dev));
334         pdata = dev_get_platdata(dev);
335         pdata->probe_err = -ENOENT;
336         device_remove(parent, DM_REMOVE_NORMAL);
337         ut_asserteq(-ENOENT, uclass_first_device(UCLASS_TEST_PROBE, &dev));
338
339         return 0;
340 }
341 DM_TEST(dm_test_first_next_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);