init.c 8.7 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
#include <linux/pagemap.h>
16 17
#include <linux/percpu.h>
#include <linux/io.h>
18
#include <linux/dma-mapping.h>
L
Linus Torvalds 已提交
19 20 21
#include <asm/mmu_context.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
22
#include <asm/sections.h>
L
Linus Torvalds 已提交
23 24 25 26
#include <asm/cache.h>

DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];
27 28 29 30 31 32 33 34 35 36 37 38 39

#ifdef CONFIG_SUPERH32
/*
 * Handle trivial transitions between cached and uncached
 * segments, making use of the 1:1 mapping relationship in
 * 512MB lowmem.
 *
 * This is the offset of the uncached section from its cached alias.
 * Default value only valid in 29 bit mode, in 32bit mode will be
 * overridden in pmb_init.
 */
unsigned long cached_to_uncached = P2SEG - P1SEG;
#endif
L
Linus Torvalds 已提交
40

41
#ifdef CONFIG_MMU
42
static pte_t *__get_pte_phys(unsigned long addr)
L
Linus Torvalds 已提交
43 44
{
	pgd_t *pgd;
45
	pud_t *pud;
L
Linus Torvalds 已提交
46 47 48
	pmd_t *pmd;
	pte_t *pte;

S
Stuart Menefy 已提交
49
	pgd = pgd_offset_k(addr);
L
Linus Torvalds 已提交
50 51
	if (pgd_none(*pgd)) {
		pgd_ERROR(*pgd);
52
		return NULL;
L
Linus Torvalds 已提交
53 54
	}

S
Stuart Menefy 已提交
55 56 57
	pud = pud_alloc(NULL, pgd, addr);
	if (unlikely(!pud)) {
		pud_ERROR(*pud);
58
		return NULL;
59 60
	}

S
Stuart Menefy 已提交
61 62 63
	pmd = pmd_alloc(NULL, pud, addr);
	if (unlikely(!pmd)) {
		pmd_ERROR(*pmd);
64
		return NULL;
L
Linus Torvalds 已提交
65 66 67
	}

	pte = pte_offset_kernel(pmd, addr);
68 69 70 71 72 73 74 75
	return pte;
}

static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
{
	pte_t *pte;

	pte = __get_pte_phys(addr);
L
Linus Torvalds 已提交
76 77 78 79 80 81
	if (!pte_none(*pte)) {
		pte_ERROR(*pte);
		return;
	}

	set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));
82
	local_flush_tlb_one(get_asid(), addr);
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

	if (pgprot_val(prot) & _PAGE_WIRED)
		tlb_wire_entry(NULL, addr, *pte);
}

static void clear_pte_phys(unsigned long addr, pgprot_t prot)
{
	pte_t *pte;

	pte = __get_pte_phys(addr);

	if (pgprot_val(prot) & _PAGE_WIRED)
		tlb_unwire_entry();

	set_pte(pte, pfn_pte(0, __pgprot(0)));
	local_flush_tlb_one(get_asid(), addr);
L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107 108 109 110 111
}

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

113 114 115 116 117 118 119 120 121 122 123 124
void __clear_fixmap(enum fixed_addresses idx, pgprot_t prot)
{
	unsigned long address = __fix_to_virt(idx);

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

	clear_pte_phys(address, prot);
}

125 126 127 128 129 130
void __init page_table_range_init(unsigned long start, unsigned long end,
					 pgd_t *pgd_base)
{
	pgd_t *pgd;
	pud_t *pud;
	pmd_t *pmd;
131 132
	pte_t *pte;
	int i, j, k;
133 134
	unsigned long vaddr;

135 136 137 138 139 140 141 142 143
	vaddr = start;
	i = __pgd_offset(vaddr);
	j = __pud_offset(vaddr);
	k = __pmd_offset(vaddr);
	pgd = pgd_base + i;

	for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
		pud = (pud_t *)pgd;
		for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
144
#ifdef __PAGETABLE_PMD_FOLDED
145
			pmd = (pmd_t *)pud;
146 147 148 149 150
#else
			pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
			pud_populate(&init_mm, pud, pmd);
			pmd += k;
#endif
151 152 153 154 155 156 157 158 159
			for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
				if (pmd_none(*pmd)) {
					pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
					pmd_populate_kernel(&init_mm, pmd, pte);
					BUG_ON(pte != pte_offset_kernel(pmd, 0));
				}
				vaddr += PMD_SIZE;
			}
			k = 0;
160
		}
161
		j = 0;
162 163
	}
}
164
#endif	/* CONFIG_MMU */
L
Linus Torvalds 已提交
165 166 167 168 169 170

/*
 * paging_init() sets up the page tables
 */
void __init paging_init(void)
{
171
	unsigned long max_zone_pfns[MAX_NR_ZONES];
172
	unsigned long vaddr, end;
173
	int nid;
L
Linus Torvalds 已提交
174

175 176 177 178
	/* 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 已提交
179

180 181 182 183
	/* Set an initial value for the MMU.TTB so we don't have to
	 * check for a null value. */
	set_TTB(swapper_pg_dir);

184 185
	/*
	 * Populate the relevant portions of swapper_pg_dir so that
186
	 * we can use the fixmap entries without calling kmalloc.
187 188 189
	 * pte's will be filled in by __set_fixmap().
	 */
	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
190 191
	end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
	page_table_range_init(vaddr, end, swapper_pg_dir);
192 193

	kmap_coherent_init();
194

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

197 198 199 200
	for_each_online_node(nid) {
		pg_data_t *pgdat = NODE_DATA(nid);
		unsigned long low, start_pfn;

201
		start_pfn = pgdat->bdata->node_min_pfn;
202 203
		low = pgdat->bdata->node_low_pfn;

204 205
		if (max_zone_pfns[ZONE_NORMAL] < low)
			max_zone_pfns[ZONE_NORMAL] = low;
206 207 208 209

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

	free_area_init_nodes(max_zone_pfns);
212 213 214

	/* Set up the uncached fixmap */
	set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
L
Linus Torvalds 已提交
215 216
}

217 218 219 220 221 222 223 224
/*
 * Early initialization for any I/O MMUs we might have.
 */
static void __init iommu_init(void)
{
	no_iommu_init();
}

225 226
unsigned int mem_init_done = 0;

L
Linus Torvalds 已提交
227 228
void __init mem_init(void)
{
P
Paul Mundt 已提交
229
	int codesize, datasize, initsize;
230
	int nid;
L
Linus Torvalds 已提交
231

232 233
	iommu_init();

234 235 236
	num_physpages = 0;
	high_memory = NULL;

237 238 239 240 241 242 243 244 245 246 247
	for_each_online_node(nid) {
		pg_data_t *pgdat = NODE_DATA(nid);
		unsigned long node_pages = 0;
		void *node_high_memory;

		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 已提交
248

249 250 251
		node_high_memory = (void *)__va((pgdat->node_start_pfn +
						 pgdat->node_spanned_pages) <<
						 PAGE_SHIFT);
252 253 254
		if (node_high_memory > high_memory)
			high_memory = node_high_memory;
	}
L
Linus Torvalds 已提交
255

256 257 258
	/* Set this up early, so we can take care of the zero page */
	cpu_cache_init();

L
Linus Torvalds 已提交
259 260 261 262
	/* clear the zero-page */
	memset(empty_zero_page, 0, PAGE_SIZE);
	__flush_wback_region(empty_zero_page, PAGE_SIZE);

263 264 265
	/* Initialize the vDSO */
	vsyscall_init();

L
Linus Torvalds 已提交
266 267 268 269
	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 已提交
270
	printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
P
Paul Mundt 已提交
271
	       "%dk data, %dk init)\n",
272
		nr_free_pages() << (PAGE_SHIFT-10),
273
		num_physpages << (PAGE_SHIFT-10),
L
Linus Torvalds 已提交
274 275 276 277
		codesize >> 10,
		datasize >> 10,
		initsize >> 10);

278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	printk(KERN_INFO "virtual kernel memory layout:\n"
		"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
#ifdef CONFIG_HIGHMEM
		"    pkmap   : 0x%08lx - 0x%08lx   (%4ld kB)\n"
#endif
		"    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
		"    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
		"      .init : 0x%08lx - 0x%08lx   (%4ld kB)\n"
		"      .data : 0x%08lx - 0x%08lx   (%4ld kB)\n"
		"      .text : 0x%08lx - 0x%08lx   (%4ld kB)\n",
		FIXADDR_START, FIXADDR_TOP,
		(FIXADDR_TOP - FIXADDR_START) >> 10,

#ifdef CONFIG_HIGHMEM
		PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE,
		(LAST_PKMAP*PAGE_SIZE) >> 10,
#endif

		(unsigned long)VMALLOC_START, VMALLOC_END,
		(VMALLOC_END - VMALLOC_START) >> 20,

		(unsigned long)memory_start, (unsigned long)high_memory,
		((unsigned long)high_memory - (unsigned long)memory_start) >> 20,

		(unsigned long)&__init_begin, (unsigned long)&__init_end,
		((unsigned long)&__init_end -
		 (unsigned long)&__init_begin) >> 10,

		(unsigned long)&_etext, (unsigned long)&_edata,
		((unsigned long)&_edata - (unsigned long)&_etext) >> 10,

		(unsigned long)&_text, (unsigned long)&_etext,
		((unsigned long)&_etext - (unsigned long)&_text) >> 10);
311 312

	mem_init_done = 1;
L
Linus Torvalds 已提交
313 314 315 316 317
}

void free_initmem(void)
{
	unsigned long addr;
318

L
Linus Torvalds 已提交
319 320 321
	addr = (unsigned long)(&__init_begin);
	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
		ClearPageReserved(virt_to_page(addr));
322
		init_page_count(virt_to_page(addr));
L
Linus Torvalds 已提交
323 324 325
		free_page(addr);
		totalram_pages++;
	}
326 327 328
	printk("Freeing unused kernel memory: %ldk freed\n",
	       ((unsigned long)&__init_end -
	        (unsigned long)&__init_begin) >> 10);
L
Linus Torvalds 已提交
329 330 331 332 333 334 335 336
}

#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));
337
		init_page_count(virt_to_page(p));
L
Linus Torvalds 已提交
338 339 340
		free_page(p);
		totalram_pages++;
	}
341
	printk("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
L
Linus Torvalds 已提交
342 343
}
#endif
344 345 346 347 348 349 350 351 352 353 354 355

#ifdef CONFIG_MEMORY_HOTPLUG
int arch_add_memory(int nid, u64 start, u64 size)
{
	pg_data_t *pgdat;
	unsigned long start_pfn = start >> PAGE_SHIFT;
	unsigned long nr_pages = size >> PAGE_SHIFT;
	int ret;

	pgdat = NODE_DATA(nid);

	/* We only have ZONE_NORMAL, so this is easy.. */
356 357
	ret = __add_pages(nid, pgdat->node_zones + ZONE_NORMAL,
				start_pfn, nr_pages);
358
	if (unlikely(ret))
359
		printk("%s: Failed, __add_pages() == %d\n", __func__, ret);
360 361 362 363 364

	return ret;
}
EXPORT_SYMBOL_GPL(arch_add_memory);

365
#ifdef CONFIG_NUMA
366 367 368 369 370 371 372
int memory_add_physaddr_to_nid(u64 addr)
{
	/* Node 0 for now.. */
	return 0;
}
EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif
M
Matt Fleming 已提交
373

374
#endif /* CONFIG_MEMORY_HOTPLUG */