blob: a9d0972df10afbd27bd38689e98c0ed4943c67dd [file] [log] [blame]
Yinghai Lufb74fb62010-08-25 13:39:15 -07001#include <linux/kernel.h>
2#include <linux/types.h>
3#include <linux/init.h>
4#include <linux/bitops.h>
5#include <linux/memblock.h>
6#include <linux/bootmem.h>
7#include <linux/mm.h>
8#include <linux/range.h>
9
Yinghai Lu9dc5d562010-08-25 13:39:15 -070010void __init memblock_x86_reserve_range(u64 start, u64 end, char *name)
11{
12 if (start == end)
13 return;
14
Yinghai Lu301ff3e2010-08-25 13:39:17 -070015 if (WARN_ONCE(start > end, "memblock_x86_reserve_range: wrong range [%#llx, %#llx)\n", start, end))
Yinghai Lu9dc5d562010-08-25 13:39:15 -070016 return;
17
Yinghai Lu301ff3e2010-08-25 13:39:17 -070018 memblock_dbg(" memblock_x86_reserve_range: [%#010llx-%#010llx] %16s\n", start, end - 1, name);
19
Yinghai Lu9dc5d562010-08-25 13:39:15 -070020 memblock_reserve(start, end - start);
21}
22
23void __init memblock_x86_free_range(u64 start, u64 end)
24{
25 if (start == end)
26 return;
27
Yinghai Lu301ff3e2010-08-25 13:39:17 -070028 if (WARN_ONCE(start > end, "memblock_x86_free_range: wrong range [%#llx, %#llx)\n", start, end))
Yinghai Lu9dc5d562010-08-25 13:39:15 -070029 return;
30
Yinghai Lu301ff3e2010-08-25 13:39:17 -070031 memblock_dbg(" memblock_x86_free_range: [%#010llx-%#010llx]\n", start, end - 1);
32
Yinghai Lu9dc5d562010-08-25 13:39:15 -070033 memblock_free(start, end - start);
34}
Yinghai Lu88ba0882010-08-25 13:39:16 -070035
36/*
37 * Finds an active region in the address range from start_pfn to last_pfn and
38 * returns its range in ei_startpfn and ei_endpfn for the memblock entry.
39 */
40static int __init memblock_x86_find_active_region(const struct memblock_region *ei,
41 unsigned long start_pfn,
42 unsigned long last_pfn,
43 unsigned long *ei_startpfn,
44 unsigned long *ei_endpfn)
45{
46 u64 align = PAGE_SIZE;
47
48 *ei_startpfn = round_up(ei->base, align) >> PAGE_SHIFT;
49 *ei_endpfn = round_down(ei->base + ei->size, align) >> PAGE_SHIFT;
50
51 /* Skip map entries smaller than a page */
52 if (*ei_startpfn >= *ei_endpfn)
53 return 0;
54
55 /* Skip if map is outside the node */
56 if (*ei_endpfn <= start_pfn || *ei_startpfn >= last_pfn)
57 return 0;
58
59 /* Check for overlaps */
60 if (*ei_startpfn < start_pfn)
61 *ei_startpfn = start_pfn;
62 if (*ei_endpfn > last_pfn)
63 *ei_endpfn = last_pfn;
64
65 return 1;
66}
67
Yinghai Lu88ba0882010-08-25 13:39:16 -070068/*
69 * Find the hole size (in bytes) in the memory range.
70 * @start: starting address of the memory range to scan
71 * @end: ending address of the memory range to scan
72 */
73u64 __init memblock_x86_hole_size(u64 start, u64 end)
74{
75 unsigned long start_pfn = start >> PAGE_SHIFT;
76 unsigned long last_pfn = end >> PAGE_SHIFT;
77 unsigned long ei_startpfn, ei_endpfn, ram = 0;
78 struct memblock_region *r;
79
80 for_each_memblock(memory, r)
81 if (memblock_x86_find_active_region(r, start_pfn, last_pfn,
82 &ei_startpfn, &ei_endpfn))
83 ram += ei_endpfn - ei_startpfn;
84
85 return end - start - ((u64)ram << PAGE_SHIFT);
86}