Commit 8d6320cc4d5cd01e2e7fd01dd635e360cf0a1699
1 parent
dc12ebbbdb
Exists in
smarc_8mq_lf_v2020.04
and in
9 other branches
dm: devres: Add tests
The devres functionality has very few users in U-Boot, but it still should have tests. Add a few basic tests of the main functions. Signed-off-by: Simon Glass <sjg@chromium.org>
Showing 4 changed files with 212 additions and 0 deletions Side-by-side Diff
drivers/core/devres.c
... | ... | @@ -223,6 +223,19 @@ |
223 | 223 | if (root) |
224 | 224 | dump_resources(root, 0); |
225 | 225 | } |
226 | + | |
227 | +void devres_get_stats(const struct udevice *dev, struct devres_stats *stats) | |
228 | +{ | |
229 | + struct devres *dr; | |
230 | + | |
231 | + stats->allocs = 0; | |
232 | + stats->total_size = 0; | |
233 | + list_for_each_entry(dr, &dev->devres_head, entry) { | |
234 | + stats->allocs++; | |
235 | + stats->total_size += dr->size; | |
236 | + } | |
237 | +} | |
238 | + | |
226 | 239 | #endif |
227 | 240 | |
228 | 241 | /* |
include/dm/devres.h
... | ... | @@ -15,6 +15,17 @@ |
15 | 15 | typedef void (*dr_release_t)(struct udevice *dev, void *res); |
16 | 16 | typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data); |
17 | 17 | |
18 | +/** | |
19 | + * struct devres_stats - Information about devres allocations for a device | |
20 | + * | |
21 | + * @allocs: Number of allocations | |
22 | + * @total_size: Total size of allocations in bytes | |
23 | + */ | |
24 | +struct devres_stats { | |
25 | + int allocs; | |
26 | + int total_size; | |
27 | +}; | |
28 | + | |
18 | 29 | #ifdef CONFIG_DEVRES |
19 | 30 | |
20 | 31 | #ifdef CONFIG_DEBUG_DEVRES |
... | ... | @@ -189,6 +200,9 @@ |
189 | 200 | */ |
190 | 201 | void devm_kfree(struct udevice *dev, void *ptr); |
191 | 202 | |
203 | +/* Get basic stats on allocations */ | |
204 | +void devres_get_stats(const struct udevice *dev, struct devres_stats *stats); | |
205 | + | |
192 | 206 | #else /* ! CONFIG_DEVRES */ |
193 | 207 | |
194 | 208 | static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp) |
... | ... | @@ -265,6 +279,12 @@ |
265 | 279 | { |
266 | 280 | kfree(ptr); |
267 | 281 | } |
282 | + | |
283 | +static inline void devres_get_stats(const struct udevice *dev, | |
284 | + struct devres_stats *stats) | |
285 | +{ | |
286 | +} | |
287 | + | |
268 | 288 | #endif /* DEVRES */ |
269 | 289 | #endif /* _DM_DEVRES_H */ |
test/dm/Makefile
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | obj-$(CONFIG_BOARD) += board.o |
19 | 19 | obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o |
20 | 20 | obj-$(CONFIG_CLK) += clk.o clk_ccf.o |
21 | +obj-$(CONFIG_DEVRES) += devres.o | |
21 | 22 | obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o |
22 | 23 | obj-$(CONFIG_DM_ETH) += eth.o |
23 | 24 | obj-$(CONFIG_FIRMWARE) += firmware.o |
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); |