blob: e7331897de8400d0fa9f6c22895a195caed37c1b [file] [log] [blame]
Simon Glass323ff9f2019-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>
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 */
18static 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}
41DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA);
42
43/* Test devm_kfree() can be used to free memory too */
44static 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}
69DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA);
70
71
72/* Test that kzalloc() returns memory that is zeroed */
73static 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}
89DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA);
90
91/* Test that devm_kmalloc_array() allocates an array that can be set */
92static 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}
112DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA);
113
114/* Test that devm_kcalloc() allocates a zeroed array */
115static 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}
141DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA);
142
Simon Glass0fe15372019-12-29 21:19:28 -0700143/* Test devres releases resources automatically as expected */
Simon Glass323ff9f2019-12-29 21:19:26 -0700144static int dm_test_devres_phase(struct unit_test_state *uts)
145{
146 struct devres_stats stats;
147 struct udevice *dev;
148
149 /*
150 * The device is bound already, so find it and check that it has the
151 * allocation created in the bind() method.
152 */
153 ut_assertok(uclass_find_first_device(UCLASS_TEST_DEVRES, &dev));
154 devres_get_stats(dev, &stats);
155 ut_asserteq(1, stats.allocs);
156 ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
157
Simon Glass0fe15372019-12-29 21:19:28 -0700158 /* Getting platdata should add one allocation */
159 ut_assertok(device_ofdata_to_platdata(dev));
160 devres_get_stats(dev, &stats);
161 ut_asserteq(2, stats.allocs);
162 ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE3, stats.total_size);
163
Simon Glass323ff9f2019-12-29 21:19:26 -0700164 /* Probing the device should add one allocation */
165 ut_assertok(uclass_first_device(UCLASS_TEST_DEVRES, &dev));
166 ut_assert(dev != NULL);
167 devres_get_stats(dev, &stats);
Simon Glass0fe15372019-12-29 21:19:28 -0700168 ut_asserteq(3, stats.allocs);
169 ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3,
170 stats.total_size);
Simon Glass323ff9f2019-12-29 21:19:26 -0700171
Simon Glass0fe15372019-12-29 21:19:28 -0700172 /* Removing the device should drop both those allocations */
Simon Glass323ff9f2019-12-29 21:19:26 -0700173 device_remove(dev, DM_REMOVE_NORMAL);
174 devres_get_stats(dev, &stats);
175 ut_asserteq(1, stats.allocs);
176 ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
177
178 /* Unbinding removes the other. Note this access a freed pointer */
179 device_unbind(dev);
180 devres_get_stats(dev, &stats);
181 ut_asserteq(0, stats.allocs);
182 ut_asserteq(0, stats.total_size);
183
184 return 0;
185}
186DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);