diff options
Diffstat (limited to 'mm/memblock.c')
| -rw-r--r-- | mm/memblock.c | 68 | 
1 files changed, 58 insertions, 10 deletions
| diff --git a/mm/memblock.c b/mm/memblock.c index 952123eba433..d4382095f8bd 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -184,7 +184,24 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u  	}  } -static int __init_memblock memblock_double_array(struct memblock_type *type) +/** + * memblock_double_array - double the size of the memblock regions array + * @type: memblock type of the regions array being doubled + * @new_area_start: starting address of memory range to avoid overlap with + * @new_area_size: size of memory range to avoid overlap with + * + * Double the size of the @type regions array. If memblock is being used to + * allocate memory for a new reserved regions array and there is a previously + * allocated memory range [@new_area_start,@new_area_start+@new_area_size] + * waiting to be reserved, ensure the memory used by the new array does + * not overlap. + * + * RETURNS: + * 0 on success, -1 on failure. + */ +static int __init_memblock memblock_double_array(struct memblock_type *type, +						phys_addr_t new_area_start, +						phys_addr_t new_area_size)  {  	struct memblock_region *new_array, *old_array;  	phys_addr_t old_size, new_size, addr; @@ -222,7 +239,18 @@ static int __init_memblock memblock_double_array(struct memblock_type *type)  		new_array = kmalloc(new_size, GFP_KERNEL);  		addr = new_array ? __pa(new_array) : 0;  	} else { -		addr = memblock_find_in_range(0, MEMBLOCK_ALLOC_ACCESSIBLE, new_size, sizeof(phys_addr_t)); +		/* only exclude range when trying to double reserved.regions */ +		if (type != &memblock.reserved) +			new_area_start = new_area_size = 0; + +		addr = memblock_find_in_range(new_area_start + new_area_size, +						memblock.current_limit, +						new_size, sizeof(phys_addr_t)); +		if (!addr && new_area_size) +			addr = memblock_find_in_range(0, +					min(new_area_start, memblock.current_limit), +					new_size, sizeof(phys_addr_t)); +  		new_array = addr ? __va(addr) : 0;  	}  	if (!addr) { @@ -399,7 +427,7 @@ repeat:  	 */  	if (!insert) {  		while (type->cnt + nr_new > type->max) -			if (memblock_double_array(type) < 0) +			if (memblock_double_array(type, obase, size) < 0)  				return -ENOMEM;  		insert = true;  		goto repeat; @@ -450,7 +478,7 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type,  	/* we'll create at most two more regions */  	while (type->cnt + 2 > type->max) -		if (memblock_double_array(type) < 0) +		if (memblock_double_array(type, base, size) < 0)  			return -ENOMEM;  	for (i = 0; i < type->cnt; i++) { @@ -540,9 +568,9 @@ int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)   * __next_free_mem_range - next function for for_each_free_mem_range()   * @idx: pointer to u64 loop variable   * @nid: nid: node selector, %MAX_NUMNODES for all nodes - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * @p_nid: ptr to int for nid of the range, can be %NULL + * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL + * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL + * @out_nid: ptr to int for nid of the range, can be %NULL   *   * Find the first free area from *@idx which matches @nid, fill the out   * parameters, and update *@idx for the next iteration.  The lower 32bit of @@ -616,9 +644,9 @@ void __init_memblock __next_free_mem_range(u64 *idx, int nid,   * __next_free_mem_range_rev - next function for for_each_free_mem_range_reverse()   * @idx: pointer to u64 loop variable   * @nid: nid: node selector, %MAX_NUMNODES for all nodes - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * @p_nid: ptr to int for nid of the range, can be %NULL + * @out_start: ptr to phys_addr_t for start address of the range, can be %NULL + * @out_end: ptr to phys_addr_t for end address of the range, can be %NULL + * @out_nid: ptr to int for nid of the range, can be %NULL   *   * Reverse of __next_free_mem_range().   */ @@ -867,6 +895,16 @@ int __init_memblock memblock_is_memory(phys_addr_t addr)  	return memblock_search(&memblock.memory, addr) != -1;  } +/** + * memblock_is_region_memory - check if a region is a subset of memory + * @base: base of region to check + * @size: size of region to check + * + * Check if the region [@base, @base+@size) is a subset of a memory block. + * + * RETURNS: + * 0 if false, non-zero if true + */  int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)  {  	int idx = memblock_search(&memblock.memory, base); @@ -879,6 +917,16 @@ int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size  		 memblock.memory.regions[idx].size) >= end;  } +/** + * memblock_is_region_reserved - check if a region intersects reserved memory + * @base: base of region to check + * @size: size of region to check + * + * Check if the region [@base, @base+@size) intersects a reserved memory block. + * + * RETURNS: + * 0 if false, non-zero if true + */  int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)  {  	memblock_cap_size(base, &size); | 
