diff options
author | Yinghai Lu <yinghai@kernel.org> | 2010-08-25 16:39:16 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-08-27 14:11:16 -0400 |
commit | b52c17ce854125700c4e19d4427d39bf2504ff63 (patch) | |
tree | 917bbfb7b1603b6deb7dee735d05071199d5ba51 /arch | |
parent | 6bcc8176d07f108da3b1af17fb2c0e82c80e948e (diff) |
x86, memblock: Add memblock_x86_free_memory_in_range()
It will return free memory size in specified range.
We can not use memory_size - reserved_size here, because some reserved area
may not be in the scope of memblock.memory.region.
Use memblock.memory.region subtracting memblock.reserved.region to get free range array.
then count size of all free ranges.
-v2: Ben insist on using _in_range
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/include/asm/memblock.h | 1 | ||||
-rw-r--r-- | arch/x86/mm/memblock.c | 48 |
2 files changed, 49 insertions, 0 deletions
diff --git a/arch/x86/include/asm/memblock.h b/arch/x86/include/asm/memblock.h index 3a86b10380f3..fc3c230812e6 100644 --- a/arch/x86/include/asm/memblock.h +++ b/arch/x86/include/asm/memblock.h | |||
@@ -15,5 +15,6 @@ void memblock_x86_register_active_regions(int nid, unsigned long start_pfn, | |||
15 | unsigned long last_pfn); | 15 | unsigned long last_pfn); |
16 | u64 memblock_x86_hole_size(u64 start, u64 end); | 16 | u64 memblock_x86_hole_size(u64 start, u64 end); |
17 | u64 memblock_x86_find_in_range_node(int nid, u64 start, u64 end, u64 size, u64 align); | 17 | u64 memblock_x86_find_in_range_node(int nid, u64 start, u64 end, u64 size, u64 align); |
18 | u64 memblock_x86_free_memory_in_range(u64 addr, u64 limit); | ||
18 | 19 | ||
19 | #endif | 20 | #endif |
diff --git a/arch/x86/mm/memblock.c b/arch/x86/mm/memblock.c index 22ff0a39b227..30d60cf29ce3 100644 --- a/arch/x86/mm/memblock.c +++ b/arch/x86/mm/memblock.c | |||
@@ -211,6 +211,54 @@ void __init memblock_x86_to_bootmem(u64 start, u64 end) | |||
211 | } | 211 | } |
212 | #endif | 212 | #endif |
213 | 213 | ||
214 | u64 __init memblock_x86_free_memory_in_range(u64 addr, u64 limit) | ||
215 | { | ||
216 | int i, count; | ||
217 | struct range *range; | ||
218 | int nr_range; | ||
219 | u64 final_start, final_end; | ||
220 | u64 free_size; | ||
221 | struct memblock_region *r; | ||
222 | |||
223 | count = (memblock.reserved.cnt + memblock.memory.cnt) * 2; | ||
224 | |||
225 | range = find_range_array(count); | ||
226 | nr_range = 0; | ||
227 | |||
228 | addr = PFN_UP(addr); | ||
229 | limit = PFN_DOWN(limit); | ||
230 | |||
231 | for_each_memblock(memory, r) { | ||
232 | final_start = PFN_UP(r->base); | ||
233 | final_end = PFN_DOWN(r->base + r->size); | ||
234 | if (final_start >= final_end) | ||
235 | continue; | ||
236 | if (final_start >= limit || final_end <= addr) | ||
237 | continue; | ||
238 | |||
239 | nr_range = add_range(range, count, nr_range, final_start, final_end); | ||
240 | } | ||
241 | subtract_range(range, count, 0, addr); | ||
242 | subtract_range(range, count, limit, -1ULL); | ||
243 | for_each_memblock(reserved, r) { | ||
244 | final_start = PFN_DOWN(r->base); | ||
245 | final_end = PFN_UP(r->base + r->size); | ||
246 | if (final_start >= final_end) | ||
247 | continue; | ||
248 | if (final_start >= limit || final_end <= addr) | ||
249 | continue; | ||
250 | |||
251 | subtract_range(range, count, final_start, final_end); | ||
252 | } | ||
253 | nr_range = clean_sort_range(range, count); | ||
254 | |||
255 | free_size = 0; | ||
256 | for (i = 0; i < nr_range; i++) | ||
257 | free_size += range[i].end - range[i].start; | ||
258 | |||
259 | return free_size << PAGE_SHIFT; | ||
260 | } | ||
261 | |||
214 | void __init memblock_x86_reserve_range(u64 start, u64 end, char *name) | 262 | void __init memblock_x86_reserve_range(u64 start, u64 end, char *name) |
215 | { | 263 | { |
216 | if (start == end) | 264 | if (start == end) |