Blame view

arch/arm/mm/init.c 19 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *  linux/arch/arm/mm/init.c
   *
90072059d   Russell King   [ARM] Re-jig boot...
4
   *  Copyright (C) 1995-2005 Russell King
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
  #include <linux/kernel.h>
  #include <linux/errno.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
  #include <linux/swap.h>
  #include <linux/init.h>
  #include <linux/bootmem.h>
  #include <linux/mman.h>
dc28094b9   Paul Gortmaker   arm: Add export.h...
16
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <linux/nodemask.h>
  #include <linux/initrd.h>
9eb8f6743   Grant Likely   arm/dt: Allow CON...
19
  #include <linux/of_fdt.h>
3835f6cb6   Nicolas Pitre   [ARM] mem_init():...
20
  #include <linux/highmem.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/gfp.h>
2778f6205   Russell King   ARM: initial LMB ...
22
  #include <linux/memblock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  
  #include <asm/mach-types.h>
716a3dc20   Russell King   ARM: Add arm_memb...
25
  #include <asm/memblock.h>
93c02ab40   Grant Likely   arm/dt: probe for...
26
  #include <asm/prom.h>
37efe6427   Russell King   [ARM] use asm/sec...
27
  #include <asm/sections.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <asm/setup.h>
74d02fb95   Russell King   [ARM] Move FLUSH_...
29
  #include <asm/sizes.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include <asm/tlb.h>
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
31
  #include <asm/fixmap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
  
  #include <asm/mach/arch.h>
  #include <asm/mach/map.h>
1c16d242a   Tejun Heo   memblock: Fix inc...
35
  #include <asm/memblock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

1b2e2b73b   Russell King   [ARM] Cleanup arc...
37
  #include "mm.h"
012d1f4af   Russell King   [ARM] move initrd...
38
39
  static unsigned long phys_initrd_start __initdata = 0;
  static unsigned long phys_initrd_size __initdata = 0;
2b0d8c251   Jeremy Kerr   ARM: 5880/1: arm:...
40
  static int __init early_initrd(char *p)
012d1f4af   Russell King   [ARM] move initrd...
41
42
  {
  	unsigned long start, size;
2b0d8c251   Jeremy Kerr   ARM: 5880/1: arm:...
43
  	char *endp;
012d1f4af   Russell King   [ARM] move initrd...
44

2b0d8c251   Jeremy Kerr   ARM: 5880/1: arm:...
45
46
47
  	start = memparse(p, &endp);
  	if (*endp == ',') {
  		size = memparse(endp + 1, NULL);
012d1f4af   Russell King   [ARM] move initrd...
48
49
50
51
  
  		phys_initrd_start = start;
  		phys_initrd_size = size;
  	}
2b0d8c251   Jeremy Kerr   ARM: 5880/1: arm:...
52
  	return 0;
012d1f4af   Russell King   [ARM] move initrd...
53
  }
2b0d8c251   Jeremy Kerr   ARM: 5880/1: arm:...
54
  early_param("initrd", early_initrd);
012d1f4af   Russell King   [ARM] move initrd...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  
  static int __init parse_tag_initrd(const struct tag *tag)
  {
  	printk(KERN_WARNING "ATAG_INITRD is deprecated; "
  		"please update your bootloader.
  ");
  	phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
  	phys_initrd_size = tag->u.initrd.size;
  	return 0;
  }
  
  __tagtable(ATAG_INITRD, parse_tag_initrd);
  
  static int __init parse_tag_initrd2(const struct tag *tag)
  {
  	phys_initrd_start = tag->u.initrd.start;
  	phys_initrd_size = tag->u.initrd.size;
  	return 0;
  }
  
  __tagtable(ATAG_INITRD2, parse_tag_initrd2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

9eb8f6743   Grant Likely   arm/dt: Allow CON...
77
78
79
80
81
82
83
  #ifdef CONFIG_OF_FLATTREE
  void __init early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end)
  {
  	phys_initrd_start = start;
  	phys_initrd_size = end - start;
  }
  #endif /* CONFIG_OF_FLATTREE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  /*
4b5f32cee   Nicolas Pitre   [ARM] rationalize...
85
86
87
   * This keeps memory configuration data used by a couple memory
   * initialization functions, as well as show_mem() for the skipping
   * of holes in the memory map.  It is populated by arm_add_memory().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
   */
4b5f32cee   Nicolas Pitre   [ARM] rationalize...
89
  struct meminfo meminfo;
5e7098275   Ray Lehtiniemi   [ARM] 3927/1: All...
90

b2b755b5f   David Rientjes   lib, arch: add fi...
91
  void show_mem(unsigned int filter)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
  {
  	int free = 0, total = 0, reserved = 0;
be3703027   Russell King   ARM: Remove DISCO...
94
  	int shared = 0, cached = 0, slab = 0, i;
5e7098275   Ray Lehtiniemi   [ARM] 3927/1: All...
95
  	struct meminfo * mi = &meminfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
  
  	printk("Mem-info:
  ");
7bf02ea22   David Rientjes   arch, mm: filter ...
99
  	show_free_areas(filter);
be3703027   Russell King   ARM: Remove DISCO...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  
  	for_each_bank (i, mi) {
  		struct membank *bank = &mi->bank[i];
  		unsigned int pfn1, pfn2;
  		struct page *page, *end;
  
  		pfn1 = bank_pfn_start(bank);
  		pfn2 = bank_pfn_end(bank);
  
  		page = pfn_to_page(pfn1);
  		end  = pfn_to_page(pfn2 - 1) + 1;
  
  		do {
  			total++;
  			if (PageReserved(page))
  				reserved++;
  			else if (PageSwapCache(page))
  				cached++;
  			else if (PageSlab(page))
  				slab++;
  			else if (!page_count(page))
  				free++;
  			else
  				shared += page_count(page) - 1;
  			page++;
  		} while (page < end);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  	}
  
  	printk("%d pages of RAM
  ", total);
  	printk("%d free pages
  ", free);
  	printk("%d reserved pages
  ", reserved);
  	printk("%d slab pages
  ", slab);
  	printk("%d pages shared
  ", shared);
  	printk("%d pages swap cached
  ", cached);
  }
f25b4b4c8   Russell King   ARM: memblock: mo...
141
  static void __init find_limits(unsigned long *min, unsigned long *max_low,
27a3f0e91   Nicolas Pitre   ARM: sort the mem...
142
  			       unsigned long *max_high)
dde5828f5   Russell King   ARM: Fix broken h...
143
  {
f25b4b4c8   Russell King   ARM: memblock: mo...
144
  	struct meminfo *mi = &meminfo;
dde5828f5   Russell King   ARM: Fix broken h...
145
  	int i;
27a3f0e91   Nicolas Pitre   ARM: sort the mem...
146
147
148
149
150
151
152
  	/* This assumes the meminfo array is properly sorted */
  	*min = bank_pfn_start(&mi->bank[0]);
  	for_each_bank (i, mi)
  		if (mi->bank[i].highmem)
  				break;
  	*max_low = bank_pfn_end(&mi->bank[i - 1]);
  	*max_high = bank_pfn_end(&mi->bank[mi->nr_banks - 1]);
dde5828f5   Russell King   ARM: Fix broken h...
153
  }
a801d2764   Russell King   ARM: memblock: us...
154
155
  static void __init arm_bootmem_init(unsigned long start_pfn,
  	unsigned long end_pfn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  {
719c1514f   Benjamin Herrenschmidt   memblock/arm: Use...
157
  	struct memblock_region *reg;
90072059d   Russell King   [ARM] Re-jig boot...
158
  	unsigned int boot_pages;
2778f6205   Russell King   ARM: initial LMB ...
159
  	phys_addr_t bitmap;
90072059d   Russell King   [ARM] Re-jig boot...
160
  	pg_data_t *pgdat;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161

90072059d   Russell King   [ARM] Re-jig boot...
162
  	/*
2778f6205   Russell King   ARM: initial LMB ...
163
164
  	 * Allocate the bootmem bitmap page.  This must be in a region
  	 * of memory which has already been mapped.
90072059d   Russell King   [ARM] Re-jig boot...
165
166
  	 */
  	boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
2778f6205   Russell King   ARM: initial LMB ...
167
168
  	bitmap = memblock_alloc_base(boot_pages << PAGE_SHIFT, L1_CACHE_BYTES,
  				__pfn_to_phys(end_pfn));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169

90072059d   Russell King   [ARM] Re-jig boot...
170
  	/*
be3703027   Russell King   ARM: Remove DISCO...
171
  	 * Initialise the bootmem allocator, handing the
90072059d   Russell King   [ARM] Re-jig boot...
172
173
  	 * memory banks over to bootmem.
  	 */
be3703027   Russell King   ARM: Remove DISCO...
174
175
  	node_set_online(0);
  	pgdat = NODE_DATA(0);
2778f6205   Russell King   ARM: initial LMB ...
176
  	init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177

a801d2764   Russell King   ARM: memblock: us...
178
179
180
181
182
183
184
185
186
187
188
  	/* Free the lowmem regions from memblock into bootmem. */
  	for_each_memblock(memory, reg) {
  		unsigned long start = memblock_region_memory_base_pfn(reg);
  		unsigned long end = memblock_region_memory_end_pfn(reg);
  
  		if (end >= end_pfn)
  			end = end_pfn;
  		if (start >= end)
  			break;
  
  		free_bootmem(__pfn_to_phys(start), (end - start) << PAGE_SHIFT);
d2a38ef9c   Russell King   [ARM] mm: provide...
189
  	}
90072059d   Russell King   [ARM] Re-jig boot...
190

a801d2764   Russell King   ARM: memblock: us...
191
  	/* Reserve the lowmem memblock reserved regions in bootmem. */
719c1514f   Benjamin Herrenschmidt   memblock/arm: Use...
192
  	for_each_memblock(reserved, reg) {
a801d2764   Russell King   ARM: memblock: us...
193
194
195
196
197
198
199
200
201
202
  		unsigned long start = memblock_region_reserved_base_pfn(reg);
  		unsigned long end = memblock_region_reserved_end_pfn(reg);
  
  		if (end >= end_pfn)
  			end = end_pfn;
  		if (start >= end)
  			break;
  
  		reserve_bootmem(__pfn_to_phys(start),
  			        (end - start) << PAGE_SHIFT, BOOTMEM_DEFAULT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  	}
b7a69ac30   Russell King   [ARM] mm: finish ...
204
  }
be20902ba   Russell King   ARM: use ARM_DMA_...
205
  #ifdef CONFIG_ZONE_DMA
650320181   Nicolas Pitre   ARM: change ARM_D...
206

650320181   Nicolas Pitre   ARM: change ARM_D...
207
  unsigned long arm_dma_zone_size __read_mostly;
650320181   Nicolas Pitre   ARM: change ARM_D...
208
  EXPORT_SYMBOL(arm_dma_zone_size);
022ae537b   Russell King   ARM: dma: replace...
209
210
211
212
213
214
215
  /*
   * The DMA mask corresponding to the maximum bus address allocatable
   * using GFP_DMA.  The default here places no restriction on DMA
   * allocations.  This must be the smallest DMA mask in the system,
   * so a successful GFP_DMA allocation will always satisfy this.
   */
  u32 arm_dma_limit;
be20902ba   Russell King   ARM: use ARM_DMA_...
216
217
218
219
220
221
222
223
224
225
226
227
  static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole,
  	unsigned long dma_size)
  {
  	if (size[0] <= dma_size)
  		return;
  
  	size[ZONE_NORMAL] = size[0] - dma_size;
  	size[ZONE_DMA] = dma_size;
  	hole[ZONE_NORMAL] = hole[0];
  	hole[ZONE_DMA] = 0;
  }
  #endif
a2c54d2af   Russell King   ARM: memblock: us...
228
229
  static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
  	unsigned long max_high)
b7a69ac30   Russell King   [ARM] mm: finish ...
230
231
  {
  	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
a2c54d2af   Russell King   ARM: memblock: us...
232
  	struct memblock_region *reg;
b7a69ac30   Russell King   [ARM] mm: finish ...
233

90072059d   Russell King   [ARM] Re-jig boot...
234
  	/*
be3703027   Russell King   ARM: Remove DISCO...
235
  	 * initialise the zones.
90072059d   Russell King   [ARM] Re-jig boot...
236
237
  	 */
  	memset(zone_size, 0, sizeof(zone_size));
90072059d   Russell King   [ARM] Re-jig boot...
238
239
  
  	/*
be3703027   Russell King   ARM: Remove DISCO...
240
241
242
  	 * The memory size has already been determined.  If we need
  	 * to do anything fancy with the allocation of this memory
  	 * to the zones, now is the time to do it.
90072059d   Russell King   [ARM] Re-jig boot...
243
  	 */
dde5828f5   Russell King   ARM: Fix broken h...
244
245
246
247
  	zone_size[0] = max_low - min;
  #ifdef CONFIG_HIGHMEM
  	zone_size[ZONE_HIGHMEM] = max_high - max_low;
  #endif
90072059d   Russell King   [ARM] Re-jig boot...
248
249
  
  	/*
be3703027   Russell King   ARM: Remove DISCO...
250
251
  	 * Calculate the size of the holes.
  	 *  holes = node_size - sum(bank_sizes)
90072059d   Russell King   [ARM] Re-jig boot...
252
  	 */
dde5828f5   Russell King   ARM: Fix broken h...
253
  	memcpy(zhole_size, zone_size, sizeof(zhole_size));
a2c54d2af   Russell King   ARM: memblock: us...
254
255
256
257
258
259
260
261
  	for_each_memblock(memory, reg) {
  		unsigned long start = memblock_region_memory_base_pfn(reg);
  		unsigned long end = memblock_region_memory_end_pfn(reg);
  
  		if (start < max_low) {
  			unsigned long low_end = min(end, max_low);
  			zhole_size[0] -= low_end - start;
  		}
dde5828f5   Russell King   ARM: Fix broken h...
262
  #ifdef CONFIG_HIGHMEM
a2c54d2af   Russell King   ARM: memblock: us...
263
264
265
266
  		if (end > max_low) {
  			unsigned long high_start = max(start, max_low);
  			zhole_size[ZONE_HIGHMEM] -= end - high_start;
  		}
dde5828f5   Russell King   ARM: Fix broken h...
267
  #endif
dde5828f5   Russell King   ARM: Fix broken h...
268
  	}
90072059d   Russell King   [ARM] Re-jig boot...
269

650320181   Nicolas Pitre   ARM: change ARM_D...
270
  #ifdef CONFIG_ZONE_DMA
90072059d   Russell King   [ARM] Re-jig boot...
271
272
273
274
  	/*
  	 * Adjust the sizes according to any special requirements for
  	 * this machine type.
  	 */
650320181   Nicolas Pitre   ARM: change ARM_D...
275
276
277
278
279
280
  	if (arm_dma_zone_size) {
  		arm_adjust_dma_zone(zone_size, zhole_size,
  			arm_dma_zone_size >> PAGE_SHIFT);
  		arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1;
  	} else
  		arm_dma_limit = 0xffffffff;
be20902ba   Russell King   ARM: use ARM_DMA_...
281
  #endif
90072059d   Russell King   [ARM] Re-jig boot...
282

be3703027   Russell King   ARM: Remove DISCO...
283
  	free_area_init_node(0, zone_size, min, zhole_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  }
7b7bf499f   Will Deacon   ARM: 6913/1: spar...
285
  #ifdef CONFIG_HAVE_ARCH_PFN_VALID
b7cfda9fc   Russell King   ARM: Fix pfn_vali...
286
287
  int pfn_valid(unsigned long pfn)
  {
fb492c916   Mark Rutland   ARM: 7067/1: mm: ...
288
  	return memblock_is_memory(__pfn_to_phys(pfn));
b7cfda9fc   Russell King   ARM: Fix pfn_vali...
289
290
  }
  EXPORT_SYMBOL(pfn_valid);
7b7bf499f   Will Deacon   ARM: 6913/1: spar...
291
  #endif
657e12fd3   Russell King   ARM: Fix sparseme...
292

7b7bf499f   Will Deacon   ARM: 6913/1: spar...
293
  #ifndef CONFIG_SPARSEMEM
eda2e5dcc   Russell King   ARM: LMB: Convert...
294
  static void arm_memory_present(void)
657e12fd3   Russell King   ARM: Fix sparseme...
295
296
297
  {
  }
  #else
eda2e5dcc   Russell King   ARM: LMB: Convert...
298
  static void arm_memory_present(void)
657e12fd3   Russell King   ARM: Fix sparseme...
299
  {
719c1514f   Benjamin Herrenschmidt   memblock/arm: Use...
300
  	struct memblock_region *reg;
719c1514f   Benjamin Herrenschmidt   memblock/arm: Use...
301

7c996361e   Yinghai Lu   arm, memblock: Fi...
302
  	for_each_memblock(memory, reg)
c7fc2de0c   Yinghai Lu   memblock, bootmem...
303
304
  		memory_present(0, memblock_region_memory_base_pfn(reg),
  			       memblock_region_memory_end_pfn(reg));
657e12fd3   Russell King   ARM: Fix sparseme...
305
  }
b7cfda9fc   Russell King   ARM: Fix pfn_vali...
306
  #endif
716a3dc20   Russell King   ARM: Add arm_memb...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  static bool arm_memblock_steal_permitted = true;
  
  phys_addr_t arm_memblock_steal(phys_addr_t size, phys_addr_t align)
  {
  	phys_addr_t phys;
  
  	BUG_ON(!arm_memblock_steal_permitted);
  
  	phys = memblock_alloc(size, align);
  	memblock_free(phys, size);
  	memblock_remove(phys, size);
  
  	return phys;
  }
8d717a52d   Russell King   ARM: Convert plat...
321
  void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
2778f6205   Russell King   ARM: initial LMB ...
322
323
  {
  	int i;
2778f6205   Russell King   ARM: initial LMB ...
324
325
326
327
328
  	for (i = 0; i < mi->nr_banks; i++)
  		memblock_add(mi->bank[i].start, mi->bank[i].size);
  
  	/* Register the kernel text, kernel data and initrd with memblock. */
  #ifdef CONFIG_XIP_KERNEL
842eab40b   Russell King   ARM: vmlinux.lds:...
329
  	memblock_reserve(__pa(_sdata), _end - _sdata);
2778f6205   Russell King   ARM: initial LMB ...
330
331
332
333
  #else
  	memblock_reserve(__pa(_stext), _end - _stext);
  #endif
  #ifdef CONFIG_BLK_DEV_INITRD
b0a2679d2   Russell King   ARM: initrd: disa...
334
  	if (phys_initrd_size &&
8f4b8c761   Russell King   ARM: initrd: disa...
335
336
337
338
339
340
341
  	    !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
  		pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd
  ",
  		       phys_initrd_start, phys_initrd_size);
  		phys_initrd_start = phys_initrd_size = 0;
  	}
  	if (phys_initrd_size &&
b0a2679d2   Russell King   ARM: initrd: disa...
342
343
344
345
346
347
  	    memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
  		pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd
  ",
  		       phys_initrd_start, phys_initrd_size);
  		phys_initrd_start = phys_initrd_size = 0;
  	}
2778f6205   Russell King   ARM: initial LMB ...
348
349
350
351
352
353
354
355
356
357
  	if (phys_initrd_size) {
  		memblock_reserve(phys_initrd_start, phys_initrd_size);
  
  		/* Now convert initrd to virtual addresses */
  		initrd_start = __phys_to_virt(phys_initrd_start);
  		initrd_end = initrd_start + phys_initrd_size;
  	}
  #endif
  
  	arm_mm_memblock_reserve();
93c02ab40   Grant Likely   arm/dt: probe for...
358
  	arm_dt_memblock_reserve();
2778f6205   Russell King   ARM: initial LMB ...
359

8d717a52d   Russell King   ARM: Convert plat...
360
361
362
  	/* reserve any platform specific memblock areas */
  	if (mdesc->reserve)
  		mdesc->reserve();
716a3dc20   Russell King   ARM: Add arm_memb...
363
  	arm_memblock_steal_permitted = false;
1aadc0560   Tejun Heo   memblock: s/membl...
364
  	memblock_allow_resize();
2778f6205   Russell King   ARM: initial LMB ...
365
366
  	memblock_dump_all();
  }
8d717a52d   Russell King   ARM: Convert plat...
367
  void __init bootmem_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  {
dde5828f5   Russell King   ARM: Fix broken h...
369
  	unsigned long min, max_low, max_high;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370

dde5828f5   Russell King   ARM: Fix broken h...
371
  	max_low = max_high = 0;
f25b4b4c8   Russell King   ARM: memblock: mo...
372
  	find_limits(&min, &max_low, &max_high);
dde5828f5   Russell King   ARM: Fix broken h...
373

a801d2764   Russell King   ARM: memblock: us...
374
  	arm_bootmem_init(min, max_low);
dde5828f5   Russell King   ARM: Fix broken h...
375

be3703027   Russell King   ARM: Remove DISCO...
376
  	/*
be3703027   Russell King   ARM: Remove DISCO...
377
378
379
  	 * Sparsemem tries to allocate bootmem in memory_present(),
  	 * so must be done after the fixed reservations
  	 */
eda2e5dcc   Russell King   ARM: LMB: Convert...
380
  	arm_memory_present();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381

b7a69ac30   Russell King   [ARM] mm: finish ...
382
383
384
385
386
387
  	/*
  	 * sparse_init() needs the bootmem allocator up and running.
  	 */
  	sparse_init();
  
  	/*
be3703027   Russell King   ARM: Remove DISCO...
388
  	 * Now free the memory - free_area_init_node needs
b7a69ac30   Russell King   [ARM] mm: finish ...
389
390
391
  	 * the sparse mem_map arrays initialized by sparse_init()
  	 * for memmap_init_zone(), otherwise all PFNs are invalid.
  	 */
a2c54d2af   Russell King   ARM: memblock: us...
392
  	arm_bootmem_free(min, max_low, max_high);
b7a69ac30   Russell King   [ARM] mm: finish ...
393

90072059d   Russell King   [ARM] Re-jig boot...
394
395
396
397
398
399
400
401
  	/*
  	 * This doesn't seem to be used by the Linux memory manager any
  	 * more, but is used by ll_rw_block.  If we can get rid of it, we
  	 * also get rid of some of the stuff above as well.
  	 *
  	 * Note: max_low_pfn and max_pfn reflect the number of _pages_ in
  	 * the system, not the maximum PFN.
  	 */
dde5828f5   Russell King   ARM: Fix broken h...
402
403
  	max_low_pfn = max_low - PHYS_PFN_OFFSET;
  	max_pfn = max_high - PHYS_PFN_OFFSET;
90072059d   Russell King   [ARM] Re-jig boot...
404
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405

6db015e49   Nicolas Pitre   [ARM] mem_init() ...
406
  static inline int free_area(unsigned long pfn, unsigned long end, char *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  {
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
408
  	unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409

6db015e49   Nicolas Pitre   [ARM] mem_init() ...
410
411
  	for (; pfn < end; pfn++) {
  		struct page *page = pfn_to_page(pfn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  		ClearPageReserved(page);
7835e98b2   Nick Piggin   [PATCH] remove se...
413
  		init_page_count(page);
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
414
415
  		__free_page(page);
  		pages++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
420
  	}
  
  	if (size && s)
  		printk(KERN_INFO "Freeing %s memory: %dK
  ", s, size);
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
421
422
  
  	return pages;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  }
54d525735   Stephen Boyd   ARM: 6996/1: mm: ...
424
425
426
427
428
429
430
  /*
   * Poison init memory with an undefined instruction (ARM) or a branch to an
   * undefined instruction (Thumb).
   */
  static inline void poison_init_mem(void *s, size_t count)
  {
  	u32 *p = (u32 *)s;
bf912d99e   Jamie Iles   ARM: 7010/1: mm: ...
431
  	for (; count != 0; count -= 4)
54d525735   Stephen Boyd   ARM: 6996/1: mm: ...
432
433
  		*p++ = 0xe7fddef0;
  }
a013053d4   Russell King   [PATCH] ARM: Move...
434
  static inline void
be3703027   Russell King   ARM: Remove DISCO...
435
  free_memmap(unsigned long start_pfn, unsigned long end_pfn)
a013053d4   Russell King   [PATCH] ARM: Move...
436
437
438
439
440
441
442
  {
  	struct page *start_pg, *end_pg;
  	unsigned long pg, pgend;
  
  	/*
  	 * Convert start_pfn/end_pfn to a struct page pointer.
  	 */
3257f43d9   Catalin Marinas   ARM: 5747/1: Fix ...
443
  	start_pg = pfn_to_page(start_pfn - 1) + 1;
9af386c8d   Will Deacon   ARM: 6890/1: memm...
444
  	end_pg = pfn_to_page(end_pfn - 1) + 1;
a013053d4   Russell King   [PATCH] ARM: Move...
445
446
447
448
449
  
  	/*
  	 * Convert to physical addresses, and
  	 * round start upwards and end downwards.
  	 */
cae6292b6   Will Deacon   ARM: 6672/1: LPAE...
450
451
  	pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
  	pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
a013053d4   Russell King   [PATCH] ARM: Move...
452
453
454
455
456
457
  
  	/*
  	 * If there are free pages between these,
  	 * free the section of the memmap array.
  	 */
  	if (pg < pgend)
be3703027   Russell King   ARM: Remove DISCO...
458
  		free_bootmem(pg, pgend - pg);
a013053d4   Russell King   [PATCH] ARM: Move...
459
460
461
462
463
  }
  
  /*
   * The mem_map array can get very big.  Free the unused area of the memory map.
   */
be3703027   Russell King   ARM: Remove DISCO...
464
  static void __init free_unused_memmap(struct meminfo *mi)
a013053d4   Russell King   [PATCH] ARM: Move...
465
466
467
468
469
  {
  	unsigned long bank_start, prev_bank_end = 0;
  	unsigned int i;
  
  	/*
3260e5293   Michael Bohan   arm: mm: Don't fr...
470
471
  	 * This relies on each bank being in address order.
  	 * The banks are sorted previously in bootmem_init().
a013053d4   Russell King   [PATCH] ARM: Move...
472
  	 */
be3703027   Russell King   ARM: Remove DISCO...
473
  	for_each_bank(i, mi) {
d2a38ef9c   Russell King   [ARM] mm: provide...
474
475
476
  		struct membank *bank = &mi->bank[i];
  
  		bank_start = bank_pfn_start(bank);
a013053d4   Russell King   [PATCH] ARM: Move...
477

9af386c8d   Will Deacon   ARM: 6890/1: memm...
478
479
480
481
482
483
484
  #ifdef CONFIG_SPARSEMEM
  		/*
  		 * Take care not to free memmap entries that don't exist
  		 * due to SPARSEMEM sections which aren't present.
  		 */
  		bank_start = min(bank_start,
  				 ALIGN(prev_bank_end, PAGES_PER_SECTION));
002ea9eef   Linus Walleij   ARM: 7113/1: mm: ...
485
486
487
488
489
490
491
  #else
  		/*
  		 * Align down here since the VM subsystem insists that the
  		 * memmap entries are valid from the bank start aligned to
  		 * MAX_ORDER_NR_PAGES.
  		 */
  		bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
9af386c8d   Will Deacon   ARM: 6890/1: memm...
492
  #endif
a013053d4   Russell King   [PATCH] ARM: Move...
493
494
495
496
  		/*
  		 * If we had a previous bank, and there is a space
  		 * between the current bank and the previous, free it.
  		 */
3260e5293   Michael Bohan   arm: mm: Don't fr...
497
  		if (prev_bank_end && prev_bank_end < bank_start)
be3703027   Russell King   ARM: Remove DISCO...
498
  			free_memmap(prev_bank_end, bank_start);
a013053d4   Russell King   [PATCH] ARM: Move...
499

3260e5293   Michael Bohan   arm: mm: Don't fr...
500
501
502
503
504
505
  		/*
  		 * Align up here since the VM subsystem insists that the
  		 * memmap entries are valid from the bank end aligned to
  		 * MAX_ORDER_NR_PAGES.
  		 */
  		prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
a013053d4   Russell King   [PATCH] ARM: Move...
506
  	}
9af386c8d   Will Deacon   ARM: 6890/1: memm...
507
508
509
510
511
512
  
  #ifdef CONFIG_SPARSEMEM
  	if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION))
  		free_memmap(prev_bank_end,
  			    ALIGN(prev_bank_end, PAGES_PER_SECTION));
  #endif
a013053d4   Russell King   [PATCH] ARM: Move...
513
  }
d0e775afb   Russell King   ARM: move freeing...
514
515
516
  static void __init free_highpages(void)
  {
  #ifdef CONFIG_HIGHMEM
df4f14c7b   Russell King   ARM: memblock: co...
517
518
  	unsigned long max_low = max_low_pfn + PHYS_PFN_OFFSET;
  	struct memblock_region *mem, *res;
d0e775afb   Russell King   ARM: move freeing...
519
520
  
  	/* set highmem page free */
df4f14c7b   Russell King   ARM: memblock: co...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  	for_each_memblock(memory, mem) {
  		unsigned long start = memblock_region_memory_base_pfn(mem);
  		unsigned long end = memblock_region_memory_end_pfn(mem);
  
  		/* Ignore complete lowmem entries */
  		if (end <= max_low)
  			continue;
  
  		/* Truncate partial highmem entries */
  		if (start < max_low)
  			start = max_low;
  
  		/* Find and exclude any reserved regions */
  		for_each_memblock(reserved, res) {
  			unsigned long res_start, res_end;
  
  			res_start = memblock_region_reserved_base_pfn(res);
  			res_end = memblock_region_reserved_end_pfn(res);
  
  			if (res_end < start)
  				continue;
  			if (res_start < start)
  				res_start = start;
  			if (res_start > end)
  				res_start = end;
  			if (res_end > end)
  				res_end = end;
  			if (res_start != start)
  				totalhigh_pages += free_area(start, res_start,
  							     NULL);
  			start = res_end;
  			if (start == end)
  				break;
  		}
  
  		/* And now free anything which remains */
  		if (start < end)
d0e775afb   Russell King   ARM: move freeing...
558
559
560
561
562
  			totalhigh_pages += free_area(start, end, NULL);
  	}
  	totalram_pages += totalhigh_pages;
  #endif
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
567
568
569
  /*
   * mem_init() marks the free areas in the mem_map and tells us how much
   * memory is free.  This is done after various parts of the system have
   * claimed their memory after the kernel image.
   */
  void __init mem_init(void)
  {
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
570
  	unsigned long reserved_pages, free_pages;
47ea3c154   Russell King   ARM: memblock: co...
571
  	struct memblock_region *reg;
be3703027   Russell King   ARM: Remove DISCO...
572
  	int i;
1dbd30e98   Linus Walleij   ARM: 6225/1: make...
573
574
575
576
577
  #ifdef CONFIG_HAVE_TCM
  	/* These pointers are filled in on TCM detection */
  	extern u32 dtcm_end;
  	extern u32 itcm_end;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578

3835f6cb6   Nicolas Pitre   [ARM] mem_init():...
579
  	max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  	/* this will put all unused low memory onto the freelists */
be3703027   Russell King   ARM: Remove DISCO...
582
  	free_unused_memmap(&meminfo);
a013053d4   Russell King   [PATCH] ARM: Move...
583

be3703027   Russell King   ARM: Remove DISCO...
584
  	totalram_pages += free_all_bootmem();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
  
  #ifdef CONFIG_SA1111
  	/* now that our DMA memory is actually so designated, we can free it */
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
588
589
  	totalram_pages += free_area(PHYS_PFN_OFFSET,
  				    __phys_to_pfn(__pa(swapper_pg_dir)), NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  #endif
d0e775afb   Russell King   ARM: move freeing...
591
  	free_highpages();
3835f6cb6   Nicolas Pitre   [ARM] mem_init():...
592

db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
593
  	reserved_pages = free_pages = 0;
be3703027   Russell King   ARM: Remove DISCO...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  	for_each_bank(i, &meminfo) {
  		struct membank *bank = &meminfo.bank[i];
  		unsigned int pfn1, pfn2;
  		struct page *page, *end;
  
  		pfn1 = bank_pfn_start(bank);
  		pfn2 = bank_pfn_end(bank);
  
  		page = pfn_to_page(pfn1);
  		end  = pfn_to_page(pfn2 - 1) + 1;
  
  		do {
  			if (PageReserved(page))
  				reserved_pages++;
  			else if (!page_count(page))
  				free_pages++;
  			page++;
  		} while (page < end);
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
612
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
  	/*
  	 * Since our memory may not be contiguous, calculate the
  	 * real number of pages we have in this system
  	 */
  	printk(KERN_INFO "Memory:");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  	num_physpages = 0;
47ea3c154   Russell King   ARM: memblock: co...
619
620
621
622
623
  	for_each_memblock(memory, reg) {
  		unsigned long pages = memblock_region_memory_end_pfn(reg) -
  			memblock_region_memory_base_pfn(reg);
  		num_physpages += pages;
  		printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
  	printk(" = %luMB total
  ", num_physpages >> (20 - PAGE_SHIFT));
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
627

db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
628
629
630
631
632
  	printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem
  ",
  		nr_free_pages() << (PAGE_SHIFT-10),
  		free_pages << (PAGE_SHIFT-10),
  		reserved_pages << (PAGE_SHIFT-10),
4b529401c   Andreas Fenkart   mm: make totalhig...
633
  		totalhigh_pages << (PAGE_SHIFT-10));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634

db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
635
636
637
638
639
640
641
642
  #define MLK(b, t) b, t, ((t) - (b)) >> 10
  #define MLM(b, t) b, t, ((t) - (b)) >> 20
  #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
  
  	printk(KERN_NOTICE "Virtual kernel memory layout:
  "
  			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)
  "
07d2a5c72   Linus Walleij   ARM: 6224/1: prin...
643
  #ifdef CONFIG_HAVE_TCM
07d2a5c72   Linus Walleij   ARM: 6224/1: prin...
644
645
  			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)
  "
07d2a5c72   Linus Walleij   ARM: 6224/1: prin...
646
647
648
  			"    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)
  "
  #endif
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
649
650
651
652
653
654
655
656
657
658
659
660
  			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)
  "
  			"    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)
  "
  			"    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)
  "
  #ifdef CONFIG_HIGHMEM
  			"    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)
  "
  #endif
  			"    modules : 0x%08lx - 0x%08lx   (%4ld MB)
  "
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
661
662
  			"      .text : 0x%p" " - 0x%p" "   (%4d kB)
  "
3835d69a6   Russell King   ARM: vmlinux.lds:...
663
664
  			"      .init : 0x%p" " - 0x%p" "   (%4d kB)
  "
45f6d7e0e   Rabin Vincent   ARM: 6951/1: incl...
665
666
667
668
  			"      .data : 0x%p" " - 0x%p" "   (%4d kB)
  "
  			"       .bss : 0x%p" " - 0x%p" "   (%4d kB)
  ",
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
669
670
671
  
  			MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
  				(PAGE_SIZE)),
07d2a5c72   Linus Walleij   ARM: 6224/1: prin...
672
  #ifdef CONFIG_HAVE_TCM
1dbd30e98   Linus Walleij   ARM: 6225/1: make...
673
674
  			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
  			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
07d2a5c72   Linus Walleij   ARM: 6224/1: prin...
675
  #endif
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
676
  			MLK(FIXADDR_START, FIXADDR_TOP),
c931b4f65   Fenkart/Bostandzhyan   ARM: 5928/1: Chan...
677
  			MLM(VMALLOC_START, VMALLOC_END),
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
678
679
680
681
682
683
  			MLM(PAGE_OFFSET, (unsigned long)high_memory),
  #ifdef CONFIG_HIGHMEM
  			MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
  				(PAGE_SIZE)),
  #endif
  			MLM(MODULES_VADDR, MODULES_END),
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
684
  			MLK_ROUNDUP(_text, _etext),
3835d69a6   Russell King   ARM: vmlinux.lds:...
685
  			MLK_ROUNDUP(__init_begin, __init_end),
45f6d7e0e   Rabin Vincent   ARM: 6951/1: incl...
686
687
  			MLK_ROUNDUP(_sdata, _edata),
  			MLK_ROUNDUP(__bss_start, __bss_stop));
db9ef1af4   Fenkart/Bostandzhyan   ARM: 5926/1: Add ...
688
689
690
691
  
  #undef MLK
  #undef MLM
  #undef MLK_ROUNDUP
a18392721   Fenkart/Bostandzhyan   ARM: 5929/1: Add ...
692
693
694
695
696
  	/*
  	 * Check boundaries twice: Some fundamental inconsistencies can
  	 * be detected at build time already.
  	 */
  #ifdef CONFIG_MMU
a18392721   Fenkart/Bostandzhyan   ARM: 5929/1: Add ...
697
698
699
700
701
702
703
704
  	BUILD_BUG_ON(TASK_SIZE				> MODULES_VADDR);
  	BUG_ON(TASK_SIZE 				> MODULES_VADDR);
  #endif
  
  #ifdef CONFIG_HIGHMEM
  	BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > PAGE_OFFSET);
  	BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE	> PAGE_OFFSET);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
709
710
711
712
713
714
715
716
717
  	if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
  		extern int sysctl_overcommit_memory;
  		/*
  		 * On a machine this small we won't get
  		 * anywhere without overcommit, so turn
  		 * it on by default.
  		 */
  		sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
  	}
  }
  
  void free_initmem(void)
  {
bc581770c   Linus Walleij   ARM: 5580/2: ARM ...
718
  #ifdef CONFIG_HAVE_TCM
ea208f646   Linus Walleij   ARM: 6144/1: TCM ...
719
  	extern char __tcm_start, __tcm_end;
bc581770c   Linus Walleij   ARM: 5580/2: ARM ...
720

54d525735   Stephen Boyd   ARM: 6996/1: mm: ...
721
  	poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start);
ea208f646   Linus Walleij   ARM: 6144/1: TCM ...
722
723
  	totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)),
  				    __phys_to_pfn(__pa(&__tcm_end)),
bc581770c   Linus Walleij   ARM: 5580/2: ARM ...
724
725
  				    "TCM link");
  #endif
54d525735   Stephen Boyd   ARM: 6996/1: mm: ...
726
  	poison_init_mem(__init_begin, __init_end - __init_begin);
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
727
  	if (!machine_is_integrator() && !machine_is_cintegrator())
37efe6427   Russell King   [ARM] use asm/sec...
728
729
  		totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
  					    __phys_to_pfn(__pa(__init_end)),
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
730
  					    "init");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
736
737
738
  }
  
  #ifdef CONFIG_BLK_DEV_INITRD
  
  static int keep_initrd;
  
  void free_initrd_mem(unsigned long start, unsigned long end)
  {
54d525735   Stephen Boyd   ARM: 6996/1: mm: ...
739
740
  	if (!keep_initrd) {
  		poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
6db015e49   Nicolas Pitre   [ARM] mem_init() ...
741
742
743
  		totalram_pages += free_area(__phys_to_pfn(__pa(start)),
  					    __phys_to_pfn(__pa(end)),
  					    "initrd");
54d525735   Stephen Boyd   ARM: 6996/1: mm: ...
744
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
747
748
749
750
751
752
753
754
  }
  
  static int __init keepinitrd_setup(char *__unused)
  {
  	keep_initrd = 1;
  	return 1;
  }
  
  __setup("keepinitrd", keepinitrd_setup);
  #endif