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