diff options
Diffstat (limited to 'arch/arm/mm/init.c')
-rw-r--r-- | arch/arm/mm/init.c | 118 |
1 files changed, 73 insertions, 45 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 8277802ec859..3a7279c1ce5e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
@@ -120,6 +120,32 @@ void show_mem(void) | |||
120 | printk("%d pages swap cached\n", cached); | 120 | printk("%d pages swap cached\n", cached); |
121 | } | 121 | } |
122 | 122 | ||
123 | static void __init find_node_limits(int node, struct meminfo *mi, | ||
124 | unsigned long *min, unsigned long *max_low, unsigned long *max_high) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | *min = -1UL; | ||
129 | *max_low = *max_high = 0; | ||
130 | |||
131 | for_each_nodebank(i, mi, node) { | ||
132 | struct membank *bank = &mi->bank[i]; | ||
133 | unsigned long start, end; | ||
134 | |||
135 | start = bank_pfn_start(bank); | ||
136 | end = bank_pfn_end(bank); | ||
137 | |||
138 | if (*min > start) | ||
139 | *min = start; | ||
140 | if (*max_high < end) | ||
141 | *max_high = end; | ||
142 | if (bank->highmem) | ||
143 | continue; | ||
144 | if (*max_low < end) | ||
145 | *max_low = end; | ||
146 | } | ||
147 | } | ||
148 | |||
123 | /* | 149 | /* |
124 | * FIXME: We really want to avoid allocating the bootmap bitmap | 150 | * FIXME: We really want to avoid allocating the bootmap bitmap |
125 | * over the top of the initrd. Hopefully, this is located towards | 151 | * over the top of the initrd. Hopefully, this is located towards |
@@ -210,41 +236,25 @@ static inline void map_memory_bank(struct membank *bank) | |||
210 | #endif | 236 | #endif |
211 | } | 237 | } |
212 | 238 | ||
213 | static unsigned long __init bootmem_init_node(int node, struct meminfo *mi) | 239 | static void __init bootmem_init_node(int node, struct meminfo *mi, |
240 | unsigned long start_pfn, unsigned long end_pfn) | ||
214 | { | 241 | { |
215 | unsigned long start_pfn, end_pfn, boot_pfn; | 242 | unsigned long boot_pfn; |
216 | unsigned int boot_pages; | 243 | unsigned int boot_pages; |
217 | pg_data_t *pgdat; | 244 | pg_data_t *pgdat; |
218 | int i; | 245 | int i; |
219 | 246 | ||
220 | start_pfn = -1UL; | ||
221 | end_pfn = 0; | ||
222 | |||
223 | /* | 247 | /* |
224 | * Calculate the pfn range, and map the memory banks for this node. | 248 | * Map the memory banks for this node. |
225 | */ | 249 | */ |
226 | for_each_nodebank(i, mi, node) { | 250 | for_each_nodebank(i, mi, node) { |
227 | struct membank *bank = &mi->bank[i]; | 251 | struct membank *bank = &mi->bank[i]; |
228 | unsigned long start, end; | ||
229 | 252 | ||
230 | start = bank_pfn_start(bank); | 253 | if (!bank->highmem) |
231 | end = bank_pfn_end(bank); | 254 | map_memory_bank(bank); |
232 | |||
233 | if (start_pfn > start) | ||
234 | start_pfn = start; | ||
235 | if (end_pfn < end) | ||
236 | end_pfn = end; | ||
237 | |||
238 | map_memory_bank(bank); | ||
239 | } | 255 | } |
240 | 256 | ||
241 | /* | 257 | /* |
242 | * If there is no memory in this node, ignore it. | ||
243 | */ | ||
244 | if (end_pfn == 0) | ||
245 | return end_pfn; | ||
246 | |||
247 | /* | ||
248 | * Allocate the bootmem bitmap page. | 258 | * Allocate the bootmem bitmap page. |
249 | */ | 259 | */ |
250 | boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn); | 260 | boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn); |
@@ -260,7 +270,8 @@ static unsigned long __init bootmem_init_node(int node, struct meminfo *mi) | |||
260 | 270 | ||
261 | for_each_nodebank(i, mi, node) { | 271 | for_each_nodebank(i, mi, node) { |
262 | struct membank *bank = &mi->bank[i]; | 272 | struct membank *bank = &mi->bank[i]; |
263 | free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank)); | 273 | if (!bank->highmem) |
274 | free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank)); | ||
264 | memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank)); | 275 | memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank)); |
265 | } | 276 | } |
266 | 277 | ||
@@ -269,8 +280,6 @@ static unsigned long __init bootmem_init_node(int node, struct meminfo *mi) | |||
269 | */ | 280 | */ |
270 | reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, | 281 | reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, |
271 | boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT); | 282 | boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT); |
272 | |||
273 | return end_pfn; | ||
274 | } | 283 | } |
275 | 284 | ||
276 | static void __init bootmem_reserve_initrd(int node) | 285 | static void __init bootmem_reserve_initrd(int node) |
@@ -297,33 +306,39 @@ static void __init bootmem_reserve_initrd(int node) | |||
297 | static void __init bootmem_free_node(int node, struct meminfo *mi) | 306 | static void __init bootmem_free_node(int node, struct meminfo *mi) |
298 | { | 307 | { |
299 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; | 308 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; |
300 | unsigned long start_pfn, end_pfn; | 309 | unsigned long min, max_low, max_high; |
301 | pg_data_t *pgdat = NODE_DATA(node); | ||
302 | int i; | 310 | int i; |
303 | 311 | ||
304 | start_pfn = pgdat->bdata->node_min_pfn; | 312 | find_node_limits(node, mi, &min, &max_low, &max_high); |
305 | end_pfn = pgdat->bdata->node_low_pfn; | ||
306 | 313 | ||
307 | /* | 314 | /* |
308 | * initialise the zones within this node. | 315 | * initialise the zones within this node. |
309 | */ | 316 | */ |
310 | memset(zone_size, 0, sizeof(zone_size)); | 317 | memset(zone_size, 0, sizeof(zone_size)); |
311 | memset(zhole_size, 0, sizeof(zhole_size)); | ||
312 | 318 | ||
313 | /* | 319 | /* |
314 | * The size of this node has already been determined. If we need | 320 | * The size of this node has already been determined. If we need |
315 | * to do anything fancy with the allocation of this memory to the | 321 | * to do anything fancy with the allocation of this memory to the |
316 | * zones, now is the time to do it. | 322 | * zones, now is the time to do it. |
317 | */ | 323 | */ |
318 | zone_size[0] = end_pfn - start_pfn; | 324 | zone_size[0] = max_low - min; |
325 | #ifdef CONFIG_HIGHMEM | ||
326 | zone_size[ZONE_HIGHMEM] = max_high - max_low; | ||
327 | #endif | ||
319 | 328 | ||
320 | /* | 329 | /* |
321 | * For each bank in this node, calculate the size of the holes. | 330 | * For each bank in this node, calculate the size of the holes. |
322 | * holes = node_size - sum(bank_sizes_in_node) | 331 | * holes = node_size - sum(bank_sizes_in_node) |
323 | */ | 332 | */ |
324 | zhole_size[0] = zone_size[0]; | 333 | memcpy(zhole_size, zone_size, sizeof(zhole_size)); |
325 | for_each_nodebank(i, mi, node) | 334 | for_each_nodebank(i, mi, node) { |
326 | zhole_size[0] -= bank_pfn_size(&mi->bank[i]); | 335 | int idx = 0; |
336 | #ifdef CONFIG_HIGHMEM | ||
337 | if (mi->bank[i].highmem) | ||
338 | idx = ZONE_HIGHMEM; | ||
339 | #endif | ||
340 | zhole_size[idx] -= bank_pfn_size(&mi->bank[i]); | ||
341 | } | ||
327 | 342 | ||
328 | /* | 343 | /* |
329 | * Adjust the sizes according to any special requirements for | 344 | * Adjust the sizes according to any special requirements for |
@@ -331,13 +346,13 @@ static void __init bootmem_free_node(int node, struct meminfo *mi) | |||
331 | */ | 346 | */ |
332 | arch_adjust_zones(node, zone_size, zhole_size); | 347 | arch_adjust_zones(node, zone_size, zhole_size); |
333 | 348 | ||
334 | free_area_init_node(node, zone_size, start_pfn, zhole_size); | 349 | free_area_init_node(node, zone_size, min, zhole_size); |
335 | } | 350 | } |
336 | 351 | ||
337 | void __init bootmem_init(void) | 352 | void __init bootmem_init(void) |
338 | { | 353 | { |
339 | struct meminfo *mi = &meminfo; | 354 | struct meminfo *mi = &meminfo; |
340 | unsigned long memend_pfn = 0; | 355 | unsigned long min, max_low, max_high; |
341 | int node, initrd_node; | 356 | int node, initrd_node; |
342 | 357 | ||
343 | /* | 358 | /* |
@@ -345,11 +360,29 @@ void __init bootmem_init(void) | |||
345 | */ | 360 | */ |
346 | initrd_node = check_initrd(mi); | 361 | initrd_node = check_initrd(mi); |
347 | 362 | ||
363 | max_low = max_high = 0; | ||
364 | |||
348 | /* | 365 | /* |
349 | * Run through each node initialising the bootmem allocator. | 366 | * Run through each node initialising the bootmem allocator. |
350 | */ | 367 | */ |
351 | for_each_node(node) { | 368 | for_each_node(node) { |
352 | unsigned long end_pfn = bootmem_init_node(node, mi); | 369 | unsigned long node_low, node_high; |
370 | |||
371 | find_node_limits(node, mi, &min, &node_low, &node_high); | ||
372 | |||
373 | if (node_low > max_low) | ||
374 | max_low = node_low; | ||
375 | if (node_high > max_high) | ||
376 | max_high = node_high; | ||
377 | |||
378 | /* | ||
379 | * If there is no memory in this node, ignore it. | ||
380 | * (We can't have nodes which have no lowmem) | ||
381 | */ | ||
382 | if (node_low == 0) | ||
383 | continue; | ||
384 | |||
385 | bootmem_init_node(node, mi, min, node_low); | ||
353 | 386 | ||
354 | /* | 387 | /* |
355 | * Reserve any special node zero regions. | 388 | * Reserve any special node zero regions. |
@@ -362,12 +395,6 @@ void __init bootmem_init(void) | |||
362 | */ | 395 | */ |
363 | if (node == initrd_node) | 396 | if (node == initrd_node) |
364 | bootmem_reserve_initrd(node); | 397 | bootmem_reserve_initrd(node); |
365 | |||
366 | /* | ||
367 | * Remember the highest memory PFN. | ||
368 | */ | ||
369 | if (end_pfn > memend_pfn) | ||
370 | memend_pfn = end_pfn; | ||
371 | } | 398 | } |
372 | 399 | ||
373 | /* | 400 | /* |
@@ -383,7 +410,7 @@ void __init bootmem_init(void) | |||
383 | for_each_node(node) | 410 | for_each_node(node) |
384 | bootmem_free_node(node, mi); | 411 | bootmem_free_node(node, mi); |
385 | 412 | ||
386 | high_memory = __va((memend_pfn << PAGE_SHIFT) - 1) + 1; | 413 | high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; |
387 | 414 | ||
388 | /* | 415 | /* |
389 | * This doesn't seem to be used by the Linux memory manager any | 416 | * This doesn't seem to be used by the Linux memory manager any |
@@ -393,7 +420,8 @@ void __init bootmem_init(void) | |||
393 | * Note: max_low_pfn and max_pfn reflect the number of _pages_ in | 420 | * Note: max_low_pfn and max_pfn reflect the number of _pages_ in |
394 | * the system, not the maximum PFN. | 421 | * the system, not the maximum PFN. |
395 | */ | 422 | */ |
396 | max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET; | 423 | max_low_pfn = max_low - PHYS_PFN_OFFSET; |
424 | max_pfn = max_high - PHYS_PFN_OFFSET; | ||
397 | } | 425 | } |
398 | 426 | ||
399 | static inline int free_area(unsigned long pfn, unsigned long end, char *s) | 427 | static inline int free_area(unsigned long pfn, unsigned long end, char *s) |