diff options
Diffstat (limited to 'mm/sparse-vmemmap.c')
| -rw-r--r-- | mm/sparse-vmemmap.c | 76 |
1 files changed, 74 insertions, 2 deletions
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index d9714bdcb4a3..392b9bb5bc01 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c | |||
| @@ -40,9 +40,11 @@ static void * __init_refok __earlyonly_bootmem_alloc(int node, | |||
| 40 | unsigned long align, | 40 | unsigned long align, |
| 41 | unsigned long goal) | 41 | unsigned long goal) |
| 42 | { | 42 | { |
| 43 | return __alloc_bootmem_node(NODE_DATA(node), size, align, goal); | 43 | return __alloc_bootmem_node_high(NODE_DATA(node), size, align, goal); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static void *vmemmap_buf; | ||
| 47 | static void *vmemmap_buf_end; | ||
| 46 | 48 | ||
| 47 | void * __meminit vmemmap_alloc_block(unsigned long size, int node) | 49 | void * __meminit vmemmap_alloc_block(unsigned long size, int node) |
| 48 | { | 50 | { |
| @@ -64,6 +66,24 @@ void * __meminit vmemmap_alloc_block(unsigned long size, int node) | |||
| 64 | __pa(MAX_DMA_ADDRESS)); | 66 | __pa(MAX_DMA_ADDRESS)); |
| 65 | } | 67 | } |
| 66 | 68 | ||
| 69 | /* need to make sure size is all the same during early stage */ | ||
| 70 | void * __meminit vmemmap_alloc_block_buf(unsigned long size, int node) | ||
| 71 | { | ||
| 72 | void *ptr; | ||
| 73 | |||
| 74 | if (!vmemmap_buf) | ||
| 75 | return vmemmap_alloc_block(size, node); | ||
| 76 | |||
| 77 | /* take the from buf */ | ||
| 78 | ptr = (void *)ALIGN((unsigned long)vmemmap_buf, size); | ||
| 79 | if (ptr + size > vmemmap_buf_end) | ||
| 80 | return vmemmap_alloc_block(size, node); | ||
| 81 | |||
| 82 | vmemmap_buf = ptr + size; | ||
| 83 | |||
| 84 | return ptr; | ||
| 85 | } | ||
| 86 | |||
| 67 | void __meminit vmemmap_verify(pte_t *pte, int node, | 87 | void __meminit vmemmap_verify(pte_t *pte, int node, |
| 68 | unsigned long start, unsigned long end) | 88 | unsigned long start, unsigned long end) |
| 69 | { | 89 | { |
| @@ -80,7 +100,7 @@ pte_t * __meminit vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node) | |||
| 80 | pte_t *pte = pte_offset_kernel(pmd, addr); | 100 | pte_t *pte = pte_offset_kernel(pmd, addr); |
| 81 | if (pte_none(*pte)) { | 101 | if (pte_none(*pte)) { |
| 82 | pte_t entry; | 102 | pte_t entry; |
| 83 | void *p = vmemmap_alloc_block(PAGE_SIZE, node); | 103 | void *p = vmemmap_alloc_block_buf(PAGE_SIZE, node); |
| 84 | if (!p) | 104 | if (!p) |
| 85 | return NULL; | 105 | return NULL; |
| 86 | entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL); | 106 | entry = pfn_pte(__pa(p) >> PAGE_SHIFT, PAGE_KERNEL); |
| @@ -163,3 +183,55 @@ struct page * __meminit sparse_mem_map_populate(unsigned long pnum, int nid) | |||
| 163 | 183 | ||
| 164 | return map; | 184 | return map; |
| 165 | } | 185 | } |
| 186 | |||
| 187 | void __init sparse_mem_maps_populate_node(struct page **map_map, | ||
| 188 | unsigned long pnum_begin, | ||
| 189 | unsigned long pnum_end, | ||
| 190 | unsigned long map_count, int nodeid) | ||
| 191 | { | ||
| 192 | unsigned long pnum; | ||
| 193 | unsigned long size = sizeof(struct page) * PAGES_PER_SECTION; | ||
| 194 | void *vmemmap_buf_start; | ||
| 195 | |||
| 196 | size = ALIGN(size, PMD_SIZE); | ||
| 197 | vmemmap_buf_start = __earlyonly_bootmem_alloc(nodeid, size * map_count, | ||
| 198 | PMD_SIZE, __pa(MAX_DMA_ADDRESS)); | ||
| 199 | |||
| 200 | if (vmemmap_buf_start) { | ||
| 201 | vmemmap_buf = vmemmap_buf_start; | ||
| 202 | vmemmap_buf_end = vmemmap_buf_start + size * map_count; | ||
| 203 | } | ||
| 204 | |||
| 205 | for (pnum = pnum_begin; pnum < pnum_end; pnum++) { | ||
| 206 | struct mem_section *ms; | ||
| 207 | |||
| 208 | if (!present_section_nr(pnum)) | ||
| 209 | continue; | ||
| 210 | |||
| 211 | map_map[pnum] = sparse_mem_map_populate(pnum, nodeid); | ||
| 212 | if (map_map[pnum]) | ||
| 213 | continue; | ||
| 214 | ms = __nr_to_section(pnum); | ||
| 215 | printk(KERN_ERR "%s: sparsemem memory map backing failed " | ||
| 216 | "some memory will not be available.\n", __func__); | ||
| 217 | ms->section_mem_map = 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | if (vmemmap_buf_start) { | ||
| 221 | /* need to free left buf */ | ||
| 222 | #ifdef CONFIG_NO_BOOTMEM | ||
| 223 | free_early(__pa(vmemmap_buf_start), __pa(vmemmap_buf_end)); | ||
| 224 | if (vmemmap_buf_start < vmemmap_buf) { | ||
| 225 | char name[15]; | ||
| 226 | |||
| 227 | snprintf(name, sizeof(name), "MEMMAP %d", nodeid); | ||
| 228 | reserve_early_without_check(__pa(vmemmap_buf_start), | ||
| 229 | __pa(vmemmap_buf), name); | ||
| 230 | } | ||
| 231 | #else | ||
| 232 | free_bootmem(__pa(vmemmap_buf), vmemmap_buf_end - vmemmap_buf); | ||
| 233 | #endif | ||
| 234 | vmemmap_buf = NULL; | ||
| 235 | vmemmap_buf_end = NULL; | ||
| 236 | } | ||
| 237 | } | ||
