From 827c829b996d4b6006b64bb611233da7cb8beb3b Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 16 Oct 2007 01:24:17 -0700 Subject: [PATCH] --- yaml --- r: 69587 b: refs/heads/master c: d29eff7bca60c9ee401d691d4562a4abca8de543 h: refs/heads/master i: 69585: 51d477ac2753d3288a34393071e6e4f97e317a64 69583: cad3eb787b1010e97a92fdd22e9648a881ae72ae v: v3 --- [refs] | 2 +- trunk/arch/powerpc/Kconfig | 1 + trunk/arch/powerpc/mm/init_64.c | 67 +++++++++++++++++++++++ trunk/include/asm-powerpc/pgtable-ppc64.h | 8 +++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 543e04acb8de..04138d4ad102 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 46644c2477c58906e95281636d04e9cc42b39352 +refs/heads/master: d29eff7bca60c9ee401d691d4562a4abca8de543 diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig index 037664d496d7..5e001ad588a7 100644 --- a/trunk/arch/powerpc/Kconfig +++ b/trunk/arch/powerpc/Kconfig @@ -295,6 +295,7 @@ config ARCH_FLATMEM_ENABLE config ARCH_SPARSEMEM_ENABLE def_bool y depends on PPC64 + select SPARSEMEM_VMEMMAP_ENABLE config ARCH_SPARSEMEM_DEFAULT def_bool y diff --git a/trunk/arch/powerpc/mm/init_64.c b/trunk/arch/powerpc/mm/init_64.c index fa90f6561b9f..29ed495444f5 100644 --- a/trunk/arch/powerpc/mm/init_64.c +++ b/trunk/arch/powerpc/mm/init_64.c @@ -183,3 +183,70 @@ void pgtable_cache_init(void) zero_ctor); } } + +#ifdef CONFIG_SPARSEMEM_VMEMMAP +/* + * Given an address within the vmemmap, determine the pfn of the page that + * represents the start of the section it is within. Note that we have to + * do this by hand as the proffered address may not be correctly aligned. + * Subtraction of non-aligned pointers produces undefined results. + */ +unsigned long __meminit vmemmap_section_start(unsigned long page) +{ + unsigned long offset = page - ((unsigned long)(vmemmap)); + + /* Return the pfn of the start of the section. */ + return (offset / sizeof(struct page)) & PAGE_SECTION_MASK; +} + +/* + * Check if this vmemmap page is already initialised. If any section + * which overlaps this vmemmap page is initialised then this page is + * initialised already. + */ +int __meminit vmemmap_populated(unsigned long start, int page_size) +{ + unsigned long end = start + page_size; + + for (; start < end; start += (PAGES_PER_SECTION * sizeof(struct page))) + if (pfn_valid(vmemmap_section_start(start))) + return 1; + + return 0; +} + +int __meminit vmemmap_populate(struct page *start_page, + unsigned long nr_pages, int node) +{ + unsigned long mode_rw; + unsigned long start = (unsigned long)start_page; + unsigned long end = (unsigned long)(start_page + nr_pages); + unsigned long page_size = 1 << mmu_psize_defs[mmu_linear_psize].shift; + + mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; + + /* Align to the page size of the linear mapping. */ + start = _ALIGN_DOWN(start, page_size); + + for (; start < end; start += page_size) { + int mapped; + void *p; + + if (vmemmap_populated(start, page_size)) + continue; + + p = vmemmap_alloc_block(page_size, node); + if (!p) + return -ENOMEM; + + printk(KERN_WARNING "vmemmap %08lx allocated at %p, " + "physical %p.\n", start, p, __pa(p)); + + mapped = htab_bolt_mapping(start, start + page_size, + __pa(p), mode_rw, mmu_linear_psize); + BUG_ON(mapped < 0); + } + + return 0; +} +#endif diff --git a/trunk/include/asm-powerpc/pgtable-ppc64.h b/trunk/include/asm-powerpc/pgtable-ppc64.h index 300f9a199bf2..dd4c26dc57d2 100644 --- a/trunk/include/asm-powerpc/pgtable-ppc64.h +++ b/trunk/include/asm-powerpc/pgtable-ppc64.h @@ -67,6 +67,14 @@ #define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET)) #define USER_REGION_ID (0UL) +/* + * Defines the address of the vmemap area, in the top 16th of the + * kernel region. + */ +#define VMEMMAP_BASE (ASM_CONST(CONFIG_KERNEL_START) + \ + (0xfUL << (REGION_SHIFT - 4))) +#define vmemmap ((struct page *)VMEMMAP_BASE) + /* * Common bits in a linux-style PTE. These match the bits in the * (hardware-defined) PowerPC PTE as closely as possible. Additional