blob: b5de0cb191ab41cdf38f03dba89353b10626147c [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>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Simon Glass8d6320c2019-12-29 21:19:26 -070012#include <malloc.h>
13#include <dm/device-internal.h>
Simon Glass61b29b82020-02-03 07:36:15 -070014#include <dm/devres.h>
Simon Glass8d6320c2019-12-29 21:19:26 -070015#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 */
20static 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}
43DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA);
44
45/* Test devm_kfree() can be used to free memory too */
46static 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}
71DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA);
72
73
74/* Test that kzalloc() returns memory that is zeroed */
75static 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}
91DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA);
92
93/* Test that devm_kmalloc_array() allocates an array that can be set */
94static 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}
114DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA);
115
116/* Test that devm_kcalloc() allocates a zeroed array */
117static 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}
143DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA);
144
Simon Glass42a0ce52019-12-29 21:19:28 -0700145/* Test devres releases resources automatically as expected */
Simon Glass8d6320c2019-12-29 21:19:26 -0700146static 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 devres_get_stats(dev, &stats);
157 ut_asserteq(1, stats.allocs);
158 ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
159
Simon Glass42a0ce52019-12-29 21:19:28 -0700160 /* Getting platdata should add one allocation */
161 ut_assertok(device_ofdata_to_platdata(dev));
162 devres_get_stats(dev, &stats);
163 ut_asserteq(2, stats.allocs);
164 ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE3, stats.total_size);
165
Simon Glass8d6320c2019-12-29 21:19:26 -0700166 /* Probing the device should add one allocation */
167 ut_assertok(uclass_first_device(UCLASS_TEST_DEVRES, &dev));
168 ut_assert(dev != NULL);
169 devres_get_stats(dev, &stats);
Simon Glass42a0ce52019-12-29 21:19:28 -0700170 ut_asserteq(3, stats.allocs);
171 ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3,
172 stats.total_size);
Simon Glass8d6320c2019-12-29 21:19:26 -0700173
Simon Glass42a0ce52019-12-29 21:19:28 -0700174 /* Removing the device should drop both those allocations */
Simon Glass8d6320c2019-12-29 21:19:26 -0700175 device_remove(dev, DM_REMOVE_NORMAL);
176 devres_get_stats(dev, &stats);
177 ut_asserteq(1, stats.allocs);
178 ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
179
180 /* Unbinding removes the other. Note this access a freed pointer */
181 device_unbind(dev);
182 devres_get_stats(dev, &stats);
183 ut_asserteq(0, stats.allocs);
184 ut_asserteq(0, stats.total_size);
185
186 return 0;
187}
188DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);