void __init paging_init()

in mm/init_64.c [2275:2461]


void __init paging_init(void)
{
	unsigned long end_pfn, shift, phys_base;
	unsigned long real_end, i;

	setup_page_offset();

	/* These build time checkes make sure that the dcache_dirty_cpu()
	 * page->flags usage will work.
	 *
	 * When a page gets marked as dcache-dirty, we store the
	 * cpu number starting at bit 32 in the page->flags.  Also,
	 * functions like clear_dcache_dirty_cpu use the cpu mask
	 * in 13-bit signed-immediate instruction fields.
	 */

	/*
	 * Page flags must not reach into upper 32 bits that are used
	 * for the cpu number
	 */
	BUILD_BUG_ON(NR_PAGEFLAGS > 32);

	/*
	 * The bit fields placed in the high range must not reach below
	 * the 32 bit boundary. Otherwise we cannot place the cpu field
	 * at the 32 bit boundary.
	 */
	BUILD_BUG_ON(SECTIONS_WIDTH + NODES_WIDTH + ZONES_WIDTH +
		ilog2(roundup_pow_of_two(NR_CPUS)) > 32);

	BUILD_BUG_ON(NR_CPUS > 4096);

	kern_base = (prom_boot_mapping_phys_low >> ILOG2_4MB) << ILOG2_4MB;
	kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;

	/* Invalidate both kernel TSBs.  */
	memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
#ifndef CONFIG_DEBUG_PAGEALLOC
	memset(swapper_4m_tsb, 0x40, sizeof(swapper_4m_tsb));
#endif

	/* TTE.cv bit on sparc v9 occupies the same position as TTE.mcde
	 * bit on M7 processor. This is a conflicting usage of the same
	 * bit. Enabling TTE.cv on M7 would turn on Memory Corruption
	 * Detection error on all pages and this will lead to problems
	 * later. Kernel does not run with MCD enabled and hence rest
	 * of the required steps to fully configure memory corruption
	 * detection are not taken. We need to ensure TTE.mcde is not
	 * set on M7 processor. Compute the value of cacheability
	 * flag for use later taking this into consideration.
	 */
	switch (sun4v_chip_type) {
	case SUN4V_CHIP_SPARC_M7:
	case SUN4V_CHIP_SPARC_M8:
	case SUN4V_CHIP_SPARC_SN:
		page_cache4v_flag = _PAGE_CP_4V;
		break;
	default:
		page_cache4v_flag = _PAGE_CACHE_4V;
		break;
	}

	if (tlb_type == hypervisor)
		sun4v_pgprot_init();
	else
		sun4u_pgprot_init();

	if (tlb_type == cheetah_plus ||
	    tlb_type == hypervisor) {
		tsb_phys_patch();
		ktsb_phys_patch();
	}

	if (tlb_type == hypervisor)
		sun4v_patch_tlb_handlers();

	/* Find available physical memory...
	 *
	 * Read it twice in order to work around a bug in openfirmware.
	 * The call to grab this table itself can cause openfirmware to
	 * allocate memory, which in turn can take away some space from
	 * the list of available memory.  Reading it twice makes sure
	 * we really do get the final value.
	 */
	read_obp_translations();
	read_obp_memory("reg", &pall[0], &pall_ents);
	read_obp_memory("available", &pavail[0], &pavail_ents);
	read_obp_memory("available", &pavail[0], &pavail_ents);

	phys_base = 0xffffffffffffffffUL;
	for (i = 0; i < pavail_ents; i++) {
		phys_base = min(phys_base, pavail[i].phys_addr);
		memblock_add(pavail[i].phys_addr, pavail[i].reg_size);
	}

	memblock_reserve(kern_base, kern_size);

	find_ramdisk(phys_base);

	if (cmdline_memory_size)
		reduce_memory(cmdline_memory_size);

	memblock_allow_resize();
	memblock_dump_all();

	set_bit(0, mmu_context_bmap);

	shift = kern_base + PAGE_OFFSET - ((unsigned long)KERNBASE);

	real_end = (unsigned long)_end;
	num_kernel_image_mappings = DIV_ROUND_UP(real_end - KERNBASE, 1 << ILOG2_4MB);
	printk("Kernel: Using %d locked TLB entries for main kernel image.\n",
	       num_kernel_image_mappings);

	/* Set kernel pgd to upper alias so physical page computations
	 * work.
	 */
	init_mm.pgd += ((shift) / (sizeof(pgd_t)));
	
	memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));

	inherit_prom_mappings();
	
	/* Ok, we can use our TLB miss and window trap handlers safely.  */
	setup_tba();

	__flush_tlb_all();

	prom_build_devicetree();
	of_populate_present_mask();
#ifndef CONFIG_SMP
	of_fill_in_cpu_data();
#endif

	if (tlb_type == hypervisor) {
		sun4v_mdesc_init();
		mdesc_populate_present_mask(cpu_all_mask);
#ifndef CONFIG_SMP
		mdesc_fill_in_cpu_data(cpu_all_mask);
#endif
		mdesc_get_page_sizes(cpu_all_mask, &cpu_pgsz_mask);

		sun4v_linear_pte_xor_finalize();

		sun4v_ktsb_init();
		sun4v_ktsb_register();
	} else {
		unsigned long impl, ver;

		cpu_pgsz_mask = (HV_PGSZ_MASK_8K | HV_PGSZ_MASK_64K |
				 HV_PGSZ_MASK_512K | HV_PGSZ_MASK_4MB);

		__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
		impl = ((ver >> 32) & 0xffff);
		if (impl == PANTHER_IMPL)
			cpu_pgsz_mask |= (HV_PGSZ_MASK_32MB |
					  HV_PGSZ_MASK_256MB);

		sun4u_linear_pte_xor_finalize();
	}

	/* Flush the TLBs and the 4M TSB so that the updated linear
	 * pte XOR settings are realized for all mappings.
	 */
	__flush_tlb_all();
#ifndef CONFIG_DEBUG_PAGEALLOC
	memset(swapper_4m_tsb, 0x40, sizeof(swapper_4m_tsb));
#endif
	__flush_tlb_all();

	/* Setup bootmem... */
	last_valid_pfn = end_pfn = bootmem_init(phys_base);

	kernel_physical_mapping_init();

	{
		unsigned long max_zone_pfns[MAX_NR_ZONES];

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

		max_zone_pfns[ZONE_NORMAL] = end_pfn;

		free_area_init(max_zone_pfns);
	}

	printk("Booting Linux...\n");
}