Merge git://git.denx.de/u-boot-sh
[oweals/u-boot.git] / 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 <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 */
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, DM_TESTF_SCAN_PDATA);
44
45 /* Test devm_kfree() can be used to free memory too */
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, DM_TESTF_SCAN_PDATA);
72
73
74 /* Test that kzalloc() returns memory that is zeroed */
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, DM_TESTF_SCAN_PDATA);
92
93 /* Test that devm_kmalloc_array() allocates an array that can be set */
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, DM_TESTF_SCAN_PDATA);
115
116 /* Test that devm_kcalloc() allocates a zeroed array */
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, DM_TESTF_SCAN_PDATA);
144
145 /* Test devres releases resources automatically as expected */
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         devres_get_stats(dev, &stats);
157         ut_asserteq(1, stats.allocs);
158         ut_asserteq(TEST_DEVRES_SIZE, stats.total_size);
159
160         /* 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
166         /* 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);
170         ut_asserteq(3, stats.allocs);
171         ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3,
172                     stats.total_size);
173
174         /* Removing the device should drop both those allocations */
175         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 }
188 DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);