diff options
Diffstat (limited to 'arch/arm/mm/init.c')
-rw-r--r-- | arch/arm/mm/init.c | 155 |
1 files changed, 112 insertions, 43 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 7fd9b5eb177f..5164069ced42 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
19 | #include <linux/gfp.h> | 19 | #include <linux/gfp.h> |
20 | #include <linux/memblock.h> | 20 | #include <linux/memblock.h> |
21 | #include <linux/sort.h> | ||
21 | 22 | ||
22 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
23 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
@@ -121,9 +122,10 @@ void show_mem(void) | |||
121 | printk("%d pages swap cached\n", cached); | 122 | printk("%d pages swap cached\n", cached); |
122 | } | 123 | } |
123 | 124 | ||
124 | static void __init find_limits(struct meminfo *mi, | 125 | static void __init find_limits(unsigned long *min, unsigned long *max_low, |
125 | unsigned long *min, unsigned long *max_low, unsigned long *max_high) | 126 | unsigned long *max_high) |
126 | { | 127 | { |
128 | struct meminfo *mi = &meminfo; | ||
127 | int i; | 129 | int i; |
128 | 130 | ||
129 | *min = -1UL; | 131 | *min = -1UL; |
@@ -147,14 +149,13 @@ static void __init find_limits(struct meminfo *mi, | |||
147 | } | 149 | } |
148 | } | 150 | } |
149 | 151 | ||
150 | static void __init arm_bootmem_init(struct meminfo *mi, | 152 | static void __init arm_bootmem_init(unsigned long start_pfn, |
151 | unsigned long start_pfn, unsigned long end_pfn) | 153 | unsigned long end_pfn) |
152 | { | 154 | { |
153 | struct memblock_region *reg; | 155 | struct memblock_region *reg; |
154 | unsigned int boot_pages; | 156 | unsigned int boot_pages; |
155 | phys_addr_t bitmap; | 157 | phys_addr_t bitmap; |
156 | pg_data_t *pgdat; | 158 | pg_data_t *pgdat; |
157 | int i; | ||
158 | 159 | ||
159 | /* | 160 | /* |
160 | * Allocate the bootmem bitmap page. This must be in a region | 161 | * Allocate the bootmem bitmap page. This must be in a region |
@@ -172,30 +173,39 @@ static void __init arm_bootmem_init(struct meminfo *mi, | |||
172 | pgdat = NODE_DATA(0); | 173 | pgdat = NODE_DATA(0); |
173 | init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn); | 174 | init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn); |
174 | 175 | ||
175 | for_each_bank(i, mi) { | 176 | /* Free the lowmem regions from memblock into bootmem. */ |
176 | struct membank *bank = &mi->bank[i]; | 177 | for_each_memblock(memory, reg) { |
177 | if (!bank->highmem) | 178 | unsigned long start = memblock_region_memory_base_pfn(reg); |
178 | free_bootmem(bank_phys_start(bank), bank_phys_size(bank)); | 179 | unsigned long end = memblock_region_memory_end_pfn(reg); |
180 | |||
181 | if (end >= end_pfn) | ||
182 | end = end_pfn; | ||
183 | if (start >= end) | ||
184 | break; | ||
185 | |||
186 | free_bootmem(__pfn_to_phys(start), (end - start) << PAGE_SHIFT); | ||
179 | } | 187 | } |
180 | 188 | ||
181 | /* | 189 | /* Reserve the lowmem memblock reserved regions in bootmem. */ |
182 | * Reserve the memblock reserved regions in bootmem. | ||
183 | */ | ||
184 | for_each_memblock(reserved, reg) { | 190 | for_each_memblock(reserved, reg) { |
185 | phys_addr_t start = memblock_region_reserved_base_pfn(reg); | 191 | unsigned long start = memblock_region_reserved_base_pfn(reg); |
186 | phys_addr_t end = memblock_region_reserved_end_pfn(reg); | 192 | unsigned long end = memblock_region_reserved_end_pfn(reg); |
187 | if (start >= start_pfn && end <= end_pfn) | 193 | |
188 | reserve_bootmem_node(pgdat, __pfn_to_phys(start), | 194 | if (end >= end_pfn) |
189 | (end - start) << PAGE_SHIFT, | 195 | end = end_pfn; |
190 | BOOTMEM_DEFAULT); | 196 | if (start >= end) |
197 | break; | ||
198 | |||
199 | reserve_bootmem(__pfn_to_phys(start), | ||
200 | (end - start) << PAGE_SHIFT, BOOTMEM_DEFAULT); | ||
191 | } | 201 | } |
192 | } | 202 | } |
193 | 203 | ||
194 | static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min, | 204 | static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, |
195 | unsigned long max_low, unsigned long max_high) | 205 | unsigned long max_high) |
196 | { | 206 | { |
197 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; | 207 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; |
198 | int i; | 208 | struct memblock_region *reg; |
199 | 209 | ||
200 | /* | 210 | /* |
201 | * initialise the zones. | 211 | * initialise the zones. |
@@ -217,13 +227,20 @@ static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min, | |||
217 | * holes = node_size - sum(bank_sizes) | 227 | * holes = node_size - sum(bank_sizes) |
218 | */ | 228 | */ |
219 | memcpy(zhole_size, zone_size, sizeof(zhole_size)); | 229 | memcpy(zhole_size, zone_size, sizeof(zhole_size)); |
220 | for_each_bank(i, mi) { | 230 | for_each_memblock(memory, reg) { |
221 | int idx = 0; | 231 | unsigned long start = memblock_region_memory_base_pfn(reg); |
232 | unsigned long end = memblock_region_memory_end_pfn(reg); | ||
233 | |||
234 | if (start < max_low) { | ||
235 | unsigned long low_end = min(end, max_low); | ||
236 | zhole_size[0] -= low_end - start; | ||
237 | } | ||
222 | #ifdef CONFIG_HIGHMEM | 238 | #ifdef CONFIG_HIGHMEM |
223 | if (mi->bank[i].highmem) | 239 | if (end > max_low) { |
224 | idx = ZONE_HIGHMEM; | 240 | unsigned long high_start = max(start, max_low); |
241 | zhole_size[ZONE_HIGHMEM] -= end - high_start; | ||
242 | } | ||
225 | #endif | 243 | #endif |
226 | zhole_size[idx] -= bank_pfn_size(&mi->bank[i]); | ||
227 | } | 244 | } |
228 | 245 | ||
229 | /* | 246 | /* |
@@ -256,10 +273,19 @@ static void arm_memory_present(void) | |||
256 | } | 273 | } |
257 | #endif | 274 | #endif |
258 | 275 | ||
276 | static int __init meminfo_cmp(const void *_a, const void *_b) | ||
277 | { | ||
278 | const struct membank *a = _a, *b = _b; | ||
279 | long cmp = bank_pfn_start(a) - bank_pfn_start(b); | ||
280 | return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; | ||
281 | } | ||
282 | |||
259 | void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) | 283 | void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) |
260 | { | 284 | { |
261 | int i; | 285 | int i; |
262 | 286 | ||
287 | sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); | ||
288 | |||
263 | memblock_init(); | 289 | memblock_init(); |
264 | for (i = 0; i < mi->nr_banks; i++) | 290 | for (i = 0; i < mi->nr_banks; i++) |
265 | memblock_add(mi->bank[i].start, mi->bank[i].size); | 291 | memblock_add(mi->bank[i].start, mi->bank[i].size); |
@@ -292,14 +318,13 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) | |||
292 | 318 | ||
293 | void __init bootmem_init(void) | 319 | void __init bootmem_init(void) |
294 | { | 320 | { |
295 | struct meminfo *mi = &meminfo; | ||
296 | unsigned long min, max_low, max_high; | 321 | unsigned long min, max_low, max_high; |
297 | 322 | ||
298 | max_low = max_high = 0; | 323 | max_low = max_high = 0; |
299 | 324 | ||
300 | find_limits(mi, &min, &max_low, &max_high); | 325 | find_limits(&min, &max_low, &max_high); |
301 | 326 | ||
302 | arm_bootmem_init(mi, min, max_low); | 327 | arm_bootmem_init(min, max_low); |
303 | 328 | ||
304 | /* | 329 | /* |
305 | * Sparsemem tries to allocate bootmem in memory_present(), | 330 | * Sparsemem tries to allocate bootmem in memory_present(), |
@@ -317,7 +342,7 @@ void __init bootmem_init(void) | |||
317 | * the sparse mem_map arrays initialized by sparse_init() | 342 | * the sparse mem_map arrays initialized by sparse_init() |
318 | * for memmap_init_zone(), otherwise all PFNs are invalid. | 343 | * for memmap_init_zone(), otherwise all PFNs are invalid. |
319 | */ | 344 | */ |
320 | arm_bootmem_free(mi, min, max_low, max_high); | 345 | arm_bootmem_free(min, max_low, max_high); |
321 | 346 | ||
322 | high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; | 347 | high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; |
323 | 348 | ||
@@ -411,6 +436,56 @@ static void __init free_unused_memmap(struct meminfo *mi) | |||
411 | } | 436 | } |
412 | } | 437 | } |
413 | 438 | ||
439 | static void __init free_highpages(void) | ||
440 | { | ||
441 | #ifdef CONFIG_HIGHMEM | ||
442 | unsigned long max_low = max_low_pfn + PHYS_PFN_OFFSET; | ||
443 | struct memblock_region *mem, *res; | ||
444 | |||
445 | /* set highmem page free */ | ||
446 | for_each_memblock(memory, mem) { | ||
447 | unsigned long start = memblock_region_memory_base_pfn(mem); | ||
448 | unsigned long end = memblock_region_memory_end_pfn(mem); | ||
449 | |||
450 | /* Ignore complete lowmem entries */ | ||
451 | if (end <= max_low) | ||
452 | continue; | ||
453 | |||
454 | /* Truncate partial highmem entries */ | ||
455 | if (start < max_low) | ||
456 | start = max_low; | ||
457 | |||
458 | /* Find and exclude any reserved regions */ | ||
459 | for_each_memblock(reserved, res) { | ||
460 | unsigned long res_start, res_end; | ||
461 | |||
462 | res_start = memblock_region_reserved_base_pfn(res); | ||
463 | res_end = memblock_region_reserved_end_pfn(res); | ||
464 | |||
465 | if (res_end < start) | ||
466 | continue; | ||
467 | if (res_start < start) | ||
468 | res_start = start; | ||
469 | if (res_start > end) | ||
470 | res_start = end; | ||
471 | if (res_end > end) | ||
472 | res_end = end; | ||
473 | if (res_start != start) | ||
474 | totalhigh_pages += free_area(start, res_start, | ||
475 | NULL); | ||
476 | start = res_end; | ||
477 | if (start == end) | ||
478 | break; | ||
479 | } | ||
480 | |||
481 | /* And now free anything which remains */ | ||
482 | if (start < end) | ||
483 | totalhigh_pages += free_area(start, end, NULL); | ||
484 | } | ||
485 | totalram_pages += totalhigh_pages; | ||
486 | #endif | ||
487 | } | ||
488 | |||
414 | /* | 489 | /* |
415 | * mem_init() marks the free areas in the mem_map and tells us how much | 490 | * mem_init() marks the free areas in the mem_map and tells us how much |
416 | * memory is free. This is done after various parts of the system have | 491 | * memory is free. This is done after various parts of the system have |
@@ -419,6 +494,7 @@ static void __init free_unused_memmap(struct meminfo *mi) | |||
419 | void __init mem_init(void) | 494 | void __init mem_init(void) |
420 | { | 495 | { |
421 | unsigned long reserved_pages, free_pages; | 496 | unsigned long reserved_pages, free_pages; |
497 | struct memblock_region *reg; | ||
422 | int i; | 498 | int i; |
423 | #ifdef CONFIG_HAVE_TCM | 499 | #ifdef CONFIG_HAVE_TCM |
424 | /* These pointers are filled in on TCM detection */ | 500 | /* These pointers are filled in on TCM detection */ |
@@ -439,16 +515,7 @@ void __init mem_init(void) | |||
439 | __phys_to_pfn(__pa(swapper_pg_dir)), NULL); | 515 | __phys_to_pfn(__pa(swapper_pg_dir)), NULL); |
440 | #endif | 516 | #endif |
441 | 517 | ||
442 | #ifdef CONFIG_HIGHMEM | 518 | free_highpages(); |
443 | /* set highmem page free */ | ||
444 | for_each_bank (i, &meminfo) { | ||
445 | unsigned long start = bank_pfn_start(&meminfo.bank[i]); | ||
446 | unsigned long end = bank_pfn_end(&meminfo.bank[i]); | ||
447 | if (start >= max_low_pfn + PHYS_PFN_OFFSET) | ||
448 | totalhigh_pages += free_area(start, end, NULL); | ||
449 | } | ||
450 | totalram_pages += totalhigh_pages; | ||
451 | #endif | ||
452 | 519 | ||
453 | reserved_pages = free_pages = 0; | 520 | reserved_pages = free_pages = 0; |
454 | 521 | ||
@@ -478,9 +545,11 @@ void __init mem_init(void) | |||
478 | */ | 545 | */ |
479 | printk(KERN_INFO "Memory:"); | 546 | printk(KERN_INFO "Memory:"); |
480 | num_physpages = 0; | 547 | num_physpages = 0; |
481 | for (i = 0; i < meminfo.nr_banks; i++) { | 548 | for_each_memblock(memory, reg) { |
482 | num_physpages += bank_pfn_size(&meminfo.bank[i]); | 549 | unsigned long pages = memblock_region_memory_end_pfn(reg) - |
483 | printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20); | 550 | memblock_region_memory_base_pfn(reg); |
551 | num_physpages += pages; | ||
552 | printk(" %ldMB", pages >> (20 - PAGE_SHIFT)); | ||
484 | } | 553 | } |
485 | printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); | 554 | printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); |
486 | 555 | ||