init.c 6.85 KB
Newer Older
1
2
/*
 * linux/arch/sh/mm/init.c
Linus Torvalds's avatar
Linus Torvalds committed
3
4
 *
 *  Copyright (C) 1999  Niibe Yutaka
5
 *  Copyright (C) 2002 - 2007  Paul Mundt
Linus Torvalds's avatar
Linus Torvalds committed
6
7
8
9
10
11
12
13
 *
 *  Based on linux/arch/i386/mm/init.c:
 *   Copyright (C) 1995  Linus Torvalds
 */
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/init.h>
#include <linux/bootmem.h>
Paul Mundt's avatar
Paul Mundt committed
14
#include <linux/proc_fs.h>
15
16
#include <linux/percpu.h>
#include <linux/io.h>
Linus Torvalds's avatar
Linus Torvalds committed
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <asm/mmu_context.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
#include <asm/cache.h>

DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];

void (*copy_page)(void *from, void *to);
void (*clear_page)(void *to);

void show_mem(void)
{
30
31
32
	int total = 0, reserved = 0, free = 0;
	int shared = 0, cached = 0, slab = 0;
	pg_data_t *pgdat;
Linus Torvalds's avatar
Linus Torvalds committed
33
34
35

	printk("Mem-info:\n");
	show_free_areas();
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

	for_each_online_pgdat(pgdat) {
		struct page *page, *end;
		unsigned long flags;

		pgdat_resize_lock(pgdat, &flags);
		page = pgdat->node_mem_map;
		end = page + pgdat->node_spanned_pages;

		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);

		pgdat_resize_unlock(pgdat, &flags);
Linus Torvalds's avatar
Linus Torvalds committed
61
	}
62
63
64
65
66
67
68
69

	printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
	printk("%d pages of RAM\n", total);
	printk("%d free pages\n", free);
	printk("%d reserved pages\n", reserved);
	printk("%d slab pages\n", slab);
	printk("%d pages shared\n", shared);
	printk("%d pages swap cached\n", cached);
Paul Mundt's avatar
Paul Mundt committed
70
71
	printk(KERN_INFO "Total of %ld pages in page table cache\n",
	       quicklist_total_size());
Linus Torvalds's avatar
Linus Torvalds committed
72
73
}

74
#ifdef CONFIG_MMU
Linus Torvalds's avatar
Linus Torvalds committed
75
76
77
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
{
	pgd_t *pgd;
78
	pud_t *pud;
Linus Torvalds's avatar
Linus Torvalds committed
79
80
81
	pmd_t *pmd;
	pte_t *pte;

Stuart Menefy's avatar
Stuart Menefy committed
82
	pgd = pgd_offset_k(addr);
Linus Torvalds's avatar
Linus Torvalds committed
83
84
85
86
87
	if (pgd_none(*pgd)) {
		pgd_ERROR(*pgd);
		return;
	}

Stuart Menefy's avatar
Stuart Menefy committed
88
89
90
91
	pud = pud_alloc(NULL, pgd, addr);
	if (unlikely(!pud)) {
		pud_ERROR(*pud);
		return;
92
93
	}

Stuart Menefy's avatar
Stuart Menefy committed
94
95
96
97
	pmd = pmd_alloc(NULL, pud, addr);
	if (unlikely(!pmd)) {
		pmd_ERROR(*pmd);
		return;
Linus Torvalds's avatar
Linus Torvalds committed
98
99
100
101
102
103
104
105
106
107
	}

	pte = pte_offset_kernel(pmd, addr);
	if (!pte_none(*pte)) {
		pte_ERROR(*pte);
		return;
	}

	set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));

108
	flush_tlb_one(get_asid(), addr);
Linus Torvalds's avatar
Linus Torvalds committed
109
110
111
112
113
114
}

/*
 * As a performance optimization, other platforms preserve the fixmap mapping
 * across a context switch, we don't presently do this, but this could be done
 * in a similar fashion as to the wired TLB interface that sh64 uses (by way
Simon Arlott's avatar
Simon Arlott committed
115
 * of the memory mapped UTLB configuration) -- this unfortunately forces us to
Linus Torvalds's avatar
Linus Torvalds committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
 * give up a TLB entry for each mapping we want to preserve. While this may be
 * viable for a small number of fixmaps, it's not particularly useful for
 * everything and needs to be carefully evaluated. (ie, we may want this for
 * the vsyscall page).
 *
 * XXX: Perhaps add a _PAGE_WIRED flag or something similar that we can pass
 * in at __set_fixmap() time to determine the appropriate behavior to follow.
 *
 *					 -- PFM.
 */
void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
{
	unsigned long address = __fix_to_virt(idx);

	if (idx >= __end_of_fixed_addresses) {
		BUG();
		return;
	}

	set_pte_phys(address, phys, prot);
}
137
#endif	/* CONFIG_MMU */
Linus Torvalds's avatar
Linus Torvalds committed
138
139
140
141
142
143
144
145
146
147
148

/* References to section boundaries */

extern char _text, _etext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;

/*
 * paging_init() sets up the page tables
 */
void __init paging_init(void)
{
149
	int nid;
Linus Torvalds's avatar
Linus Torvalds committed
150

151
152
153
154
	/* We don't need to map the kernel through the TLB, as
	 * it is permanatly mapped using P1. So clear the
	 * entire pgd. */
	memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
Linus Torvalds's avatar
Linus Torvalds committed
155

156
157
158
159
	/* Set an initial value for the MMU.TTB so we don't have to
	 * check for a null value. */
	set_TTB(swapper_pg_dir);

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
	for_each_online_node(nid) {
		pg_data_t *pgdat = NODE_DATA(nid);
		unsigned long max_zone_pfns[MAX_NR_ZONES];
		unsigned long low, start_pfn;

		memset(max_zone_pfns, 0, sizeof(max_zone_pfns));

		start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT;
		low = pgdat->bdata->node_low_pfn;

		max_zone_pfns[ZONE_NORMAL] = low;
		add_active_range(nid, start_pfn, low);

		printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n",
		       nid, start_pfn, low);

		free_area_init_nodes(max_zone_pfns);

		printk("Node %u: mem_map starts at %p\n",
		       pgdat->node_id, pgdat->node_mem_map);
	}
Linus Torvalds's avatar
Linus Torvalds committed
181
182
}

Paul Mundt's avatar
Paul Mundt committed
183
184
static struct kcore_list kcore_mem, kcore_vmalloc;

Linus Torvalds's avatar
Linus Torvalds committed
185
186
187
void __init mem_init(void)
{
	int codesize, reservedpages, datasize, initsize;
188
	int nid;
Linus Torvalds's avatar
Linus Torvalds committed
189

190
	reservedpages = 0;
Linus Torvalds's avatar
Linus Torvalds committed
191

192
193
194
195
196
197
198
199
200
201
202
203
	for_each_online_node(nid) {
		pg_data_t *pgdat = NODE_DATA(nid);
		unsigned long node_pages = 0;
		void *node_high_memory;
		int i;

		num_physpages += pgdat->node_present_pages;

		if (pgdat->node_spanned_pages)
			node_pages = free_all_bootmem_node(pgdat);

		totalram_pages += node_pages;
Linus Torvalds's avatar
Linus Torvalds committed
204

205
206
207
208
209
210
211
212
213
214
		for (i = 0; i < node_pages; i++)
			if (PageReserved(pgdat->node_mem_map + i))
				reservedpages++;

		node_high_memory = (void *)((pgdat->node_start_pfn +
					     pgdat->node_spanned_pages) <<
						PAGE_SHIFT);
		if (node_high_memory > high_memory)
			high_memory = node_high_memory;
	}
Linus Torvalds's avatar
Linus Torvalds committed
215
216
217
218
219

	/* clear the zero-page */
	memset(empty_zero_page, 0, PAGE_SIZE);
	__flush_wback_region(empty_zero_page, PAGE_SIZE);

220
	/*
Linus Torvalds's avatar
Linus Torvalds committed
221
222
223
	 * Setup wrappers for copy/clear_page(), these will get overridden
	 * later in the boot process if a better method is available.
	 */
Yoshinori Sato's avatar
Yoshinori Sato committed
224
#ifdef CONFIG_MMU
Linus Torvalds's avatar
Linus Torvalds committed
225
226
	copy_page = copy_page_slow;
	clear_page = clear_page_slow;
Yoshinori Sato's avatar
Yoshinori Sato committed
227
228
229
230
#else
	copy_page = copy_page_nommu;
	clear_page = clear_page_nommu;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
231
232
233
234
235

	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;

Paul Mundt's avatar
Paul Mundt committed
236
237
238
239
240
241
	kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
	kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
		   VMALLOC_END - VMALLOC_START);

	printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
	       "%dk reserved, %dk data, %dk init)\n",
Linus Torvalds's avatar
Linus Torvalds committed
242
		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
243
		totalram_pages << (PAGE_SHIFT-10),
Linus Torvalds's avatar
Linus Torvalds committed
244
245
246
247
248
249
		codesize >> 10,
		reservedpages << (PAGE_SHIFT-10),
		datasize >> 10,
		initsize >> 10);

	p3_cache_init();
250
251
252

	/* Initialize the vDSO */
	vsyscall_init();
Linus Torvalds's avatar
Linus Torvalds committed
253
254
255
256
257
}

void free_initmem(void)
{
	unsigned long addr;
258

Linus Torvalds's avatar
Linus Torvalds committed
259
260
261
	addr = (unsigned long)(&__init_begin);
	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
		ClearPageReserved(virt_to_page(addr));
262
		init_page_count(virt_to_page(addr));
Linus Torvalds's avatar
Linus Torvalds committed
263
264
265
266
267
268
269
270
271
272
273
274
		free_page(addr);
		totalram_pages++;
	}
	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
}

#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
	unsigned long p;
	for (p = start; p < end; p += PAGE_SIZE) {
		ClearPageReserved(virt_to_page(p));
275
		init_page_count(virt_to_page(p));
Linus Torvalds's avatar
Linus Torvalds committed
276
277
278
279
280
281
		free_page(p);
		totalram_pages++;
	}
	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
}
#endif