xref: /linux/mm/cma.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
18607a965SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a254129eSJoonsoo Kim /*
3a254129eSJoonsoo Kim  * Contiguous Memory Allocator
4a254129eSJoonsoo Kim  *
5a254129eSJoonsoo Kim  * Copyright (c) 2010-2011 by Samsung Electronics.
6a254129eSJoonsoo Kim  * Copyright IBM Corporation, 2013
7a254129eSJoonsoo Kim  * Copyright LG Electronics Inc., 2014
8a254129eSJoonsoo Kim  * Written by:
9a254129eSJoonsoo Kim  *	Marek Szyprowski <m.szyprowski@samsung.com>
10a254129eSJoonsoo Kim  *	Michal Nazarewicz <mina86@mina86.com>
11a254129eSJoonsoo Kim  *	Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
12a254129eSJoonsoo Kim  *	Joonsoo Kim <iamjoonsoo.kim@lge.com>
13a254129eSJoonsoo Kim  */
14a254129eSJoonsoo Kim 
15a254129eSJoonsoo Kim #define pr_fmt(fmt) "cma: " fmt
16a254129eSJoonsoo Kim 
1799e8ea6cSStefan Strogin #define CREATE_TRACE_POINTS
18a254129eSJoonsoo Kim 
19a254129eSJoonsoo Kim #include <linux/memblock.h>
20a254129eSJoonsoo Kim #include <linux/err.h>
21c009da42SFrank van der Linden #include <linux/list.h>
22a254129eSJoonsoo Kim #include <linux/mm.h>
23a254129eSJoonsoo Kim #include <linux/sizes.h>
24a254129eSJoonsoo Kim #include <linux/slab.h>
25ad789a85SThorsten Blum #include <linux/string.h>
2611f45931SThorsten Blum #include <linux/string_choices.h>
27a254129eSJoonsoo Kim #include <linux/log2.h>
28a254129eSJoonsoo Kim #include <linux/cma.h>
29f7426b98SMarek Szyprowski #include <linux/highmem.h>
30620951e2SThierry Reding #include <linux/io.h>
31514c6032SRandy Dunlap #include <linux/kmemleak.h>
3299e8ea6cSStefan Strogin #include <trace/events/cma.h>
33a254129eSJoonsoo Kim 
349420f89dSMike Rapoport (IBM) #include "internal.h"
3528b24c1fSSasha Levin #include "cma.h"
36a254129eSJoonsoo Kim 
3728b24c1fSSasha Levin struct cma cma_areas[MAX_CMA_AREAS];
381fa00a56SPintu Kumar unsigned int cma_area_count;
39a254129eSJoonsoo Kim 
cma_get_base(const struct cma * cma)40ac173824SSasha Levin phys_addr_t cma_get_base(const struct cma *cma)
41a254129eSJoonsoo Kim {
42c009da42SFrank van der Linden 	WARN_ON_ONCE(cma->nranges != 1);
43c009da42SFrank van der Linden 	return PFN_PHYS(cma->ranges[0].base_pfn);
44a254129eSJoonsoo Kim }
45a254129eSJoonsoo Kim 
cma_get_size(const struct cma * cma)46ac173824SSasha Levin unsigned long cma_get_size(const struct cma *cma)
47a254129eSJoonsoo Kim {
48a254129eSJoonsoo Kim 	return cma->count << PAGE_SHIFT;
49a254129eSJoonsoo Kim }
50a254129eSJoonsoo Kim 
cma_get_name(const struct cma * cma)51f318dd08SLaura Abbott const char *cma_get_name(const struct cma *cma)
52f318dd08SLaura Abbott {
5318e98e56SBarry Song 	return cma->name;
54f318dd08SLaura Abbott }
55*7e72a8f8SMaxime Ripard EXPORT_SYMBOL_GPL(cma_get_name);
56f318dd08SLaura Abbott 
cma_bitmap_aligned_mask(const struct cma * cma,unsigned int align_order)57ac173824SSasha Levin static unsigned long cma_bitmap_aligned_mask(const struct cma *cma,
58e048cb32SDoug Berger 					     unsigned int align_order)
59a254129eSJoonsoo Kim {
6068faed63SWeijie Yang 	if (align_order <= cma->order_per_bit)
6168faed63SWeijie Yang 		return 0;
6268faed63SWeijie Yang 	return (1UL << (align_order - cma->order_per_bit)) - 1;
63a254129eSJoonsoo Kim }
64a254129eSJoonsoo Kim 
65850fc430SDanesh Petigara /*
66e048cb32SDoug Berger  * Find the offset of the base PFN from the specified align_order.
67e048cb32SDoug Berger  * The value returned is represented in order_per_bits.
68850fc430SDanesh Petigara  */
cma_bitmap_aligned_offset(const struct cma * cma,const struct cma_memrange * cmr,unsigned int align_order)69ac173824SSasha Levin static unsigned long cma_bitmap_aligned_offset(const struct cma *cma,
70c009da42SFrank van der Linden 					       const struct cma_memrange *cmr,
71e048cb32SDoug Berger 					       unsigned int align_order)
72b5be83e3SGregory Fong {
73c009da42SFrank van der Linden 	return (cmr->base_pfn & ((1UL << align_order) - 1))
74e048cb32SDoug Berger 		>> cma->order_per_bit;
75b5be83e3SGregory Fong }
76b5be83e3SGregory Fong 
cma_bitmap_pages_to_bits(const struct cma * cma,unsigned long pages)77ac173824SSasha Levin static unsigned long cma_bitmap_pages_to_bits(const struct cma *cma,
78a254129eSJoonsoo Kim 					      unsigned long pages)
79a254129eSJoonsoo Kim {
80a254129eSJoonsoo Kim 	return ALIGN(pages, 1UL << cma->order_per_bit) >> cma->order_per_bit;
81a254129eSJoonsoo Kim }
82a254129eSJoonsoo Kim 
cma_clear_bitmap(struct cma * cma,const struct cma_memrange * cmr,unsigned long pfn,unsigned long count)83c009da42SFrank van der Linden static void cma_clear_bitmap(struct cma *cma, const struct cma_memrange *cmr,
84c009da42SFrank van der Linden 			     unsigned long pfn, unsigned long count)
85a254129eSJoonsoo Kim {
86a254129eSJoonsoo Kim 	unsigned long bitmap_no, bitmap_count;
870ef7dcacSMike Kravetz 	unsigned long flags;
88a254129eSJoonsoo Kim 
89c009da42SFrank van der Linden 	bitmap_no = (pfn - cmr->base_pfn) >> cma->order_per_bit;
90a254129eSJoonsoo Kim 	bitmap_count = cma_bitmap_pages_to_bits(cma, count);
91a254129eSJoonsoo Kim 
920ef7dcacSMike Kravetz 	spin_lock_irqsave(&cma->lock, flags);
93c009da42SFrank van der Linden 	bitmap_clear(cmr->bitmap, bitmap_no, bitmap_count);
947365ff2cSFrank van der Linden 	cma->available_count += count;
950ef7dcacSMike Kravetz 	spin_unlock_irqrestore(&cma->lock, flags);
96a254129eSJoonsoo Kim }
97a254129eSJoonsoo Kim 
989320fa27SFrank van der Linden /*
999320fa27SFrank van der Linden  * Check if a CMA area contains no ranges that intersect with
1009320fa27SFrank van der Linden  * multiple zones. Store the result in the flags in case
1019320fa27SFrank van der Linden  * this gets called more than once.
1029320fa27SFrank van der Linden  */
cma_validate_zones(struct cma * cma)1039320fa27SFrank van der Linden bool cma_validate_zones(struct cma *cma)
1049320fa27SFrank van der Linden {
1059320fa27SFrank van der Linden 	int r;
1069320fa27SFrank van der Linden 	unsigned long base_pfn;
1079320fa27SFrank van der Linden 	struct cma_memrange *cmr;
1089320fa27SFrank van der Linden 	bool valid_bit_set;
1099320fa27SFrank van der Linden 
1109320fa27SFrank van der Linden 	/*
1119320fa27SFrank van der Linden 	 * If already validated, return result of previous check.
1129320fa27SFrank van der Linden 	 * Either the valid or invalid bit will be set if this
1139320fa27SFrank van der Linden 	 * check has already been done. If neither is set, the
1149320fa27SFrank van der Linden 	 * check has not been performed yet.
1159320fa27SFrank van der Linden 	 */
1169320fa27SFrank van der Linden 	valid_bit_set = test_bit(CMA_ZONES_VALID, &cma->flags);
1179320fa27SFrank van der Linden 	if (valid_bit_set || test_bit(CMA_ZONES_INVALID, &cma->flags))
1189320fa27SFrank van der Linden 		return valid_bit_set;
1199320fa27SFrank van der Linden 
1209320fa27SFrank van der Linden 	for (r = 0; r < cma->nranges; r++) {
1219320fa27SFrank van der Linden 		cmr = &cma->ranges[r];
1229320fa27SFrank van der Linden 		base_pfn = cmr->base_pfn;
1239320fa27SFrank van der Linden 
1249320fa27SFrank van der Linden 		/*
1259320fa27SFrank van der Linden 		 * alloc_contig_range() requires the pfn range specified
1269320fa27SFrank van der Linden 		 * to be in the same zone. Simplify by forcing the entire
1279320fa27SFrank van der Linden 		 * CMA resv range to be in the same zone.
1289320fa27SFrank van der Linden 		 */
1299320fa27SFrank van der Linden 		WARN_ON_ONCE(!pfn_valid(base_pfn));
1309320fa27SFrank van der Linden 		if (pfn_range_intersects_zones(cma->nid, base_pfn, cmr->count)) {
1319320fa27SFrank van der Linden 			set_bit(CMA_ZONES_INVALID, &cma->flags);
1329320fa27SFrank van der Linden 			return false;
1339320fa27SFrank van der Linden 		}
1349320fa27SFrank van der Linden 	}
1359320fa27SFrank van der Linden 
1369320fa27SFrank van der Linden 	set_bit(CMA_ZONES_VALID, &cma->flags);
1379320fa27SFrank van der Linden 
1389320fa27SFrank van der Linden 	return true;
1399320fa27SFrank van der Linden }
1409320fa27SFrank van der Linden 
cma_activate_area(struct cma * cma)1413a5139f1SMike Kravetz static void __init cma_activate_area(struct cma *cma)
142a254129eSJoonsoo Kim {
14383b6d498SZhongkun He 	unsigned long pfn, end_pfn, early_pfn[CMA_MAX_RANGES];
144c009da42SFrank van der Linden 	int allocrange, r;
145c009da42SFrank van der Linden 	struct cma_memrange *cmr;
14685abcd02SFrank van der Linden 	unsigned long bitmap_count, count;
147a254129eSJoonsoo Kim 
148c009da42SFrank van der Linden 	for (allocrange = 0; allocrange < cma->nranges; allocrange++) {
149c009da42SFrank van der Linden 		cmr = &cma->ranges[allocrange];
15083b6d498SZhongkun He 		early_pfn[allocrange] = cmr->early_pfn;
151c009da42SFrank van der Linden 		cmr->bitmap = bitmap_zalloc(cma_bitmap_maxno(cma, cmr),
152c009da42SFrank van der Linden 					    GFP_KERNEL);
153c009da42SFrank van der Linden 		if (!cmr->bitmap)
154c009da42SFrank van der Linden 			goto cleanup;
155c009da42SFrank van der Linden 	}
156c009da42SFrank van der Linden 
1579320fa27SFrank van der Linden 	if (!cma_validate_zones(cma))
1589320fa27SFrank van der Linden 		goto cleanup;
1599320fa27SFrank van der Linden 
160c009da42SFrank van der Linden 	for (r = 0; r < cma->nranges; r++) {
161c009da42SFrank van der Linden 		cmr = &cma->ranges[r];
16283b6d498SZhongkun He 		if (early_pfn[r] != cmr->base_pfn) {
16383b6d498SZhongkun He 			count = early_pfn[r] - cmr->base_pfn;
16485abcd02SFrank van der Linden 			bitmap_count = cma_bitmap_pages_to_bits(cma, count);
16585abcd02SFrank van der Linden 			bitmap_set(cmr->bitmap, 0, bitmap_count);
16685abcd02SFrank van der Linden 		}
16785abcd02SFrank van der Linden 
16883b6d498SZhongkun He 		for (pfn = early_pfn[r]; pfn < cmr->base_pfn + cmr->count;
169072355c1SDavid Hildenbrand 		     pfn += pageblock_nr_pages)
170072355c1SDavid Hildenbrand 			init_cma_reserved_pageblock(pfn_to_page(pfn));
171c009da42SFrank van der Linden 	}
172a254129eSJoonsoo Kim 
1730ef7dcacSMike Kravetz 	spin_lock_init(&cma->lock);
17426b02a1fSSasha Levin 
17524ac6fb6SGe Yang 	mutex_init(&cma->alloc_mutex);
17624ac6fb6SGe Yang 
17726b02a1fSSasha Levin #ifdef CONFIG_CMA_DEBUGFS
17826b02a1fSSasha Levin 	INIT_HLIST_HEAD(&cma->mem_head);
17926b02a1fSSasha Levin 	spin_lock_init(&cma->mem_head_lock);
18026b02a1fSSasha Levin #endif
18185abcd02SFrank van der Linden 	set_bit(CMA_ACTIVATED, &cma->flags);
18226b02a1fSSasha Levin 
1833a5139f1SMike Kravetz 	return;
184a254129eSJoonsoo Kim 
185c009da42SFrank van der Linden cleanup:
186c009da42SFrank van der Linden 	for (r = 0; r < allocrange; r++)
187c009da42SFrank van der Linden 		bitmap_free(cma->ranges[r].bitmap);
188c009da42SFrank van der Linden 
189072355c1SDavid Hildenbrand 	/* Expose all pages to the buddy, they are useless for CMA. */
1909320fa27SFrank van der Linden 	if (!test_bit(CMA_RESERVE_PAGES_ON_ERROR, &cma->flags)) {
191c009da42SFrank van der Linden 		for (r = 0; r < allocrange; r++) {
192c009da42SFrank van der Linden 			cmr = &cma->ranges[r];
19385abcd02SFrank van der Linden 			end_pfn = cmr->base_pfn + cmr->count;
19483b6d498SZhongkun He 			for (pfn = early_pfn[r]; pfn < end_pfn; pfn++)
195072355c1SDavid Hildenbrand 				free_reserved_page(pfn_to_page(pfn));
19627d121d0SHari Bathini 		}
197c009da42SFrank van der Linden 	}
198072355c1SDavid Hildenbrand 	totalcma_pages -= cma->count;
1997365ff2cSFrank van der Linden 	cma->available_count = cma->count = 0;
2003a5139f1SMike Kravetz 	pr_err("CMA area %s could not be activated\n", cma->name);
201a254129eSJoonsoo Kim }
202a254129eSJoonsoo Kim 
cma_init_reserved_areas(void)203a254129eSJoonsoo Kim static int __init cma_init_reserved_areas(void)
204a254129eSJoonsoo Kim {
205a254129eSJoonsoo Kim 	int i;
206a254129eSJoonsoo Kim 
2073a5139f1SMike Kravetz 	for (i = 0; i < cma_area_count; i++)
2083a5139f1SMike Kravetz 		cma_activate_area(&cma_areas[i]);
209a254129eSJoonsoo Kim 
210a254129eSJoonsoo Kim 	return 0;
211a254129eSJoonsoo Kim }
212d883c6cfSJoonsoo Kim core_initcall(cma_init_reserved_areas);
213a254129eSJoonsoo Kim 
cma_reserve_pages_on_error(struct cma * cma)21427d121d0SHari Bathini void __init cma_reserve_pages_on_error(struct cma *cma)
21527d121d0SHari Bathini {
2169320fa27SFrank van der Linden 	set_bit(CMA_RESERVE_PAGES_ON_ERROR, &cma->flags);
21727d121d0SHari Bathini }
21827d121d0SHari Bathini 
cma_new_area(const char * name,phys_addr_t size,unsigned int order_per_bit,struct cma ** res_cma)219c009da42SFrank van der Linden static int __init cma_new_area(const char *name, phys_addr_t size,
220c009da42SFrank van der Linden 			       unsigned int order_per_bit,
221c009da42SFrank van der Linden 			       struct cma **res_cma)
222c009da42SFrank van der Linden {
223c009da42SFrank van der Linden 	struct cma *cma;
224c009da42SFrank van der Linden 
225c009da42SFrank van der Linden 	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
226c009da42SFrank van der Linden 		pr_err("Not enough slots for CMA reserved regions!\n");
227c009da42SFrank van der Linden 		return -ENOSPC;
228c009da42SFrank van der Linden 	}
229c009da42SFrank van der Linden 
230c009da42SFrank van der Linden 	/*
231c009da42SFrank van der Linden 	 * Each reserved area must be initialised later, when more kernel
232c009da42SFrank van der Linden 	 * subsystems (like slab allocator) are available.
233c009da42SFrank van der Linden 	 */
234c009da42SFrank van der Linden 	cma = &cma_areas[cma_area_count];
235c009da42SFrank van der Linden 	cma_area_count++;
236c009da42SFrank van der Linden 
237c009da42SFrank van der Linden 	if (name)
238ad789a85SThorsten Blum 		strscpy(cma->name, name);
239c009da42SFrank van der Linden 	else
240c009da42SFrank van der Linden 		snprintf(cma->name, CMA_MAX_NAME,  "cma%d\n", cma_area_count);
241c009da42SFrank van der Linden 
242c009da42SFrank van der Linden 	cma->available_count = cma->count = size >> PAGE_SHIFT;
243c009da42SFrank van der Linden 	cma->order_per_bit = order_per_bit;
244c009da42SFrank van der Linden 	*res_cma = cma;
245c009da42SFrank van der Linden 	totalcma_pages += cma->count;
246c009da42SFrank van der Linden 
247c009da42SFrank van der Linden 	return 0;
248c009da42SFrank van der Linden }
249c009da42SFrank van der Linden 
cma_drop_area(struct cma * cma)250c009da42SFrank van der Linden static void __init cma_drop_area(struct cma *cma)
251c009da42SFrank van der Linden {
252c009da42SFrank van der Linden 	totalcma_pages -= cma->count;
253c009da42SFrank van der Linden 	cma_area_count--;
254c009da42SFrank van der Linden }
255c009da42SFrank van der Linden 
256a254129eSJoonsoo Kim /**
257de9e14eeSMarek Szyprowski  * cma_init_reserved_mem() - create custom contiguous area from reserved memory
258de9e14eeSMarek Szyprowski  * @base: Base address of the reserved area
259de9e14eeSMarek Szyprowski  * @size: Size of the reserved area (in bytes),
260de9e14eeSMarek Szyprowski  * @order_per_bit: Order of pages represented by one bit on bitmap.
261e8b098fcSMike Rapoport  * @name: The name of the area. If this parameter is NULL, the name of
262e8b098fcSMike Rapoport  *        the area will be set to "cmaN", where N is a running counter of
263e8b098fcSMike Rapoport  *        used areas.
264de9e14eeSMarek Szyprowski  * @res_cma: Pointer to store the created cma region.
265de9e14eeSMarek Szyprowski  *
266de9e14eeSMarek Szyprowski  * This function creates custom contiguous area from already reserved memory.
267de9e14eeSMarek Szyprowski  */
cma_init_reserved_mem(phys_addr_t base,phys_addr_t size,unsigned int order_per_bit,const char * name,struct cma ** res_cma)268de9e14eeSMarek Szyprowski int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
269ac173824SSasha Levin 				 unsigned int order_per_bit,
270f318dd08SLaura Abbott 				 const char *name,
271ac173824SSasha Levin 				 struct cma **res_cma)
272de9e14eeSMarek Szyprowski {
273de9e14eeSMarek Szyprowski 	struct cma *cma;
274c009da42SFrank van der Linden 	int ret;
275de9e14eeSMarek Szyprowski 
276de9e14eeSMarek Szyprowski 	/* Sanity checks */
277de9e14eeSMarek Szyprowski 	if (!size || !memblock_is_region_reserved(base, size))
278de9e14eeSMarek Szyprowski 		return -EINVAL;
279de9e14eeSMarek Szyprowski 
2802532e6c7SRitesh Harjani (IBM) 	/*
2812532e6c7SRitesh Harjani (IBM) 	 * CMA uses CMA_MIN_ALIGNMENT_BYTES as alignment requirement which
2822532e6c7SRitesh Harjani (IBM) 	 * needs pageblock_order to be initialized. Let's enforce it.
2832532e6c7SRitesh Harjani (IBM) 	 */
2842532e6c7SRitesh Harjani (IBM) 	if (!pageblock_order) {
2852532e6c7SRitesh Harjani (IBM) 		pr_err("pageblock_order not yet initialized. Called during early boot?\n");
2862532e6c7SRitesh Harjani (IBM) 		return -EINVAL;
2872532e6c7SRitesh Harjani (IBM) 	}
2882532e6c7SRitesh Harjani (IBM) 
289e16faf26SDavid Hildenbrand 	/* ensure minimal alignment required by mm core */
290e16faf26SDavid Hildenbrand 	if (!IS_ALIGNED(base | size, CMA_MIN_ALIGNMENT_BYTES))
291de9e14eeSMarek Szyprowski 		return -EINVAL;
292de9e14eeSMarek Szyprowski 
293c009da42SFrank van der Linden 	ret = cma_new_area(name, size, order_per_bit, &cma);
294c009da42SFrank van der Linden 	if (ret != 0)
295c009da42SFrank van der Linden 		return ret;
29618e98e56SBarry Song 
297c009da42SFrank van der Linden 	cma->ranges[0].base_pfn = PFN_DOWN(base);
29885abcd02SFrank van der Linden 	cma->ranges[0].early_pfn = PFN_DOWN(base);
299c009da42SFrank van der Linden 	cma->ranges[0].count = cma->count;
300c009da42SFrank van der Linden 	cma->nranges = 1;
301b51d3db9SFrank van der Linden 	cma->nid = NUMA_NO_NODE;
30218e98e56SBarry Song 
303de9e14eeSMarek Szyprowski 	*res_cma = cma;
304de9e14eeSMarek Szyprowski 
305de9e14eeSMarek Szyprowski 	return 0;
306de9e14eeSMarek Szyprowski }
307de9e14eeSMarek Szyprowski 
308c009da42SFrank van der Linden /*
309c009da42SFrank van der Linden  * Structure used while walking physical memory ranges and finding out
310c009da42SFrank van der Linden  * which one(s) to use for a CMA area.
311c009da42SFrank van der Linden  */
312c009da42SFrank van der Linden struct cma_init_memrange {
313c009da42SFrank van der Linden 	phys_addr_t base;
314c009da42SFrank van der Linden 	phys_addr_t size;
315c009da42SFrank van der Linden 	struct list_head list;
316c009da42SFrank van der Linden };
317c009da42SFrank van der Linden 
318c009da42SFrank van der Linden /*
319c009da42SFrank van der Linden  * Work array used during CMA initialization.
320c009da42SFrank van der Linden  */
321c009da42SFrank van der Linden static struct cma_init_memrange memranges[CMA_MAX_RANGES] __initdata;
322c009da42SFrank van der Linden 
revsizecmp(struct cma_init_memrange * mlp,struct cma_init_memrange * mrp)323c009da42SFrank van der Linden static bool __init revsizecmp(struct cma_init_memrange *mlp,
324c009da42SFrank van der Linden 			      struct cma_init_memrange *mrp)
325c009da42SFrank van der Linden {
326c009da42SFrank van der Linden 	return mlp->size > mrp->size;
327c009da42SFrank van der Linden }
328c009da42SFrank van der Linden 
basecmp(struct cma_init_memrange * mlp,struct cma_init_memrange * mrp)329c009da42SFrank van der Linden static bool __init basecmp(struct cma_init_memrange *mlp,
330c009da42SFrank van der Linden 			   struct cma_init_memrange *mrp)
331c009da42SFrank van der Linden {
332c009da42SFrank van der Linden 	return mlp->base < mrp->base;
333c009da42SFrank van der Linden }
334c009da42SFrank van der Linden 
335c009da42SFrank van der Linden /*
336c009da42SFrank van der Linden  * Helper function to create sorted lists.
337c009da42SFrank van der Linden  */
list_insert_sorted(struct list_head * ranges,struct cma_init_memrange * mrp,bool (* cmp)(struct cma_init_memrange * lh,struct cma_init_memrange * rh))338c009da42SFrank van der Linden static void __init list_insert_sorted(
339c009da42SFrank van der Linden 	struct list_head *ranges,
340c009da42SFrank van der Linden 	struct cma_init_memrange *mrp,
341c009da42SFrank van der Linden 	bool (*cmp)(struct cma_init_memrange *lh, struct cma_init_memrange *rh))
342c009da42SFrank van der Linden {
343c009da42SFrank van der Linden 	struct list_head *mp;
344c009da42SFrank van der Linden 	struct cma_init_memrange *mlp;
345c009da42SFrank van der Linden 
346c009da42SFrank van der Linden 	if (list_empty(ranges))
347c009da42SFrank van der Linden 		list_add(&mrp->list, ranges);
348c009da42SFrank van der Linden 	else {
349c009da42SFrank van der Linden 		list_for_each(mp, ranges) {
350c009da42SFrank van der Linden 			mlp = list_entry(mp, struct cma_init_memrange, list);
351c009da42SFrank van der Linden 			if (cmp(mlp, mrp))
352c009da42SFrank van der Linden 				break;
353c009da42SFrank van der Linden 		}
354c009da42SFrank van der Linden 		__list_add(&mrp->list, mlp->list.prev, &mlp->list);
355c009da42SFrank van der Linden 	}
356c009da42SFrank van der Linden }
357c009da42SFrank van der Linden 
cma_fixed_reserve(phys_addr_t base,phys_addr_t size)358bef58716SMike Rapoport (Microsoft) static int __init cma_fixed_reserve(phys_addr_t base, phys_addr_t size)
359bef58716SMike Rapoport (Microsoft) {
360bef58716SMike Rapoport (Microsoft) 	if (IS_ENABLED(CONFIG_HIGHMEM)) {
361bef58716SMike Rapoport (Microsoft) 		phys_addr_t highmem_start = __pa(high_memory - 1) + 1;
362bef58716SMike Rapoport (Microsoft) 
363bef58716SMike Rapoport (Microsoft) 		/*
364bef58716SMike Rapoport (Microsoft) 		 * If allocating at a fixed base the request region must not
365bef58716SMike Rapoport (Microsoft) 		 * cross the low/high memory boundary.
366bef58716SMike Rapoport (Microsoft) 		 */
367bef58716SMike Rapoport (Microsoft) 		if (base < highmem_start && base + size > highmem_start) {
368bef58716SMike Rapoport (Microsoft) 			pr_err("Region at %pa defined on low/high memory boundary (%pa)\n",
369bef58716SMike Rapoport (Microsoft) 			       &base, &highmem_start);
370bef58716SMike Rapoport (Microsoft) 			return -EINVAL;
371bef58716SMike Rapoport (Microsoft) 		}
372bef58716SMike Rapoport (Microsoft) 	}
373bef58716SMike Rapoport (Microsoft) 
374bef58716SMike Rapoport (Microsoft) 	if (memblock_is_region_reserved(base, size) ||
375bef58716SMike Rapoport (Microsoft) 	    memblock_reserve(base, size) < 0) {
376bef58716SMike Rapoport (Microsoft) 		return -EBUSY;
377bef58716SMike Rapoport (Microsoft) 	}
378bef58716SMike Rapoport (Microsoft) 
379bef58716SMike Rapoport (Microsoft) 	return 0;
380bef58716SMike Rapoport (Microsoft) }
381bef58716SMike Rapoport (Microsoft) 
cma_alloc_mem(phys_addr_t base,phys_addr_t size,phys_addr_t align,phys_addr_t limit,int nid)3828aa2c0bfSMike Rapoport (Microsoft) static phys_addr_t __init cma_alloc_mem(phys_addr_t base, phys_addr_t size,
3838aa2c0bfSMike Rapoport (Microsoft) 			phys_addr_t align, phys_addr_t limit, int nid)
3848aa2c0bfSMike Rapoport (Microsoft) {
3858aa2c0bfSMike Rapoport (Microsoft) 	phys_addr_t addr = 0;
3868aa2c0bfSMike Rapoport (Microsoft) 
3878aa2c0bfSMike Rapoport (Microsoft) 	/*
3888aa2c0bfSMike Rapoport (Microsoft) 	 * If there is enough memory, try a bottom-up allocation first.
3898aa2c0bfSMike Rapoport (Microsoft) 	 * It will place the new cma area close to the start of the node
3908aa2c0bfSMike Rapoport (Microsoft) 	 * and guarantee that the compaction is moving pages out of the
3918aa2c0bfSMike Rapoport (Microsoft) 	 * cma area and not into it.
3928aa2c0bfSMike Rapoport (Microsoft) 	 * Avoid using first 4GB to not interfere with constrained zones
3938aa2c0bfSMike Rapoport (Microsoft) 	 * like DMA/DMA32.
3948aa2c0bfSMike Rapoport (Microsoft) 	 */
3958aa2c0bfSMike Rapoport (Microsoft) #ifdef CONFIG_PHYS_ADDR_T_64BIT
3968aa2c0bfSMike Rapoport (Microsoft) 	if (!memblock_bottom_up() && limit >= SZ_4G + size) {
3978aa2c0bfSMike Rapoport (Microsoft) 		memblock_set_bottom_up(true);
3988aa2c0bfSMike Rapoport (Microsoft) 		addr = memblock_alloc_range_nid(size, align, SZ_4G, limit,
3998aa2c0bfSMike Rapoport (Microsoft) 						nid, true);
4008aa2c0bfSMike Rapoport (Microsoft) 		memblock_set_bottom_up(false);
4018aa2c0bfSMike Rapoport (Microsoft) 	}
4028aa2c0bfSMike Rapoport (Microsoft) #endif
4038aa2c0bfSMike Rapoport (Microsoft) 
4048aa2c0bfSMike Rapoport (Microsoft) 	/*
4058aa2c0bfSMike Rapoport (Microsoft) 	 * On systems with HIGHMEM try allocating from there before consuming
4068aa2c0bfSMike Rapoport (Microsoft) 	 * memory in lower zones.
4078aa2c0bfSMike Rapoport (Microsoft) 	 */
4088aa2c0bfSMike Rapoport (Microsoft) 	if (!addr && IS_ENABLED(CONFIG_HIGHMEM)) {
4098aa2c0bfSMike Rapoport (Microsoft) 		phys_addr_t highmem = __pa(high_memory - 1) + 1;
4108aa2c0bfSMike Rapoport (Microsoft) 
4118aa2c0bfSMike Rapoport (Microsoft) 		/*
4128aa2c0bfSMike Rapoport (Microsoft) 		 * All pages in the reserved area must come from the same zone.
4138aa2c0bfSMike Rapoport (Microsoft) 		 * If the requested region crosses the low/high memory boundary,
4148aa2c0bfSMike Rapoport (Microsoft) 		 * try allocating from high memory first and fall back to low
4158aa2c0bfSMike Rapoport (Microsoft) 		 * memory in case of failure.
4168aa2c0bfSMike Rapoport (Microsoft) 		 */
4178aa2c0bfSMike Rapoport (Microsoft) 		if (base < highmem && limit > highmem) {
4188aa2c0bfSMike Rapoport (Microsoft) 			addr = memblock_alloc_range_nid(size, align, highmem,
4198aa2c0bfSMike Rapoport (Microsoft) 							limit, nid, true);
4208aa2c0bfSMike Rapoport (Microsoft) 			limit = highmem;
4218aa2c0bfSMike Rapoport (Microsoft) 		}
4228aa2c0bfSMike Rapoport (Microsoft) 	}
4238aa2c0bfSMike Rapoport (Microsoft) 
4248aa2c0bfSMike Rapoport (Microsoft) 	if (!addr)
4258aa2c0bfSMike Rapoport (Microsoft) 		addr = memblock_alloc_range_nid(size, align, base, limit, nid,
4268aa2c0bfSMike Rapoport (Microsoft) 						true);
4278aa2c0bfSMike Rapoport (Microsoft) 
4288aa2c0bfSMike Rapoport (Microsoft) 	return addr;
4298aa2c0bfSMike Rapoport (Microsoft) }
4308aa2c0bfSMike Rapoport (Microsoft) 
__cma_declare_contiguous_nid(phys_addr_t * basep,phys_addr_t size,phys_addr_t limit,phys_addr_t alignment,unsigned int order_per_bit,bool fixed,const char * name,struct cma ** res_cma,int nid)43120089ebdSMike Rapoport (Microsoft) static int __init __cma_declare_contiguous_nid(phys_addr_t *basep,
43220089ebdSMike Rapoport (Microsoft) 			phys_addr_t size, phys_addr_t limit,
43320089ebdSMike Rapoport (Microsoft) 			phys_addr_t alignment, unsigned int order_per_bit,
43420089ebdSMike Rapoport (Microsoft) 			bool fixed, const char *name, struct cma **res_cma,
43520089ebdSMike Rapoport (Microsoft) 			int nid)
43620089ebdSMike Rapoport (Microsoft) {
43720089ebdSMike Rapoport (Microsoft) 	phys_addr_t memblock_end = memblock_end_of_DRAM();
4388aa2c0bfSMike Rapoport (Microsoft) 	phys_addr_t base = *basep;
43920089ebdSMike Rapoport (Microsoft) 	int ret;
44020089ebdSMike Rapoport (Microsoft) 
44120089ebdSMike Rapoport (Microsoft) 	pr_debug("%s(size %pa, base %pa, limit %pa alignment %pa)\n",
44220089ebdSMike Rapoport (Microsoft) 		__func__, &size, &base, &limit, &alignment);
44320089ebdSMike Rapoport (Microsoft) 
44420089ebdSMike Rapoport (Microsoft) 	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
44520089ebdSMike Rapoport (Microsoft) 		pr_err("Not enough slots for CMA reserved regions!\n");
44620089ebdSMike Rapoport (Microsoft) 		return -ENOSPC;
44720089ebdSMike Rapoport (Microsoft) 	}
44820089ebdSMike Rapoport (Microsoft) 
44920089ebdSMike Rapoport (Microsoft) 	if (!size)
45020089ebdSMike Rapoport (Microsoft) 		return -EINVAL;
45120089ebdSMike Rapoport (Microsoft) 
45220089ebdSMike Rapoport (Microsoft) 	if (alignment && !is_power_of_2(alignment))
45320089ebdSMike Rapoport (Microsoft) 		return -EINVAL;
45420089ebdSMike Rapoport (Microsoft) 
45520089ebdSMike Rapoport (Microsoft) 	if (!IS_ENABLED(CONFIG_NUMA))
45620089ebdSMike Rapoport (Microsoft) 		nid = NUMA_NO_NODE;
45720089ebdSMike Rapoport (Microsoft) 
45820089ebdSMike Rapoport (Microsoft) 	/* Sanitise input arguments. */
45920089ebdSMike Rapoport (Microsoft) 	alignment = max_t(phys_addr_t, alignment, CMA_MIN_ALIGNMENT_BYTES);
46020089ebdSMike Rapoport (Microsoft) 	if (fixed && base & (alignment - 1)) {
46120089ebdSMike Rapoport (Microsoft) 		pr_err("Region at %pa must be aligned to %pa bytes\n",
46220089ebdSMike Rapoport (Microsoft) 			&base, &alignment);
46320089ebdSMike Rapoport (Microsoft) 		return -EINVAL;
46420089ebdSMike Rapoport (Microsoft) 	}
46520089ebdSMike Rapoport (Microsoft) 	base = ALIGN(base, alignment);
46620089ebdSMike Rapoport (Microsoft) 	size = ALIGN(size, alignment);
46720089ebdSMike Rapoport (Microsoft) 	limit &= ~(alignment - 1);
46820089ebdSMike Rapoport (Microsoft) 
46920089ebdSMike Rapoport (Microsoft) 	if (!base)
47020089ebdSMike Rapoport (Microsoft) 		fixed = false;
47120089ebdSMike Rapoport (Microsoft) 
47220089ebdSMike Rapoport (Microsoft) 	/* size should be aligned with order_per_bit */
47320089ebdSMike Rapoport (Microsoft) 	if (!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit))
47420089ebdSMike Rapoport (Microsoft) 		return -EINVAL;
47520089ebdSMike Rapoport (Microsoft) 
47620089ebdSMike Rapoport (Microsoft) 
47720089ebdSMike Rapoport (Microsoft) 	/*
47820089ebdSMike Rapoport (Microsoft) 	 * If the limit is unspecified or above the memblock end, its effective
47920089ebdSMike Rapoport (Microsoft) 	 * value will be the memblock end. Set it explicitly to simplify further
48020089ebdSMike Rapoport (Microsoft) 	 * checks.
48120089ebdSMike Rapoport (Microsoft) 	 */
48220089ebdSMike Rapoport (Microsoft) 	if (limit == 0 || limit > memblock_end)
48320089ebdSMike Rapoport (Microsoft) 		limit = memblock_end;
48420089ebdSMike Rapoport (Microsoft) 
48520089ebdSMike Rapoport (Microsoft) 	if (base + size > limit) {
48620089ebdSMike Rapoport (Microsoft) 		pr_err("Size (%pa) of region at %pa exceeds limit (%pa)\n",
48720089ebdSMike Rapoport (Microsoft) 			&size, &base, &limit);
48820089ebdSMike Rapoport (Microsoft) 		return -EINVAL;
48920089ebdSMike Rapoport (Microsoft) 	}
49020089ebdSMike Rapoport (Microsoft) 
49120089ebdSMike Rapoport (Microsoft) 	/* Reserve memory */
49220089ebdSMike Rapoport (Microsoft) 	if (fixed) {
493bef58716SMike Rapoport (Microsoft) 		ret = cma_fixed_reserve(base, size);
494bef58716SMike Rapoport (Microsoft) 		if (ret)
495bef58716SMike Rapoport (Microsoft) 			return ret;
49620089ebdSMike Rapoport (Microsoft) 	} else {
4978aa2c0bfSMike Rapoport (Microsoft) 		base = cma_alloc_mem(base, size, alignment, limit, nid);
4988aa2c0bfSMike Rapoport (Microsoft) 		if (!base)
49920089ebdSMike Rapoport (Microsoft) 			return -ENOMEM;
50020089ebdSMike Rapoport (Microsoft) 
50120089ebdSMike Rapoport (Microsoft) 		/*
50220089ebdSMike Rapoport (Microsoft) 		 * kmemleak scans/reads tracked objects for pointers to other
50320089ebdSMike Rapoport (Microsoft) 		 * objects but this address isn't mapped and accessible
50420089ebdSMike Rapoport (Microsoft) 		 */
5058aa2c0bfSMike Rapoport (Microsoft) 		kmemleak_ignore_phys(base);
50620089ebdSMike Rapoport (Microsoft) 	}
50720089ebdSMike Rapoport (Microsoft) 
50820089ebdSMike Rapoport (Microsoft) 	ret = cma_init_reserved_mem(base, size, order_per_bit, name, res_cma);
50920089ebdSMike Rapoport (Microsoft) 	if (ret) {
51020089ebdSMike Rapoport (Microsoft) 		memblock_phys_free(base, size);
51120089ebdSMike Rapoport (Microsoft) 		return ret;
51220089ebdSMike Rapoport (Microsoft) 	}
51320089ebdSMike Rapoport (Microsoft) 
51420089ebdSMike Rapoport (Microsoft) 	(*res_cma)->nid = nid;
51520089ebdSMike Rapoport (Microsoft) 	*basep = base;
51620089ebdSMike Rapoport (Microsoft) 
51720089ebdSMike Rapoport (Microsoft) 	return 0;
51820089ebdSMike Rapoport (Microsoft) }
51920089ebdSMike Rapoport (Microsoft) 
520c009da42SFrank van der Linden /*
521c009da42SFrank van der Linden  * Create CMA areas with a total size of @total_size. A normal allocation
522c009da42SFrank van der Linden  * for one area is tried first. If that fails, the biggest memblock
523c009da42SFrank van der Linden  * ranges above 4G are selected, and allocated bottom up.
524c009da42SFrank van der Linden  *
525c009da42SFrank van der Linden  * The complexity here is not great, but this function will only be
526c009da42SFrank van der Linden  * called during boot, and the lists operated on have fewer than
527c009da42SFrank van der Linden  * CMA_MAX_RANGES elements (default value: 8).
528c009da42SFrank van der Linden  */
cma_declare_contiguous_multi(phys_addr_t total_size,phys_addr_t align,unsigned int order_per_bit,const char * name,struct cma ** res_cma,int nid)529c009da42SFrank van der Linden int __init cma_declare_contiguous_multi(phys_addr_t total_size,
530c009da42SFrank van der Linden 			phys_addr_t align, unsigned int order_per_bit,
531c009da42SFrank van der Linden 			const char *name, struct cma **res_cma, int nid)
532c009da42SFrank van der Linden {
53360580e0bSFrank van der Linden 	phys_addr_t start = 0, end;
534c009da42SFrank van der Linden 	phys_addr_t size, sizesum, sizeleft;
535c009da42SFrank van der Linden 	struct cma_init_memrange *mrp, *mlp, *failed;
536c009da42SFrank van der Linden 	struct cma_memrange *cmrp;
537c009da42SFrank van der Linden 	LIST_HEAD(ranges);
538c009da42SFrank van der Linden 	LIST_HEAD(final_ranges);
539c009da42SFrank van der Linden 	struct list_head *mp, *next;
540c009da42SFrank van der Linden 	int ret, nr = 1;
541c009da42SFrank van der Linden 	u64 i;
542c009da42SFrank van der Linden 	struct cma *cma;
543c009da42SFrank van der Linden 
544c009da42SFrank van der Linden 	/*
545c009da42SFrank van der Linden 	 * First, try it the normal way, producing just one range.
546c009da42SFrank van der Linden 	 */
54760580e0bSFrank van der Linden 	ret = __cma_declare_contiguous_nid(&start, total_size, 0, align,
548c009da42SFrank van der Linden 			order_per_bit, false, name, res_cma, nid);
549c009da42SFrank van der Linden 	if (ret != -ENOMEM)
550c009da42SFrank van der Linden 		goto out;
551c009da42SFrank van der Linden 
552c009da42SFrank van der Linden 	/*
553c009da42SFrank van der Linden 	 * Couldn't find one range that fits our needs, so try multiple
554c009da42SFrank van der Linden 	 * ranges.
555c009da42SFrank van der Linden 	 *
556c009da42SFrank van der Linden 	 * No need to do the alignment checks here, the call to
557c009da42SFrank van der Linden 	 * cma_declare_contiguous_nid above would have caught
558c009da42SFrank van der Linden 	 * any issues. With the checks, we know that:
559c009da42SFrank van der Linden 	 *
560c009da42SFrank van der Linden 	 * - @align is a power of 2
561c009da42SFrank van der Linden 	 * - @align is >= pageblock alignment
562c009da42SFrank van der Linden 	 * - @size is aligned to @align and to @order_per_bit
563c009da42SFrank van der Linden 	 *
564c009da42SFrank van der Linden 	 * So, as long as we create ranges that have a base
565c009da42SFrank van der Linden 	 * aligned to @align, and a size that is aligned to
566c009da42SFrank van der Linden 	 * both @align and @order_to_bit, things will work out.
567c009da42SFrank van der Linden 	 */
568c009da42SFrank van der Linden 	nr = 0;
569c009da42SFrank van der Linden 	sizesum = 0;
570c009da42SFrank van der Linden 	failed = NULL;
571c009da42SFrank van der Linden 
572c009da42SFrank van der Linden 	ret = cma_new_area(name, total_size, order_per_bit, &cma);
573c009da42SFrank van der Linden 	if (ret != 0)
574c009da42SFrank van der Linden 		goto out;
575c009da42SFrank van der Linden 
576c009da42SFrank van der Linden 	align = max_t(phys_addr_t, align, CMA_MIN_ALIGNMENT_BYTES);
577c009da42SFrank van der Linden 	/*
578c009da42SFrank van der Linden 	 * Create a list of ranges above 4G, largest range first.
579c009da42SFrank van der Linden 	 */
580c009da42SFrank van der Linden 	for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &start, &end, NULL) {
581c009da42SFrank van der Linden 		if (upper_32_bits(start) == 0)
582c009da42SFrank van der Linden 			continue;
583c009da42SFrank van der Linden 
584c009da42SFrank van der Linden 		start = ALIGN(start, align);
585c009da42SFrank van der Linden 		if (start >= end)
586c009da42SFrank van der Linden 			continue;
587c009da42SFrank van der Linden 
588c009da42SFrank van der Linden 		end = ALIGN_DOWN(end, align);
589c009da42SFrank van der Linden 		if (end <= start)
590c009da42SFrank van der Linden 			continue;
591c009da42SFrank van der Linden 
592c009da42SFrank van der Linden 		size = end - start;
593c009da42SFrank van der Linden 		size = ALIGN_DOWN(size, (PAGE_SIZE << order_per_bit));
594c009da42SFrank van der Linden 		if (!size)
595c009da42SFrank van der Linden 			continue;
596c009da42SFrank van der Linden 		sizesum += size;
597c009da42SFrank van der Linden 
598c009da42SFrank van der Linden 		pr_debug("consider %016llx - %016llx\n", (u64)start, (u64)end);
599c009da42SFrank van der Linden 
600c009da42SFrank van der Linden 		/*
601c009da42SFrank van der Linden 		 * If we don't yet have used the maximum number of
602c009da42SFrank van der Linden 		 * areas, grab a new one.
603c009da42SFrank van der Linden 		 *
604c009da42SFrank van der Linden 		 * If we can't use anymore, see if this range is not
605c009da42SFrank van der Linden 		 * smaller than the smallest one already recorded. If
606c009da42SFrank van der Linden 		 * not, re-use the smallest element.
607c009da42SFrank van der Linden 		 */
608c009da42SFrank van der Linden 		if (nr < CMA_MAX_RANGES)
609c009da42SFrank van der Linden 			mrp = &memranges[nr++];
610c009da42SFrank van der Linden 		else {
611c009da42SFrank van der Linden 			mrp = list_last_entry(&ranges,
612c009da42SFrank van der Linden 					      struct cma_init_memrange, list);
613c009da42SFrank van der Linden 			if (size < mrp->size)
614c009da42SFrank van der Linden 				continue;
615c009da42SFrank van der Linden 			list_del(&mrp->list);
616c009da42SFrank van der Linden 			sizesum -= mrp->size;
617c009da42SFrank van der Linden 			pr_debug("deleted %016llx - %016llx from the list\n",
618c009da42SFrank van der Linden 				(u64)mrp->base, (u64)mrp->base + size);
619c009da42SFrank van der Linden 		}
620c009da42SFrank van der Linden 		mrp->base = start;
621c009da42SFrank van der Linden 		mrp->size = size;
622c009da42SFrank van der Linden 
623c009da42SFrank van der Linden 		/*
624c009da42SFrank van der Linden 		 * Now do a sorted insert.
625c009da42SFrank van der Linden 		 */
626c009da42SFrank van der Linden 		list_insert_sorted(&ranges, mrp, revsizecmp);
627c009da42SFrank van der Linden 		pr_debug("added %016llx - %016llx to the list\n",
628c009da42SFrank van der Linden 		    (u64)mrp->base, (u64)mrp->base + size);
629c009da42SFrank van der Linden 		pr_debug("total size now %llu\n", (u64)sizesum);
630c009da42SFrank van der Linden 	}
631c009da42SFrank van der Linden 
632c009da42SFrank van der Linden 	/*
633c009da42SFrank van der Linden 	 * There is not enough room in the CMA_MAX_RANGES largest
634c009da42SFrank van der Linden 	 * ranges, so bail out.
635c009da42SFrank van der Linden 	 */
636c009da42SFrank van der Linden 	if (sizesum < total_size) {
637c009da42SFrank van der Linden 		cma_drop_area(cma);
638c009da42SFrank van der Linden 		ret = -ENOMEM;
639c009da42SFrank van der Linden 		goto out;
640c009da42SFrank van der Linden 	}
641c009da42SFrank van der Linden 
642c009da42SFrank van der Linden 	/*
643c009da42SFrank van der Linden 	 * Found ranges that provide enough combined space.
644c009da42SFrank van der Linden 	 * Now, sorted them by address, smallest first, because we
645c009da42SFrank van der Linden 	 * want to mimic a bottom-up memblock allocation.
646c009da42SFrank van der Linden 	 */
647c009da42SFrank van der Linden 	sizesum = 0;
648c009da42SFrank van der Linden 	list_for_each_safe(mp, next, &ranges) {
649c009da42SFrank van der Linden 		mlp = list_entry(mp, struct cma_init_memrange, list);
650c009da42SFrank van der Linden 		list_del(mp);
651c009da42SFrank van der Linden 		list_insert_sorted(&final_ranges, mlp, basecmp);
652c009da42SFrank van der Linden 		sizesum += mlp->size;
653c009da42SFrank van der Linden 		if (sizesum >= total_size)
654c009da42SFrank van der Linden 			break;
655c009da42SFrank van der Linden 	}
656c009da42SFrank van der Linden 
657c009da42SFrank van der Linden 	/*
658c009da42SFrank van der Linden 	 * Walk the final list, and add a CMA range for
659c009da42SFrank van der Linden 	 * each range, possibly not using the last one fully.
660c009da42SFrank van der Linden 	 */
661c009da42SFrank van der Linden 	nr = 0;
662c009da42SFrank van der Linden 	sizeleft = total_size;
663c009da42SFrank van der Linden 	list_for_each(mp, &final_ranges) {
664c009da42SFrank van der Linden 		mlp = list_entry(mp, struct cma_init_memrange, list);
665c009da42SFrank van der Linden 		size = min(sizeleft, mlp->size);
666c009da42SFrank van der Linden 		if (memblock_reserve(mlp->base, size)) {
667c009da42SFrank van der Linden 			/*
668c009da42SFrank van der Linden 			 * Unexpected error. Could go on to
669c009da42SFrank van der Linden 			 * the next one, but just abort to
670c009da42SFrank van der Linden 			 * be safe.
671c009da42SFrank van der Linden 			 */
672c009da42SFrank van der Linden 			failed = mlp;
673c009da42SFrank van der Linden 			break;
674c009da42SFrank van der Linden 		}
675c009da42SFrank van der Linden 
676c009da42SFrank van der Linden 		pr_debug("created region %d: %016llx - %016llx\n",
677c009da42SFrank van der Linden 		    nr, (u64)mlp->base, (u64)mlp->base + size);
678c009da42SFrank van der Linden 		cmrp = &cma->ranges[nr++];
679c009da42SFrank van der Linden 		cmrp->base_pfn = PHYS_PFN(mlp->base);
68085abcd02SFrank van der Linden 		cmrp->early_pfn = cmrp->base_pfn;
681c009da42SFrank van der Linden 		cmrp->count = size >> PAGE_SHIFT;
682c009da42SFrank van der Linden 
683c009da42SFrank van der Linden 		sizeleft -= size;
684c009da42SFrank van der Linden 		if (sizeleft == 0)
685c009da42SFrank van der Linden 			break;
686c009da42SFrank van der Linden 	}
687c009da42SFrank van der Linden 
688c009da42SFrank van der Linden 	if (failed) {
689c009da42SFrank van der Linden 		list_for_each(mp, &final_ranges) {
690c009da42SFrank van der Linden 			mlp = list_entry(mp, struct cma_init_memrange, list);
691c009da42SFrank van der Linden 			if (mlp == failed)
692c009da42SFrank van der Linden 				break;
693c009da42SFrank van der Linden 			memblock_phys_free(mlp->base, mlp->size);
694c009da42SFrank van der Linden 		}
695c009da42SFrank van der Linden 		cma_drop_area(cma);
696c009da42SFrank van der Linden 		ret = -ENOMEM;
697c009da42SFrank van der Linden 		goto out;
698c009da42SFrank van der Linden 	}
699c009da42SFrank van der Linden 
700c009da42SFrank van der Linden 	cma->nranges = nr;
701b51d3db9SFrank van der Linden 	cma->nid = nid;
702c009da42SFrank van der Linden 	*res_cma = cma;
703c009da42SFrank van der Linden 
704c009da42SFrank van der Linden out:
705c009da42SFrank van der Linden 	if (ret != 0)
706c009da42SFrank van der Linden 		pr_err("Failed to reserve %lu MiB\n",
707c009da42SFrank van der Linden 			(unsigned long)total_size / SZ_1M);
708c009da42SFrank van der Linden 	else
709c009da42SFrank van der Linden 		pr_info("Reserved %lu MiB in %d range%s\n",
71011f45931SThorsten Blum 			(unsigned long)total_size / SZ_1M, nr, str_plural(nr));
711c009da42SFrank van der Linden 	return ret;
712c009da42SFrank van der Linden }
713c009da42SFrank van der Linden 
714de9e14eeSMarek Szyprowski /**
7158676af1fSAslan Bakirov  * cma_declare_contiguous_nid() - reserve custom contiguous area
716a254129eSJoonsoo Kim  * @base: Base address of the reserved area optional, use 0 for any
717c1f733aaSJoonsoo Kim  * @size: Size of the reserved area (in bytes),
718a254129eSJoonsoo Kim  * @limit: End address of the reserved memory (optional, 0 for any).
719a254129eSJoonsoo Kim  * @alignment: Alignment for the CMA area, should be power of 2 or zero
720a254129eSJoonsoo Kim  * @order_per_bit: Order of pages represented by one bit on bitmap.
721a254129eSJoonsoo Kim  * @fixed: hint about where to place the reserved area
722e8b098fcSMike Rapoport  * @name: The name of the area. See function cma_init_reserved_mem()
723c1f733aaSJoonsoo Kim  * @res_cma: Pointer to store the created cma region.
7248676af1fSAslan Bakirov  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
725a254129eSJoonsoo Kim  *
726a254129eSJoonsoo Kim  * This function reserves memory from early allocator. It should be
727a254129eSJoonsoo Kim  * called by arch specific code once the early allocator (memblock or bootmem)
728a254129eSJoonsoo Kim  * has been activated and all other subsystems have already allocated/reserved
729a254129eSJoonsoo Kim  * memory. This function allows to create custom reserved areas.
730a254129eSJoonsoo Kim  *
731a254129eSJoonsoo Kim  * If @fixed is true, reserve contiguous area at exactly @base.  If false,
732a254129eSJoonsoo Kim  * reserve in range from @base to @limit.
733a254129eSJoonsoo Kim  */
cma_declare_contiguous_nid(phys_addr_t base,phys_addr_t size,phys_addr_t limit,phys_addr_t alignment,unsigned int order_per_bit,bool fixed,const char * name,struct cma ** res_cma,int nid)7348676af1fSAslan Bakirov int __init cma_declare_contiguous_nid(phys_addr_t base,
735c1f733aaSJoonsoo Kim 			phys_addr_t size, phys_addr_t limit,
736a254129eSJoonsoo Kim 			phys_addr_t alignment, unsigned int order_per_bit,
7378676af1fSAslan Bakirov 			bool fixed, const char *name, struct cma **res_cma,
7388676af1fSAslan Bakirov 			int nid)
739a254129eSJoonsoo Kim {
740c009da42SFrank van der Linden 	int ret;
741c009da42SFrank van der Linden 
74260580e0bSFrank van der Linden 	ret = __cma_declare_contiguous_nid(&base, size, limit, alignment,
743c009da42SFrank van der Linden 			order_per_bit, fixed, name, res_cma, nid);
744c009da42SFrank van der Linden 	if (ret != 0)
745c009da42SFrank van der Linden 		pr_err("Failed to reserve %ld MiB\n",
746c009da42SFrank van der Linden 				(unsigned long)size / SZ_1M);
747c009da42SFrank van der Linden 	else
748c009da42SFrank van der Linden 		pr_info("Reserved %ld MiB at %pa\n",
749c009da42SFrank van der Linden 				(unsigned long)size / SZ_1M, &base);
750c009da42SFrank van der Linden 
751c009da42SFrank van der Linden 	return ret;
752c009da42SFrank van der Linden }
753c009da42SFrank van der Linden 
cma_debug_show_areas(struct cma * cma)754dbe43d4dSJaewon Kim static void cma_debug_show_areas(struct cma *cma)
755dbe43d4dSJaewon Kim {
75677c50f91SYury Norov (NVIDIA) 	unsigned long start, end;
7577365ff2cSFrank van der Linden 	unsigned long nr_part;
758c009da42SFrank van der Linden 	unsigned long nbits;
759c009da42SFrank van der Linden 	int r;
760c009da42SFrank van der Linden 	struct cma_memrange *cmr;
761dbe43d4dSJaewon Kim 
7620ef7dcacSMike Kravetz 	spin_lock_irq(&cma->lock);
763dbe43d4dSJaewon Kim 	pr_info("number of available pages: ");
764c009da42SFrank van der Linden 	for (r = 0; r < cma->nranges; r++) {
765c009da42SFrank van der Linden 		cmr = &cma->ranges[r];
766c009da42SFrank van der Linden 
767c009da42SFrank van der Linden 		nbits = cma_bitmap_maxno(cma, cmr);
768c009da42SFrank van der Linden 
769c009da42SFrank van der Linden 		pr_info("range %d: ", r);
77077c50f91SYury Norov (NVIDIA) 		for_each_clear_bitrange(start, end, cmr->bitmap, nbits) {
77177c50f91SYury Norov (NVIDIA) 			nr_part = (end - start) << cma->order_per_bit;
77277c50f91SYury Norov (NVIDIA) 			pr_cont("%s%lu@%lu", start ? "+" : "", nr_part, start);
773dbe43d4dSJaewon Kim 		}
774c009da42SFrank van der Linden 		pr_info("\n");
775c009da42SFrank van der Linden 	}
7767365ff2cSFrank van der Linden 	pr_cont("=> %lu free of %lu total pages\n", cma->available_count,
7777365ff2cSFrank van der Linden 			cma->count);
7780ef7dcacSMike Kravetz 	spin_unlock_irq(&cma->lock);
779dbe43d4dSJaewon Kim }
780dbe43d4dSJaewon Kim 
cma_range_alloc(struct cma * cma,struct cma_memrange * cmr,unsigned long count,unsigned int align,struct page ** pagep,gfp_t gfp)781c009da42SFrank van der Linden static int cma_range_alloc(struct cma *cma, struct cma_memrange *cmr,
782c009da42SFrank van der Linden 				unsigned long count, unsigned int align,
783c009da42SFrank van der Linden 				struct page **pagep, gfp_t gfp)
784a254129eSJoonsoo Kim {
785a254129eSJoonsoo Kim 	unsigned long bitmap_maxno, bitmap_no, bitmap_count;
7866972706fSDavid Hildenbrand 	unsigned long start, pfn, mask, offset;
787c009da42SFrank van der Linden 	int ret = -EBUSY;
788a254129eSJoonsoo Kim 	struct page *page = NULL;
789a254129eSJoonsoo Kim 
790a254129eSJoonsoo Kim 	mask = cma_bitmap_aligned_mask(cma, align);
791c009da42SFrank van der Linden 	offset = cma_bitmap_aligned_offset(cma, cmr, align);
792c009da42SFrank van der Linden 	bitmap_maxno = cma_bitmap_maxno(cma, cmr);
793a254129eSJoonsoo Kim 	bitmap_count = cma_bitmap_pages_to_bits(cma, count);
794a254129eSJoonsoo Kim 
7956b36ba59SShiraz Hashim 	if (bitmap_count > bitmap_maxno)
796c009da42SFrank van der Linden 		goto out;
7976b36ba59SShiraz Hashim 
7986972706fSDavid Hildenbrand 	for (start = 0; ; start = bitmap_no + mask + 1) {
7990ef7dcacSMike Kravetz 		spin_lock_irq(&cma->lock);
8007365ff2cSFrank van der Linden 		/*
8017365ff2cSFrank van der Linden 		 * If the request is larger than the available number
8027365ff2cSFrank van der Linden 		 * of pages, stop right away.
8037365ff2cSFrank van der Linden 		 */
8047365ff2cSFrank van der Linden 		if (count > cma->available_count) {
8057365ff2cSFrank van der Linden 			spin_unlock_irq(&cma->lock);
8067365ff2cSFrank van der Linden 			break;
8077365ff2cSFrank van der Linden 		}
808c009da42SFrank van der Linden 		bitmap_no = bitmap_find_next_zero_area_off(cmr->bitmap,
809b5be83e3SGregory Fong 				bitmap_maxno, start, bitmap_count, mask,
810b5be83e3SGregory Fong 				offset);
811a254129eSJoonsoo Kim 		if (bitmap_no >= bitmap_maxno) {
8120ef7dcacSMike Kravetz 			spin_unlock_irq(&cma->lock);
813a254129eSJoonsoo Kim 			break;
814a254129eSJoonsoo Kim 		}
8156972706fSDavid Hildenbrand 
8166972706fSDavid Hildenbrand 		pfn = cmr->base_pfn + (bitmap_no << cma->order_per_bit);
8176972706fSDavid Hildenbrand 		page = pfn_to_page(pfn);
8186972706fSDavid Hildenbrand 
8196972706fSDavid Hildenbrand 		/*
8206972706fSDavid Hildenbrand 		 * Do not hand out page ranges that are not contiguous, so
8216972706fSDavid Hildenbrand 		 * callers can just iterate the pages without having to worry
8226972706fSDavid Hildenbrand 		 * about these corner cases.
8236972706fSDavid Hildenbrand 		 */
8246972706fSDavid Hildenbrand 		if (!page_range_contiguous(page, count)) {
8256972706fSDavid Hildenbrand 			spin_unlock_irq(&cma->lock);
8266972706fSDavid Hildenbrand 			pr_warn_ratelimited("%s: %s: skipping incompatible area [0x%lx-0x%lx]",
8276972706fSDavid Hildenbrand 					    __func__, cma->name, pfn, pfn + count - 1);
8286972706fSDavid Hildenbrand 			continue;
8296972706fSDavid Hildenbrand 		}
8306972706fSDavid Hildenbrand 
831c009da42SFrank van der Linden 		bitmap_set(cmr->bitmap, bitmap_no, bitmap_count);
8327365ff2cSFrank van der Linden 		cma->available_count -= count;
833a254129eSJoonsoo Kim 		/*
834a254129eSJoonsoo Kim 		 * It's safe to drop the lock here. We've marked this region for
835a254129eSJoonsoo Kim 		 * our exclusive use. If the migration fails we will take the
836a254129eSJoonsoo Kim 		 * lock again and unmark it.
837a254129eSJoonsoo Kim 		 */
8380ef7dcacSMike Kravetz 		spin_unlock_irq(&cma->lock);
839a254129eSJoonsoo Kim 
84024ac6fb6SGe Yang 		mutex_lock(&cma->alloc_mutex);
841e0c13267SKefeng Wang 		ret = alloc_contig_frozen_range(pfn, pfn + count, ACR_FLAGS_CMA, gfp);
84224ac6fb6SGe Yang 		mutex_unlock(&cma->alloc_mutex);
8436972706fSDavid Hildenbrand 		if (!ret)
844a254129eSJoonsoo Kim 			break;
845b7155e76SJoonsoo Kim 
846c009da42SFrank van der Linden 		cma_clear_bitmap(cma, cmr, pfn, count);
847b7155e76SJoonsoo Kim 		if (ret != -EBUSY)
848b7155e76SJoonsoo Kim 			break;
849b7155e76SJoonsoo Kim 
850399fd496SKassey Li 		pr_debug("%s(): memory range at pfn 0x%lx %p is busy, retrying\n",
8516972706fSDavid Hildenbrand 			 __func__, pfn, page);
8527bc1aec5SLiam Mark 
8536972706fSDavid Hildenbrand 		trace_cma_alloc_busy_retry(cma->name, pfn, page, count, align);
854a254129eSJoonsoo Kim 	}
855c009da42SFrank van der Linden out:
8566972706fSDavid Hildenbrand 	if (!ret)
857c009da42SFrank van der Linden 		*pagep = page;
858c009da42SFrank van der Linden 	return ret;
859c009da42SFrank van der Linden }
860c009da42SFrank van der Linden 
__cma_alloc_frozen(struct cma * cma,unsigned long count,unsigned int align,gfp_t gfp)8619bda131cSKefeng Wang static struct page *__cma_alloc_frozen(struct cma *cma,
8629bda131cSKefeng Wang 		unsigned long count, unsigned int align, gfp_t gfp)
863c009da42SFrank van der Linden {
864c009da42SFrank van der Linden 	struct page *page = NULL;
865c009da42SFrank van der Linden 	int ret = -ENOMEM, r;
866c009da42SFrank van der Linden 	unsigned long i;
867c009da42SFrank van der Linden 	const char *name = cma ? cma->name : NULL;
868c009da42SFrank van der Linden 
869c009da42SFrank van der Linden 	if (!cma || !cma->count)
870c009da42SFrank van der Linden 		return page;
871c009da42SFrank van der Linden 
872c009da42SFrank van der Linden 	pr_debug("%s(cma %p, name: %s, count %lu, align %d)\n", __func__,
873c009da42SFrank van der Linden 		(void *)cma, cma->name, count, align);
874c009da42SFrank van der Linden 
875c009da42SFrank van der Linden 	if (!count)
876c009da42SFrank van der Linden 		return page;
877c009da42SFrank van der Linden 
8780cd01c4aSgaoxiang17 	trace_cma_alloc_start(name, count, cma->available_count, cma->count, align);
87908e21e24SRichard Chang 
880c009da42SFrank van der Linden 	for (r = 0; r < cma->nranges; r++) {
881c009da42SFrank van der Linden 		page = NULL;
882c009da42SFrank van der Linden 
883c009da42SFrank van der Linden 		ret = cma_range_alloc(cma, &cma->ranges[r], count, align,
884c009da42SFrank van der Linden 				       &page, gfp);
885c009da42SFrank van der Linden 		if (ret != -EBUSY || page)
886c009da42SFrank van der Linden 			break;
887c009da42SFrank van der Linden 	}
888a254129eSJoonsoo Kim 
8892813b9c0SAndrey Konovalov 	/*
8902813b9c0SAndrey Konovalov 	 * CMA can allocate multiple page blocks, which results in different
8912813b9c0SAndrey Konovalov 	 * blocks being marked with different tags. Reset the tags to ignore
8922813b9c0SAndrey Konovalov 	 * those page blocks.
8932813b9c0SAndrey Konovalov 	 */
8942813b9c0SAndrey Konovalov 	if (page) {
8952813b9c0SAndrey Konovalov 		for (i = 0; i < count; i++)
8966972706fSDavid Hildenbrand 			page_kasan_tag_reset(page + i);
8972813b9c0SAndrey Konovalov 	}
8982813b9c0SAndrey Konovalov 
899463586e9SYu Zhao 	if (ret && !(gfp & __GFP_NOWARN)) {
90078fa5150SMinchan Kim 		pr_err_ratelimited("%s: %s: alloc failed, req-size: %lu pages, ret: %d\n",
901a052d4d1SPatrick Daly 				   __func__, cma->name, count, ret);
902dbe43d4dSJaewon Kim 		cma_debug_show_areas(cma);
903dbe43d4dSJaewon Kim 	}
904dbe43d4dSJaewon Kim 
905a254129eSJoonsoo Kim 	pr_debug("%s(): returned %p\n", __func__, page);
906c009da42SFrank van der Linden 	trace_cma_alloc_finish(name, page ? page_to_pfn(page) : 0,
907c009da42SFrank van der Linden 			       page, count, align, ret);
90843ca106fSMinchan Kim 	if (page) {
909bbb26920SMinchan Kim 		count_vm_event(CMA_ALLOC_SUCCESS);
91043ca106fSMinchan Kim 		cma_sysfs_account_success_pages(cma, count);
91143ca106fSMinchan Kim 	} else {
912bbb26920SMinchan Kim 		count_vm_event(CMA_ALLOC_FAIL);
91343ca106fSMinchan Kim 		cma_sysfs_account_fail_pages(cma, count);
91443ca106fSMinchan Kim 	}
915bbb26920SMinchan Kim 
916a254129eSJoonsoo Kim 	return page;
917a254129eSJoonsoo Kim }
918a254129eSJoonsoo Kim 
cma_alloc_frozen(struct cma * cma,unsigned long count,unsigned int align,bool no_warn)9199bda131cSKefeng Wang struct page *cma_alloc_frozen(struct cma *cma, unsigned long count,
9209bda131cSKefeng Wang 		unsigned int align, bool no_warn)
9219bda131cSKefeng Wang {
9229bda131cSKefeng Wang 	gfp_t gfp = GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0);
9239bda131cSKefeng Wang 
9249bda131cSKefeng Wang 	return __cma_alloc_frozen(cma, count, align, gfp);
9259bda131cSKefeng Wang }
9269bda131cSKefeng Wang 
cma_alloc_frozen_compound(struct cma * cma,unsigned int order)9279bda131cSKefeng Wang struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order)
9289bda131cSKefeng Wang {
9299bda131cSKefeng Wang 	gfp_t gfp = GFP_KERNEL | __GFP_COMP | __GFP_NOWARN;
9309bda131cSKefeng Wang 
9319bda131cSKefeng Wang 	return __cma_alloc_frozen(cma, 1 << order, order, gfp);
9329bda131cSKefeng Wang }
9339bda131cSKefeng Wang 
934463586e9SYu Zhao /**
935463586e9SYu Zhao  * cma_alloc() - allocate pages from contiguous area
936463586e9SYu Zhao  * @cma:   Contiguous memory region for which the allocation is performed.
937463586e9SYu Zhao  * @count: Requested number of pages.
938463586e9SYu Zhao  * @align: Requested alignment of pages (in PAGE_SIZE order).
939463586e9SYu Zhao  * @no_warn: Avoid printing message about failed allocation
940463586e9SYu Zhao  *
941463586e9SYu Zhao  * This function allocates part of contiguous memory on specific
942463586e9SYu Zhao  * contiguous memory area.
943463586e9SYu Zhao  */
cma_alloc(struct cma * cma,unsigned long count,unsigned int align,bool no_warn)944463586e9SYu Zhao struct page *cma_alloc(struct cma *cma, unsigned long count,
945463586e9SYu Zhao 		       unsigned int align, bool no_warn)
946463586e9SYu Zhao {
947463586e9SYu Zhao 	struct page *page;
948463586e9SYu Zhao 
9499bda131cSKefeng Wang 	page = cma_alloc_frozen(cma, count, align, no_warn);
9509bda131cSKefeng Wang 	if (page)
9519bda131cSKefeng Wang 		set_pages_refcounted(page, count);
952463586e9SYu Zhao 
9539bda131cSKefeng Wang 	return page;
954463586e9SYu Zhao }
955*7e72a8f8SMaxime Ripard EXPORT_SYMBOL_GPL(cma_alloc);
956463586e9SYu Zhao 
find_cma_memrange(struct cma * cma,const struct page * pages,unsigned long count)9579bda131cSKefeng Wang static struct cma_memrange *find_cma_memrange(struct cma *cma,
9589bda131cSKefeng Wang 		const struct page *pages, unsigned long count)
959a254129eSJoonsoo Kim {
9609bda131cSKefeng Wang 	struct cma_memrange *cmr = NULL;
961c009da42SFrank van der Linden 	unsigned long pfn, end_pfn;
962c009da42SFrank van der Linden 	int r;
963c009da42SFrank van der Linden 
964c009da42SFrank van der Linden 	pr_debug("%s(page %p, count %lu)\n", __func__, (void *)pages, count);
965a254129eSJoonsoo Kim 
9666c08cc64SKefeng Wang 	if (!cma || !pages || count > cma->count)
9679bda131cSKefeng Wang 		return NULL;
968a254129eSJoonsoo Kim 
969a254129eSJoonsoo Kim 	pfn = page_to_pfn(pages);
970a254129eSJoonsoo Kim 
971c009da42SFrank van der Linden 	for (r = 0; r < cma->nranges; r++) {
972c009da42SFrank van der Linden 		cmr = &cma->ranges[r];
9736c08cc64SKefeng Wang 		end_pfn = cmr->base_pfn + cmr->count;
9746c08cc64SKefeng Wang 		if (pfn >= cmr->base_pfn && pfn < end_pfn) {
9756c08cc64SKefeng Wang 			if (pfn + count <= end_pfn)
976c009da42SFrank van der Linden 				break;
9776c08cc64SKefeng Wang 
9786c08cc64SKefeng Wang 			VM_WARN_ON_ONCE(1);
979c009da42SFrank van der Linden 		}
980c009da42SFrank van der Linden 	}
981c009da42SFrank van der Linden 
9826c08cc64SKefeng Wang 	if (r == cma->nranges) {
9836c08cc64SKefeng Wang 		pr_debug("%s(page %p, count %lu, no cma range matches the page range)\n",
9846c08cc64SKefeng Wang 			 __func__, (void *)pages, count);
9859bda131cSKefeng Wang 		return NULL;
9866c08cc64SKefeng Wang 	}
987a254129eSJoonsoo Kim 
9889bda131cSKefeng Wang 	return cmr;
9899bda131cSKefeng Wang }
990e0c13267SKefeng Wang 
__cma_release_frozen(struct cma * cma,struct cma_memrange * cmr,const struct page * pages,unsigned long count)9919bda131cSKefeng Wang static void __cma_release_frozen(struct cma *cma, struct cma_memrange *cmr,
9929bda131cSKefeng Wang 		const struct page *pages, unsigned long count)
9939bda131cSKefeng Wang {
9949bda131cSKefeng Wang 	unsigned long pfn = page_to_pfn(pages);
9959bda131cSKefeng Wang 
9969bda131cSKefeng Wang 	pr_debug("%s(page %p, count %lu)\n", __func__, (void *)pages, count);
9979bda131cSKefeng Wang 
9989bda131cSKefeng Wang 	free_contig_frozen_range(pfn, count);
999c009da42SFrank van der Linden 	cma_clear_bitmap(cma, cmr, pfn, count);
1000b9ad003aSAnshuman Khandual 	cma_sysfs_account_release_pages(cma, count);
10013aab8ae7SMinchan Kim 	trace_cma_release(cma->name, pfn, pages, count);
10029bda131cSKefeng Wang }
10039bda131cSKefeng Wang 
10049bda131cSKefeng Wang /**
10059bda131cSKefeng Wang  * cma_release() - release allocated pages
10069bda131cSKefeng Wang  * @cma:   Contiguous memory region for which the allocation is performed.
10079bda131cSKefeng Wang  * @pages: Allocated pages.
10089bda131cSKefeng Wang  * @count: Number of allocated pages.
10099bda131cSKefeng Wang  *
10109bda131cSKefeng Wang  * This function releases memory allocated by cma_alloc().
10119bda131cSKefeng Wang  * It returns false when provided pages do not belong to contiguous area and
10129bda131cSKefeng Wang  * true otherwise.
10139bda131cSKefeng Wang  */
cma_release(struct cma * cma,const struct page * pages,unsigned long count)10149bda131cSKefeng Wang bool cma_release(struct cma *cma, const struct page *pages,
10159bda131cSKefeng Wang 		 unsigned long count)
10169bda131cSKefeng Wang {
10179bda131cSKefeng Wang 	struct cma_memrange *cmr;
1018f4355d6bSZi Yan 	unsigned long ret = 0;
10199bda131cSKefeng Wang 	unsigned long i, pfn;
10209bda131cSKefeng Wang 
10219bda131cSKefeng Wang 	cmr = find_cma_memrange(cma, pages, count);
10229bda131cSKefeng Wang 	if (!cmr)
10239bda131cSKefeng Wang 		return false;
10249bda131cSKefeng Wang 
10259bda131cSKefeng Wang 	pfn = page_to_pfn(pages);
10269bda131cSKefeng Wang 	for (i = 0; i < count; i++, pfn++)
1027f4355d6bSZi Yan 		ret += !put_page_testzero(pfn_to_page(pfn));
1028f4355d6bSZi Yan 
1029f4355d6bSZi Yan 	WARN(ret, "%lu pages are still in use!\n", ret);
10309bda131cSKefeng Wang 
10319bda131cSKefeng Wang 	__cma_release_frozen(cma, cmr, pages, count);
1032a254129eSJoonsoo Kim 
1033a254129eSJoonsoo Kim 	return true;
1034a254129eSJoonsoo Kim }
1035*7e72a8f8SMaxime Ripard EXPORT_SYMBOL_GPL(cma_release);
1036e4231bcdSLaura Abbott 
cma_release_frozen(struct cma * cma,const struct page * pages,unsigned long count)10379bda131cSKefeng Wang bool cma_release_frozen(struct cma *cma, const struct page *pages,
10389bda131cSKefeng Wang 		unsigned long count)
1039463586e9SYu Zhao {
10409bda131cSKefeng Wang 	struct cma_memrange *cmr;
10419bda131cSKefeng Wang 
10429bda131cSKefeng Wang 	cmr = find_cma_memrange(cma, pages, count);
10439bda131cSKefeng Wang 	if (!cmr)
1044463586e9SYu Zhao 		return false;
1045463586e9SYu Zhao 
10469bda131cSKefeng Wang 	__cma_release_frozen(cma, cmr, pages, count);
10479bda131cSKefeng Wang 
10489bda131cSKefeng Wang 	return true;
1049463586e9SYu Zhao }
1050463586e9SYu Zhao 
cma_for_each_area(int (* it)(struct cma * cma,void * data),void * data)1051e4231bcdSLaura Abbott int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
1052e4231bcdSLaura Abbott {
1053e4231bcdSLaura Abbott 	int i;
1054e4231bcdSLaura Abbott 
1055e4231bcdSLaura Abbott 	for (i = 0; i < cma_area_count; i++) {
1056e4231bcdSLaura Abbott 		int ret = it(&cma_areas[i], data);
1057e4231bcdSLaura Abbott 
1058e4231bcdSLaura Abbott 		if (ret)
1059e4231bcdSLaura Abbott 			return ret;
1060e4231bcdSLaura Abbott 	}
1061e4231bcdSLaura Abbott 
1062e4231bcdSLaura Abbott 	return 0;
1063e4231bcdSLaura Abbott }
1064624ab90bSFrank van der Linden 
cma_intersects(struct cma * cma,unsigned long start,unsigned long end)1065624ab90bSFrank van der Linden bool cma_intersects(struct cma *cma, unsigned long start, unsigned long end)
1066624ab90bSFrank van der Linden {
1067624ab90bSFrank van der Linden 	int r;
1068624ab90bSFrank van der Linden 	struct cma_memrange *cmr;
1069624ab90bSFrank van der Linden 	unsigned long rstart, rend;
1070624ab90bSFrank van der Linden 
1071624ab90bSFrank van der Linden 	for (r = 0; r < cma->nranges; r++) {
1072624ab90bSFrank van der Linden 		cmr = &cma->ranges[r];
1073624ab90bSFrank van der Linden 
1074624ab90bSFrank van der Linden 		rstart = PFN_PHYS(cmr->base_pfn);
1075624ab90bSFrank van der Linden 		rend = PFN_PHYS(cmr->base_pfn + cmr->count);
1076624ab90bSFrank van der Linden 		if (end < rstart)
1077624ab90bSFrank van der Linden 			continue;
1078624ab90bSFrank van der Linden 		if (start >= rend)
1079624ab90bSFrank van der Linden 			continue;
1080624ab90bSFrank van der Linden 		return true;
1081624ab90bSFrank van der Linden 	}
1082624ab90bSFrank van der Linden 
1083624ab90bSFrank van der Linden 	return false;
1084624ab90bSFrank van der Linden }
108585abcd02SFrank van der Linden 
108685abcd02SFrank van der Linden /*
108785abcd02SFrank van der Linden  * Very basic function to reserve memory from a CMA area that has not
108885abcd02SFrank van der Linden  * yet been activated. This is expected to be called early, when the
108985abcd02SFrank van der Linden  * system is single-threaded, so there is no locking. The alignment
109085abcd02SFrank van der Linden  * checking is restrictive - only pageblock-aligned areas
109185abcd02SFrank van der Linden  * (CMA_MIN_ALIGNMENT_BYTES) may be reserved through this function.
109285abcd02SFrank van der Linden  * This keeps things simple, and is enough for the current use case.
109385abcd02SFrank van der Linden  *
109485abcd02SFrank van der Linden  * The CMA bitmaps have not yet been allocated, so just start
109585abcd02SFrank van der Linden  * reserving from the bottom up, using a PFN to keep track
109685abcd02SFrank van der Linden  * of what has been reserved. Unreserving is not possible.
109785abcd02SFrank van der Linden  *
109885abcd02SFrank van der Linden  * The caller is responsible for initializing the page structures
109985abcd02SFrank van der Linden  * in the area properly, since this just points to memblock-allocated
110085abcd02SFrank van der Linden  * memory. The caller should subsequently use init_cma_pageblock to
110185abcd02SFrank van der Linden  * set the migrate type and CMA stats  the pageblocks that were reserved.
110285abcd02SFrank van der Linden  *
110385abcd02SFrank van der Linden  * If the CMA area fails to activate later, memory obtained through
110485abcd02SFrank van der Linden  * this interface is not handed to the page allocator, this is
110585abcd02SFrank van der Linden  * the responsibility of the caller (e.g. like normal memblock-allocated
110685abcd02SFrank van der Linden  * memory).
110785abcd02SFrank van der Linden  */
cma_reserve_early(struct cma * cma,unsigned long size)110885abcd02SFrank van der Linden void __init *cma_reserve_early(struct cma *cma, unsigned long size)
110985abcd02SFrank van der Linden {
111085abcd02SFrank van der Linden 	int r;
111185abcd02SFrank van der Linden 	struct cma_memrange *cmr;
111285abcd02SFrank van der Linden 	unsigned long available;
111385abcd02SFrank van der Linden 	void *ret = NULL;
111485abcd02SFrank van der Linden 
111585abcd02SFrank van der Linden 	if (!cma || !cma->count)
111685abcd02SFrank van der Linden 		return NULL;
111785abcd02SFrank van der Linden 	/*
111885abcd02SFrank van der Linden 	 * Can only be called early in init.
111985abcd02SFrank van der Linden 	 */
112085abcd02SFrank van der Linden 	if (test_bit(CMA_ACTIVATED, &cma->flags))
112185abcd02SFrank van der Linden 		return NULL;
112285abcd02SFrank van der Linden 
112385abcd02SFrank van der Linden 	if (!IS_ALIGNED(size, CMA_MIN_ALIGNMENT_BYTES))
112485abcd02SFrank van der Linden 		return NULL;
112585abcd02SFrank van der Linden 
112685abcd02SFrank van der Linden 	if (!IS_ALIGNED(size, (PAGE_SIZE << cma->order_per_bit)))
112785abcd02SFrank van der Linden 		return NULL;
112885abcd02SFrank van der Linden 
112985abcd02SFrank van der Linden 	size >>= PAGE_SHIFT;
113085abcd02SFrank van der Linden 
113185abcd02SFrank van der Linden 	if (size > cma->available_count)
113285abcd02SFrank van der Linden 		return NULL;
113385abcd02SFrank van der Linden 
113485abcd02SFrank van der Linden 	for (r = 0; r < cma->nranges; r++) {
113585abcd02SFrank van der Linden 		cmr = &cma->ranges[r];
113685abcd02SFrank van der Linden 		available = cmr->count - (cmr->early_pfn - cmr->base_pfn);
113785abcd02SFrank van der Linden 		if (size <= available) {
113885abcd02SFrank van der Linden 			ret = phys_to_virt(PFN_PHYS(cmr->early_pfn));
113985abcd02SFrank van der Linden 			cmr->early_pfn += size;
114085abcd02SFrank van der Linden 			cma->available_count -= size;
114185abcd02SFrank van der Linden 			return ret;
114285abcd02SFrank van der Linden 		}
114385abcd02SFrank van der Linden 	}
114485abcd02SFrank van der Linden 
114585abcd02SFrank van der Linden 	return ret;
114685abcd02SFrank van der Linden }
1147