diff options
Diffstat (limited to 'arch/powerpc/mm/mem.c')
| -rw-r--r-- | arch/powerpc/mm/mem.c | 207 | 
1 files changed, 134 insertions, 73 deletions
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index a6649965090..2c8e90f5789 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -17,7 +17,7 @@   *   */ -#include <linux/module.h> +#include <linux/export.h>  #include <linux/sched.h>  #include <linux/kernel.h>  #include <linux/errno.h> @@ -34,6 +34,7 @@  #include <linux/suspend.h>  #include <linux/memblock.h>  #include <linux/hugetlb.h> +#include <linux/slab.h>  #include <asm/pgalloc.h>  #include <asm/prom.h> @@ -50,6 +51,7 @@  #include <asm/vdso.h>  #include <asm/fixmap.h>  #include <asm/swiotlb.h> +#include <asm/rtas.h>  #include "mmu_decl.h" @@ -60,14 +62,13 @@  int init_bootmem_done;  int mem_init_done; -phys_addr_t memory_limit; +unsigned long long memory_limit;  #ifdef CONFIG_HIGHMEM  pte_t *kmap_pte; +EXPORT_SYMBOL(kmap_pte);  pgprot_t kmap_prot; -  EXPORT_SYMBOL(kmap_prot); -EXPORT_SYMBOL(kmap_pte);  static inline pte_t *virt_to_kpte(unsigned long vaddr)  { @@ -123,13 +124,31 @@ int arch_add_memory(int nid, u64 start, u64 size)  	pgdata = NODE_DATA(nid);  	start = (unsigned long)__va(start); -	create_section_mapping(start, start + size); +	if (create_section_mapping(start, start + size)) +		return -EINVAL;  	/* this should work for most non-highmem platforms */  	zone = pgdata->node_zones;  	return __add_pages(nid, zone, start_pfn, nr_pages);  } + +#ifdef CONFIG_MEMORY_HOTREMOVE +int arch_remove_memory(u64 start, u64 size) +{ +	unsigned long start_pfn = start >> PAGE_SHIFT; +	unsigned long nr_pages = size >> PAGE_SHIFT; +	struct zone *zone; +	int ret; + +	zone = page_zone(pfn_to_page(start_pfn)); +	ret = __remove_pages(zone, start_pfn, nr_pages); +	if (!ret && (ppc_md.remove_memory)) +		ret = ppc_md.remove_memory(start, size); + +	return ret; +} +#endif  #endif /* CONFIG_MEMORY_HOTPLUG */  /* @@ -192,13 +211,10 @@ void __init do_init_bootmem(void)  	min_low_pfn = MEMORY_START >> PAGE_SHIFT;  	boot_mapsize = init_bootmem_node(NODE_DATA(0), start >> PAGE_SHIFT, min_low_pfn, max_low_pfn); -	/* Add active regions with valid PFNs */ -	for_each_memblock(memory, reg) { -		unsigned long start_pfn, end_pfn; -		start_pfn = memblock_region_memory_base_pfn(reg); -		end_pfn = memblock_region_memory_end_pfn(reg); -		add_active_range(0, start_pfn, end_pfn); -	} +	/* Place all memblock_regions in the same node and merge contiguous +	 * memblock_regions +	 */ +	memblock_set_node(0, (phys_addr_t)ULLONG_MAX, &memblock.memory, 0);  	/* Add all physical memory to the bootmem map, mark each area  	 * present. @@ -249,7 +265,7 @@ static int __init mark_nonram_nosave(void)   */  void __init paging_init(void)  { -	unsigned long total_ram = memblock_phys_mem_size(); +	unsigned long long total_ram = memblock_phys_mem_size();  	phys_addr_t top_of_ram = memblock_end_of_DRAM();  	unsigned long max_zone_pfns[MAX_NR_ZONES]; @@ -269,7 +285,7 @@ void __init paging_init(void)  	kmap_prot = PAGE_KERNEL;  #endif /* CONFIG_HIGHMEM */ -	printk(KERN_DEBUG "Top of RAM: 0x%llx, Total RAM: 0x%lx\n", +	printk(KERN_DEBUG "Top of RAM: 0x%llx, Total RAM: 0x%llx\n",  	       (unsigned long long)top_of_ram, total_ram);  	printk(KERN_DEBUG "Memory hole size: %ldMB\n",  	       (long int)((top_of_ram - total_ram) >> 20)); @@ -286,50 +302,30 @@ void __init paging_init(void)  }  #endif /* ! CONFIG_NEED_MULTIPLE_NODES */ +static void __init register_page_bootmem_info(void) +{ +	int i; + +	for_each_online_node(i) +		register_page_bootmem_info_node(NODE_DATA(i)); +} +  void __init mem_init(void)  { -#ifdef CONFIG_NEED_MULTIPLE_NODES -	int nid; -#endif -	pg_data_t *pgdat; -	unsigned long i; -	struct page *page; -	unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; +	/* +	 * book3s is limited to 16 page sizes due to encoding this in +	 * a 4-bit field for slices. +	 */ +	BUILD_BUG_ON(MMU_PAGE_COUNT > 16);  #ifdef CONFIG_SWIOTLB -	if (ppc_swiotlb_enable) -		swiotlb_init(1); +	swiotlb_init(0);  #endif -	num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT; +	register_page_bootmem_info();  	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); - -#ifdef CONFIG_NEED_MULTIPLE_NODES -        for_each_online_node(nid) { -		if (NODE_DATA(nid)->node_spanned_pages != 0) { -			printk("freeing bootmem node %d\n", nid); -			totalram_pages += -				free_all_bootmem_node(NODE_DATA(nid)); -		} -	} -#else -	max_mapnr = max_pfn; -	totalram_pages += free_all_bootmem(); -#endif -	for_each_online_pgdat(pgdat) { -		for (i = 0; i < pgdat->node_spanned_pages; i++) { -			if (!pfn_valid(pgdat->node_start_pfn + i)) -				continue; -			page = pgdat_page_nr(pgdat, i); -			if (PageReserved(page)) -				reservedpages++; -		} -	} - -	codesize = (unsigned long)&_sdata - (unsigned long)&_stext; -	datasize = (unsigned long)&_edata - (unsigned long)&_sdata; -	initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; -	bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; +	set_max_mapnr(max_pfn); +	free_all_bootmem();  #ifdef CONFIG_HIGHMEM  	{ @@ -337,31 +333,24 @@ void __init mem_init(void)  		highmem_mapnr = lowmem_end_addr >> PAGE_SHIFT;  		for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { +			phys_addr_t paddr = (phys_addr_t)pfn << PAGE_SHIFT;  			struct page *page = pfn_to_page(pfn); -			if (memblock_is_reserved(pfn << PAGE_SHIFT)) -				continue; -			ClearPageReserved(page); -			init_page_count(page); -			__free_page(page); -			totalhigh_pages++; -			reservedpages--; +			if (!memblock_is_reserved(paddr)) +				free_highmem_page(page);  		} -		totalram_pages += totalhigh_pages; -		printk(KERN_DEBUG "High memory: %luk\n", -		       totalhigh_pages << (PAGE_SHIFT-10));  	}  #endif /* CONFIG_HIGHMEM */ -	printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, " -	       "%luk reserved, %luk data, %luk bss, %luk init)\n", -		nr_free_pages() << (PAGE_SHIFT-10), -		num_physpages << (PAGE_SHIFT-10), -		codesize >> 10, -		reservedpages << (PAGE_SHIFT-10), -		datasize >> 10, -		bsssize >> 10, -		initsize >> 10); +#if defined(CONFIG_PPC_FSL_BOOK3E) && !defined(CONFIG_SMP) +	/* +	 * If smp is enabled, next_tlbcam_idx is initialized in the cpu up +	 * functions.... do it here for the non-smp case. +	 */ +	per_cpu(next_tlbcam_idx, smp_processor_id()) = +		(mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) - 1; +#endif +	mem_init_print_info(NULL);  #ifdef CONFIG_PPC32  	pr_info("Kernel virtual memory layout:\n");  	pr_info("  * 0x%08lx..0x%08lx  : fixmap\n", FIXADDR_START, FIXADDR_TOP); @@ -382,6 +371,19 @@ void __init mem_init(void)  	mem_init_done = 1;  } +void free_initmem(void) +{ +	ppc_md.progress = ppc_printk_progress; +	free_initmem_default(POISON_FREE_INITMEM); +} + +#ifdef CONFIG_BLK_DEV_INITRD +void __init free_initrd_mem(unsigned long start, unsigned long end) +{ +	free_reserved_area((void *)start, (void *)end, -1, "initrd"); +} +#endif +  /*   * This is called when a page has been modified by the kernel.   * It just marks the page as not i-cache clean.  We do the i-cache @@ -407,9 +409,9 @@ void flush_dcache_icache_page(struct page *page)  #endif  #ifdef CONFIG_BOOKE  	{ -		void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE); +		void *start = kmap_atomic(page);  		__flush_dcache_icache(start); -		kunmap_atomic(start, KM_PPC_SYNC_ICACHE); +		kunmap_atomic(start);  	}  #elif defined(CONFIG_8xx) || defined(CONFIG_PPC64)  	/* On 8xx there is no need to kmap since highmem is not supported */ @@ -418,13 +420,14 @@ void flush_dcache_icache_page(struct page *page)  	__flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT);  #endif  } +EXPORT_SYMBOL(flush_dcache_icache_page);  void clear_user_page(void *page, unsigned long vaddr, struct page *pg)  {  	clear_page(page);  	/* -	 * We shouldnt have to do this, but some versions of glibc +	 * We shouldn't have to do this, but some versions of glibc  	 * require it (ld.so assumes zero filled pages are icache clean)  	 * - Anton  	 */ @@ -478,6 +481,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,  		      pte_t *ptep)  {  #ifdef CONFIG_PPC_STD_MMU +	/* +	 * We don't need to worry about _PAGE_PRESENT here because we are +	 * called with either mm->page_table_lock held or ptl lock held +	 */  	unsigned long access = 0, trap;  	/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */ @@ -500,4 +507,58 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,  		return;  	hash_preload(vma->vm_mm, address, access, trap);  #endif /* CONFIG_PPC_STD_MMU */ +#if (defined(CONFIG_PPC_BOOK3E_64) || defined(CONFIG_PPC_FSL_BOOK3E)) \ +	&& defined(CONFIG_HUGETLB_PAGE) +	if (is_vm_hugetlb_page(vma)) +		book3e_hugetlb_preload(vma, address, *ptep); +#endif +} + +/* + * System memory should not be in /proc/iomem but various tools expect it + * (eg kdump). + */ +static int __init add_system_ram_resources(void) +{ +	struct memblock_region *reg; + +	for_each_memblock(memory, reg) { +		struct resource *res; +		unsigned long base = reg->base; +		unsigned long size = reg->size; + +		res = kzalloc(sizeof(struct resource), GFP_KERNEL); +		WARN_ON(!res); + +		if (res) { +			res->name = "System RAM"; +			res->start = base; +			res->end = base + size - 1; +			res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; +			WARN_ON(request_resource(&iomem_resource, res) < 0); +		} +	} + +	return 0; +} +subsys_initcall(add_system_ram_resources); + +#ifdef CONFIG_STRICT_DEVMEM +/* + * devmem_is_allowed(): check to see if /dev/mem access to a certain address + * is valid. The argument is a physical page number. + * + * Access has to be given to non-kernel-ram areas as well, these contain the + * PCI mmio resources as well as potential bios/acpi data regions. + */ +int devmem_is_allowed(unsigned long pfn) +{ +	if (iomem_is_exclusive(pfn << PAGE_SHIFT)) +		return 0; +	if (!page_is_ram(pfn)) +		return 1; +	if (page_is_rtas_user_buf(pfn)) +		return 1; +	return 0;  } +#endif /* CONFIG_STRICT_DEVMEM */  | 
