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