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 */
18static 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 */
61static 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 */
108static 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 */
151static 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 */
188static 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 */
234static 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 */
276static 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 */
312static 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 */
341static 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
350static 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
359static 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
370static 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
381static 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
392int 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