blob: cbd0972c9b48781a8cc063a6e4a4872a3b27be03 [file] [log] [blame]
Simon Glass8d6320c2019-12-29 21:19:26 -07001// 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>
Simon Glass61b29b82020-02-03 07:36:15 -070013#include <dm/devres.h>
Simon Glass8d6320c2019-12-29 21:19:26 -070014#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 */
19static 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}
42DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA);
43
44/* Test devm_kfree() can be used to free memory too */
45static 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}
70DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA);
71
72
73/* Test that kzalloc() returns memory that is zeroed */
74static 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}
90DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA);
91
92/* Test that devm_kmalloc_array() allocates an array that can be set */
93static 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}
113DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA);
114
115/* Test that devm_kcalloc() allocates a zeroed array */
116static 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}
142DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA);
143
Simon Glass42a0ce52019-12-29 21:19:28 -0700144/* Test devres releases resources automatically as expected */
Simon Glass8d6320c2019-12-29 21:19:26 -0700145static 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
Simon Glass42a0ce52019-12-29 21:19:28 -0700159 /* 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
Simon Glass8d6320c2019-12-29 21:19:26 -0700165 /* 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);
Simon Glass42a0ce52019-12-29 21:19:28 -0700169 ut_asserteq(3, stats.allocs);
170 ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3,
171 stats.total_size);
Simon Glass8d6320c2019-12-29 21:19:26 -0700172
Simon Glass42a0ce52019-12-29 21:19:28 -0700173 /* Removing the device should drop both those allocations */
Simon Glass8d6320c2019-12-29 21:19:26 -0700174 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}
187DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);