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