dm: devres: Add tests
[oweals/u-boot.git] / test / dm / devres.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Tests for the devres (
4  *
5  * Copyright 2019 Google LLC
6  */
7
8 #include <common.h>
9 #include <errno.h>
10 #include <dm.h>
11 #include <malloc.h>
12 #include <dm/device-internal.h>
13 #include <dm/test.h>
14 #include <dm/uclass-internal.h>
15 #include <test/ut.h>
16
17 /* Test that devm_kmalloc() allocates memory, free when device is removed */
18 static int dm_test_devres_alloc(struct unit_test_state *uts)
19 {
20         ulong mem_start, mem_dev, mem_kmalloc;
21         struct udevice *dev;
22         void *ptr;
23
24         mem_start = ut_check_delta(0);
25         ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
26         mem_dev = ut_check_delta(mem_start);
27         ut_assert(mem_dev > 0);
28
29         /* This should increase allocated memory */
30         ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0);
31         ut_assert(ptr != NULL);
32         mem_kmalloc = ut_check_delta(mem_dev);
33         ut_assert(mem_kmalloc > 0);
34
35         /* Check that ptr is freed */
36         device_remove(dev, DM_REMOVE_NORMAL);
37         ut_asserteq(0, ut_check_delta(mem_start));
38
39         return 0;
40 }
41 DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA);
42
43 /* Test devm_kfree() can be used to free memory too */
44 static int dm_test_devres_free(struct unit_test_state *uts)
45 {
46         ulong mem_start, mem_dev, mem_kmalloc;
47         struct udevice *dev;
48         void *ptr;
49
50         mem_start = ut_check_delta(0);
51         ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
52         mem_dev = ut_check_delta(mem_start);
53         ut_assert(mem_dev > 0);
54
55         ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0);
56         ut_assert(ptr != NULL);
57         mem_kmalloc = ut_check_delta(mem_dev);
58         ut_assert(mem_kmalloc > 0);
59
60         /* Free the ptr and check that memory usage goes down */
61         devm_kfree(dev, ptr);
62         ut_assert(ut_check_delta(mem_kmalloc) < 0);
63
64         device_remove(dev, DM_REMOVE_NORMAL);
65         ut_asserteq(0, ut_check_delta(mem_start));
66
67         return 0;
68 }
69 DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA);
70
71
72 /* Test that kzalloc() returns memory that is zeroed */
73 static int dm_test_devres_kzalloc(struct unit_test_state *uts)
74 {
75         struct udevice *dev;
76         u8 *ptr, val;
77         int i;
78
79         ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
80
81         ptr = devm_kzalloc(dev, TEST_DEVRES_SIZE, 0);
82         ut_assert(ptr != NULL);
83         for (val = 0, i = 0; i < TEST_DEVRES_SIZE; i++)
84                 val |= *ptr;
85         ut_asserteq(0, val);
86
87         return 0;
88 }
89 DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA);
90
91 /* Test that devm_kmalloc_array() allocates an array that can be set */
92 static int dm_test_devres_kmalloc_array(struct unit_test_state *uts)
93 {
94         ulong mem_start, mem_dev;
95         struct udevice *dev;
96         u8 *ptr;
97
98         mem_start = ut_check_delta(0);
99         ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
100         mem_dev = ut_check_delta(mem_start);
101
102         ptr = devm_kmalloc_array(dev, TEST_DEVRES_COUNT, TEST_DEVRES_SIZE, 0);
103         ut_assert(ptr != NULL);
104         memset(ptr, '\xff', TEST_DEVRES_TOTAL);
105         ut_assert(ut_check_delta(mem_dev) > 0);
106
107         device_remove(dev, DM_REMOVE_NORMAL);
108         ut_asserteq(0, ut_check_delta(mem_start));
109
110         return 0;
111 }
112 DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA);
113
114 /* Test that devm_kcalloc() allocates a zeroed array */
115 static int dm_test_devres_kcalloc(struct unit_test_state *uts)
116 {
117         ulong mem_start, mem_dev;
118         struct udevice *dev;
119         u8 *ptr, val;
120         int i;
121
122         mem_start = ut_check_delta(0);
123         ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev));
124         mem_dev = ut_check_delta(mem_start);
125         ut_assert(mem_dev > 0);
126
127         /* This should increase allocated memory */
128         ptr = devm_kcalloc(dev, TEST_DEVRES_SIZE, TEST_DEVRES_COUNT, 0);
129         ut_assert(ptr != NULL);
130         ut_assert(ut_check_delta(mem_dev) > 0);
131         for (val = 0, i = 0; i < TEST_DEVRES_TOTAL; i++)
132                 val |= *ptr;
133         ut_asserteq(0, val);
134
135         /* Check that ptr is freed */
136         device_remove(dev, DM_REMOVE_NORMAL);
137         ut_asserteq(0, ut_check_delta(mem_start));
138
139         return 0;
140 }
141 DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA);
142
143 static int dm_test_devres_phase(struct unit_test_state *uts)
144 {
145         struct devres_stats stats;
146         struct udevice *dev;
147
148         /*
149          * The device is bound already, so find it and check that it has the
150          * allocation created in the bind() method.
151          */
152         ut_assertok(uclass_find_first_device(UCLASS_TEST_DEVRES, &dev));
153         devres_get_stats(dev, &stats);
154         ut_asserteq(1, stats.allocs);
155         ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
156
157         /* Probing the device should add one allocation */
158         ut_assertok(uclass_first_device(UCLASS_TEST_DEVRES, &dev));
159         ut_assert(dev != NULL);
160         devres_get_stats(dev, &stats);
161         ut_asserteq(2, stats.allocs);
162         ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2, stats.total_size);
163
164         /* Removing the device should drop one allocation */
165         device_remove(dev, DM_REMOVE_NORMAL);
166         devres_get_stats(dev, &stats);
167         ut_asserteq(1, stats.allocs);
168         ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
169
170         /* Unbinding removes the other. Note this access a freed pointer */
171         device_unbind(dev);
172         devres_get_stats(dev, &stats);
173         ut_asserteq(0, stats.allocs);
174         ut_asserteq(0, stats.total_size);
175
176         return 0;
177 }
178 DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);