Merge branch 'next' of https://gitlab.denx.de/u-boot/custodians/u-boot-mpc83xx
[platform/kernel/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 <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 */
18 static 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 }
41 DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA);
42
43 /* Test devm_kfree() can be used to free memory too */
44 static 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 }
69 DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA);
70
71
72 /* Test that kzalloc() returns memory that is zeroed */
73 static 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 }
89 DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA);
90
91 /* Test that devm_kmalloc_array() allocates an array that can be set */
92 static 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 }
112 DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA);
113
114 /* Test that devm_kcalloc() allocates a zeroed array */
115 static 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 }
141 DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA);
142
143 /* Test devres releases resources automatically as expected */
144 static 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
158         /* 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
164         /* 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);
168         ut_asserteq(3, stats.allocs);
169         ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3,
170                     stats.total_size);
171
172         /* Removing the device should drop both those allocations */
173         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 }
186 DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);