1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include "alloc_helpers_api.h"
3 
4 /*
5  * A simple test that tries to allocate a memory region above a specified,
6  * aligned address:
7  *
8  *             +
9  *  |          +-----------+         |
10  *  |          |    rgn    |         |
11  *  +----------+-----------+---------+
12  *             ^
13  *             |
14  *             Aligned min_addr
15  *
16  * Expect to allocate a cleared region at the minimal memory address.
17  */
18 static int alloc_from_simple_generic_check(void)
19 {
20 	struct memblock_region *rgn = &memblock.reserved.regions[0];
21 	void *allocated_ptr = NULL;
22 	phys_addr_t size = SZ_16;
23 	phys_addr_t min_addr;
24 
25 	PREFIX_PUSH();
26 	setup_memblock();
27 
28 	min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES;
29 
30 	allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
31 
32 	ASSERT_NE(allocated_ptr, NULL);
33 	ASSERT_MEM_EQ(allocated_ptr, 0, size);
34 
35 	ASSERT_EQ(rgn->size, size);
36 	ASSERT_EQ(rgn->base, min_addr);
37 
38 	ASSERT_EQ(memblock.reserved.cnt, 1);
39 	ASSERT_EQ(memblock.reserved.total_size, size);
40 
41 	test_pass_pop();
42 
43 	return 0;
44 }
45 
46 /*
47  * A test that tries to allocate a memory region above a certain address.
48  * The minimal address here is not aligned:
49  *
50  *         +      +
51  *  |      +      +---------+            |
52  *  |      |      |   rgn   |            |
53  *  +------+------+---------+------------+
54  *         ^      ^------.
55  *         |             |
56  *       min_addr        Aligned address
57  *                       boundary
58  *
59  * Expect to allocate a cleared region at the closest aligned memory address.
60  */
61 static int alloc_from_misaligned_generic_check(void)
62 {
63 	struct memblock_region *rgn = &memblock.reserved.regions[0];
64 	void *allocated_ptr = NULL;
65 	phys_addr_t size = SZ_32;
66 	phys_addr_t min_addr;
67 
68 	PREFIX_PUSH();
69 	setup_memblock();
70 
71 	/* A misaligned address */
72 	min_addr = memblock_end_of_DRAM() - (SMP_CACHE_BYTES * 2 - 1);
73 
74 	allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
75 
76 	ASSERT_NE(allocated_ptr, NULL);
77 	ASSERT_MEM_EQ(allocated_ptr, 0, size);
78 
79 	ASSERT_EQ(rgn->size, size);
80 	ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
81 
82 	ASSERT_EQ(memblock.reserved.cnt, 1);
83 	ASSERT_EQ(memblock.reserved.total_size, size);
84 
85 	test_pass_pop();
86 
87 	return 0;
88 }
89 
90 /*
91  * A test that tries to allocate a memory region above an address that is too
92  * close to the end of the memory:
93  *
94  *              +        +
95  *  |           +--------+---+      |
96  *  |           |   rgn  +   |      |
97  *  +-----------+--------+---+------+
98  *              ^        ^
99  *              |        |
100  *              |        min_addr
101  *              |
102  *              Aligned address
103  *              boundary
104  *
105  * Expect to prioritize granting memory over satisfying the minimal address
106  * requirement.
107  */
108 static int alloc_from_top_down_high_addr_check(void)
109 {
110 	struct memblock_region *rgn = &memblock.reserved.regions[0];
111 	void *allocated_ptr = NULL;
112 	phys_addr_t size = SZ_32;
113 	phys_addr_t min_addr;
114 
115 	PREFIX_PUSH();
116 	setup_memblock();
117 
118 	/* The address is too close to the end of the memory */
119 	min_addr = memblock_end_of_DRAM() - SZ_16;
120 
121 	allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
122 
123 	ASSERT_NE(allocated_ptr, NULL);
124 	ASSERT_EQ(rgn->size, size);
125 	ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
126 
127 	ASSERT_EQ(memblock.reserved.cnt, 1);
128 	ASSERT_EQ(memblock.reserved.total_size, size);
129 
130 	test_pass_pop();
131 
132 	return 0;
133 }
134 
135 /*
136  * A test that tries to allocate a memory region when there is no space
137  * available above the minimal address above a certain address:
138  *
139  *                     +
140  *  |        +---------+-------------|
141  *  |        |   rgn   |             |
142  *  +--------+---------+-------------+
143  *                     ^
144  *                     |
145  *                     min_addr
146  *
147  * Expect to prioritize granting memory over satisfying the minimal address
148  * requirement and to allocate next to the previously reserved region. The
149  * regions get merged into one.
150  */
151 static int alloc_from_top_down_no_space_above_check(void)
152 {
153 	struct memblock_region *rgn = &memblock.reserved.regions[0];
154 	void *allocated_ptr = NULL;
155 	phys_addr_t r1_size = SZ_64;
156 	phys_addr_t r2_size = SZ_2;
157 	phys_addr_t total_size = r1_size + r2_size;
158 	phys_addr_t min_addr;
159 
160 	PREFIX_PUSH();
161 	setup_memblock();
162 
163 	min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
164 
165 	/* No space above this address */
166 	memblock_reserve(min_addr, r2_size);
167 
168 	allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
169 
170 	ASSERT_NE(allocated_ptr, NULL);
171 	ASSERT_EQ(rgn->base, min_addr - r1_size);
172 	ASSERT_EQ(rgn->size, total_size);
173 
174 	ASSERT_EQ(memblock.reserved.cnt, 1);
175 	ASSERT_EQ(memblock.reserved.total_size, total_size);
176 
177 	test_pass_pop();
178 
179 	return 0;
180 }
181 
182 /*
183  * A test that tries to allocate a memory region with a minimal address below
184  * the start address of the available memory. As the allocation is top-down,
185  * first reserve a region that will force allocation near the start.
186  * Expect successful allocation and merge of both regions.
187  */
188 static int alloc_from_top_down_min_addr_cap_check(void)
189 {
190 	struct memblock_region *rgn = &memblock.reserved.regions[0];
191 	void *allocated_ptr = NULL;
192 	phys_addr_t r1_size = SZ_64;
193 	phys_addr_t min_addr;
194 	phys_addr_t start_addr;
195 
196 	PREFIX_PUSH();
197 	setup_memblock();
198 
199 	start_addr = (phys_addr_t)memblock_start_of_DRAM();
200 	min_addr = start_addr - SMP_CACHE_BYTES * 3;
201 
202 	memblock_reserve(start_addr + r1_size, MEM_SIZE - r1_size);
203 
204 	allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
205 
206 	ASSERT_NE(allocated_ptr, NULL);
207 	ASSERT_EQ(rgn->base, start_addr);
208 	ASSERT_EQ(rgn->size, MEM_SIZE);
209 
210 	ASSERT_EQ(memblock.reserved.cnt, 1);
211 	ASSERT_EQ(memblock.reserved.total_size, MEM_SIZE);
212 
213 	test_pass_pop();
214 
215 	return 0;
216 }
217 
218 /*
219  * A test that tries to allocate a memory region above an address that is too
220  * close to the end of the memory:
221  *
222  *                             +
223  *  |-----------+              +     |
224  *  |    rgn    |              |     |
225  *  +-----------+--------------+-----+
226  *  ^                          ^
227  *  |                          |
228  *  Aligned address            min_addr
229  *  boundary
230  *
231  * Expect to prioritize granting memory over satisfying the minimal address
232  * requirement. Allocation happens at beginning of the available memory.
233  */
234 static int alloc_from_bottom_up_high_addr_check(void)
235 {
236 	struct memblock_region *rgn = &memblock.reserved.regions[0];
237 	void *allocated_ptr = NULL;
238 	phys_addr_t size = SZ_32;
239 	phys_addr_t min_addr;
240 
241 	PREFIX_PUSH();
242 	setup_memblock();
243 
244 	/* The address is too close to the end of the memory */
245 	min_addr = memblock_end_of_DRAM() - SZ_8;
246 
247 	allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
248 
249 	ASSERT_NE(allocated_ptr, NULL);
250 	ASSERT_EQ(rgn->size, size);
251 	ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
252 
253 	ASSERT_EQ(memblock.reserved.cnt, 1);
254 	ASSERT_EQ(memblock.reserved.total_size, size);
255 
256 	test_pass_pop();
257 
258 	return 0;
259 }
260 
261 /*
262  * A test that tries to allocate a memory region when there is no space
263  * available above the minimal address above a certain address:
264  *
265  *                   +
266  *  |-----------+    +-------------------|
267  *  |    rgn    |    |                   |
268  *  +-----------+----+-------------------+
269  *                   ^
270  *                   |
271  *                   min_addr
272  *
273  * Expect to prioritize granting memory over satisfying the minimal address
274  * requirement and to allocate at the beginning of the available memory.
275  */
276 static int alloc_from_bottom_up_no_space_above_check(void)
277 {
278 	struct memblock_region *rgn = &memblock.reserved.regions[0];
279 	void *allocated_ptr = NULL;
280 	phys_addr_t r1_size = SZ_64;
281 	phys_addr_t min_addr;
282 	phys_addr_t r2_size;
283 
284 	PREFIX_PUSH();
285 	setup_memblock();
286 
287 	min_addr = memblock_start_of_DRAM() + SZ_128;
288 	r2_size = memblock_end_of_DRAM() - min_addr;
289 
290 	/* No space above this address */
291 	memblock_reserve(min_addr - SMP_CACHE_BYTES, r2_size);
292 
293 	allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
294 
295 	ASSERT_NE(allocated_ptr, NULL);
296 	ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
297 	ASSERT_EQ(rgn->size, r1_size);
298 
299 	ASSERT_EQ(memblock.reserved.cnt, 2);
300 	ASSERT_EQ(memblock.reserved.total_size, r1_size + r2_size);
301 
302 	test_pass_pop();
303 
304 	return 0;
305 }
306 
307 /*
308  * A test that tries to allocate a memory region with a minimal address below
309  * the start address of the available memory. Expect to allocate a region
310  * at the beginning of the available memory.
311  */
312 static int alloc_from_bottom_up_min_addr_cap_check(void)
313 {
314 	struct memblock_region *rgn = &memblock.reserved.regions[0];
315 	void *allocated_ptr = NULL;
316 	phys_addr_t r1_size = SZ_64;
317 	phys_addr_t min_addr;
318 	phys_addr_t start_addr;
319 
320 	PREFIX_PUSH();
321 	setup_memblock();
322 
323 	start_addr = (phys_addr_t)memblock_start_of_DRAM();
324 	min_addr = start_addr - SMP_CACHE_BYTES * 3;
325 
326 	allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
327 
328 	ASSERT_NE(allocated_ptr, NULL);
329 	ASSERT_EQ(rgn->base, start_addr);
330 	ASSERT_EQ(rgn->size, r1_size);
331 
332 	ASSERT_EQ(memblock.reserved.cnt, 1);
333 	ASSERT_EQ(memblock.reserved.total_size, r1_size);
334 
335 	test_pass_pop();
336 
337 	return 0;
338 }
339 
340 /* Test case wrappers */
341 static int alloc_from_simple_check(void)
342 {
343 	test_print("\tRunning %s...\n", __func__);
344 	run_top_down(alloc_from_simple_generic_check);
345 	run_bottom_up(alloc_from_simple_generic_check);
346 
347 	return 0;
348 }
349 
350 static int alloc_from_misaligned_check(void)
351 {
352 	test_print("\tRunning %s...\n", __func__);
353 	run_top_down(alloc_from_misaligned_generic_check);
354 	run_bottom_up(alloc_from_misaligned_generic_check);
355 
356 	return 0;
357 }
358 
359 static int alloc_from_high_addr_check(void)
360 {
361 	test_print("\tRunning %s...\n", __func__);
362 	memblock_set_bottom_up(false);
363 	alloc_from_top_down_high_addr_check();
364 	memblock_set_bottom_up(true);
365 	alloc_from_bottom_up_high_addr_check();
366 
367 	return 0;
368 }
369 
370 static int alloc_from_no_space_above_check(void)
371 {
372 	test_print("\tRunning %s...\n", __func__);
373 	memblock_set_bottom_up(false);
374 	alloc_from_top_down_no_space_above_check();
375 	memblock_set_bottom_up(true);
376 	alloc_from_bottom_up_no_space_above_check();
377 
378 	return 0;
379 }
380 
381 static int alloc_from_min_addr_cap_check(void)
382 {
383 	test_print("\tRunning %s...\n", __func__);
384 	memblock_set_bottom_up(false);
385 	alloc_from_top_down_min_addr_cap_check();
386 	memblock_set_bottom_up(true);
387 	alloc_from_bottom_up_min_addr_cap_check();
388 
389 	return 0;
390 }
391 
392 int memblock_alloc_helpers_checks(void)
393 {
394 	const char *func_testing = "memblock_alloc_from";
395 
396 	prefix_reset();
397 	prefix_push(func_testing);
398 	test_print("Running %s tests...\n", func_testing);
399 
400 	reset_memblock_attributes();
401 	dummy_physical_memory_init();
402 
403 	alloc_from_simple_check();
404 	alloc_from_misaligned_check();
405 	alloc_from_high_addr_check();
406 	alloc_from_no_space_above_check();
407 	alloc_from_min_addr_cap_check();
408 
409 	dummy_physical_memory_cleanup();
410 
411 	prefix_pop();
412 
413 	return 0;
414 }
415