init.c 6.8 KB
Newer Older
1 2
/*
 * linux/arch/sh/mm/init.c
L
Linus Torvalds 已提交
3 4
 *
 *  Copyright (C) 1999  Niibe Yutaka
5
 *  Copyright (C) 2002 - 2007  Paul Mundt
L
Linus Torvalds 已提交
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>
P
Paul Mundt 已提交
14
#include <linux/proc_fs.h>
15 16
#include <linux/percpu.h>
#include <linux/io.h>
L
Linus Torvalds 已提交
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;
L
Linus Torvalds 已提交
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);
L
Linus Torvalds 已提交
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);
P
Paul Mundt 已提交
70 71
	printk(KERN_INFO "Total of %ld pages in page table cache\n",
	       quicklist_total_size());
L
Linus Torvalds 已提交
72 73
}

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

S
Stuart Menefy 已提交
82
	pgd = pgd_offset_k(addr);
L
Linus Torvalds 已提交
83 84 85 86 87
	if (pgd_none(*pgd)) {
		pgd_ERROR(*pgd);
		return;
	}

S
Stuart Menefy 已提交
88 89 90 91
	pud = pud_alloc(NULL, pgd, addr);
	if (unlikely(!pud)) {
		pud_ERROR(*pud);
		return;
92 93
	}

S
Stuart Menefy 已提交
94 95 96 97
	pmd = pmd_alloc(NULL, pud, addr);
	if (unlikely(!pmd)) {
		pmd_ERROR(*pmd);
		return;
L
Linus Torvalds 已提交
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);
L
Linus Torvalds 已提交
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
}

/*
 * 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
 * of the memorry mapped UTLB configuration) -- this unfortunately forces us to
 * 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 */
L
Linus Torvalds 已提交
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;
L
Linus Torvalds 已提交
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));
L
Linus Torvalds 已提交
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);
	}
L
Linus Torvalds 已提交
181 182
}

P
Paul Mundt 已提交
183 184
static struct kcore_list kcore_mem, kcore_vmalloc;

L
Linus Torvalds 已提交
185 186 187
void __init mem_init(void)
{
	int codesize, reservedpages, datasize, initsize;
188
	int nid;
L
Linus Torvalds 已提交
189

190
	reservedpages = 0;
L
Linus Torvalds 已提交
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;
L
Linus Torvalds 已提交
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;
	}
L
Linus Torvalds 已提交
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
	/*
L
Linus Torvalds 已提交
221 222 223
	 * Setup wrappers for copy/clear_page(), these will get overridden
	 * later in the boot process if a better method is available.
	 */
Y
Yoshinori Sato 已提交
224
#ifdef CONFIG_MMU
L
Linus Torvalds 已提交
225 226
	copy_page = copy_page_slow;
	clear_page = clear_page_slow;
Y
Yoshinori Sato 已提交
227 228 229 230
#else
	copy_page = copy_page_nommu;
	clear_page = clear_page_nommu;
#endif
L
Linus Torvalds 已提交
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;

P
Paul Mundt 已提交
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",
L
Linus Torvalds 已提交
242
		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
243
		totalram_pages << (PAGE_SHIFT-10),
L
Linus Torvalds 已提交
244 245 246 247 248 249
		codesize >> 10,
		reservedpages << (PAGE_SHIFT-10),
		datasize >> 10,
		initsize >> 10);

	p3_cache_init();
P
Paul Mundt 已提交
250 251 252

	/* Initialize the vDSO */
	vsyscall_init();
L
Linus Torvalds 已提交
253 254 255 256 257
}

void free_initmem(void)
{
	unsigned long addr;
258

L
Linus Torvalds 已提交
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));
L
Linus Torvalds 已提交
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));
L
Linus Torvalds 已提交
276 277 278 279 280 281
		free_page(p);
		totalram_pages++;
	}
	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
}
#endif