diff options
author | David Miller <davem@davemloft.net> | 2007-10-16 01:24:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 09:42:51 -0700 |
commit | 46644c2477c58906e95281636d04e9cc42b39352 (patch) | |
tree | fd02fa96c5f55fc94a2db71abc0c2c389a69a33e /arch/sparc64/mm/init.c | |
parent | ef229c5a5e7701ab08a6a06258f415b150348bcc (diff) | |
download | kernel-crypto-46644c2477c58906e95281636d04e9cc42b39352.tar.gz kernel-crypto-46644c2477c58906e95281636d04e9cc42b39352.tar.xz kernel-crypto-46644c2477c58906e95281636d04e9cc42b39352.zip |
SPARC64: SPARSEMEM_VMEMMAP support
[apw@shadowen.org: style fixups]
[apw@shadowen.org: vmemmap sparc64: convert to new config options]
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Acked-by: Mel Gorman <mel@csn.ul.ie>
Acked-by: Christoph Lameter <clameter@sgi.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/sparc64/mm/init.c')
-rw-r--r-- | arch/sparc64/mm/init.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index f0ab9aab308..69538d1aa0a 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1645,6 +1645,58 @@ EXPORT_SYMBOL(_PAGE_E); unsigned long _PAGE_CACHE __read_mostly; EXPORT_SYMBOL(_PAGE_CACHE); +#ifdef CONFIG_SPARSEMEM_VMEMMAP + +#define VMEMMAP_CHUNK_SHIFT 22 +#define VMEMMAP_CHUNK (1UL << VMEMMAP_CHUNK_SHIFT) +#define VMEMMAP_CHUNK_MASK ~(VMEMMAP_CHUNK - 1UL) +#define VMEMMAP_ALIGN(x) (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK) + +#define VMEMMAP_SIZE ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \ + sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT) +unsigned long vmemmap_table[VMEMMAP_SIZE]; + +int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) +{ + unsigned long vstart = (unsigned long) start; + unsigned long vend = (unsigned long) (start + nr); + unsigned long phys_start = (vstart - VMEMMAP_BASE); + unsigned long phys_end = (vend - VMEMMAP_BASE); + unsigned long addr = phys_start & VMEMMAP_CHUNK_MASK; + unsigned long end = VMEMMAP_ALIGN(phys_end); + unsigned long pte_base; + + pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4U | + _PAGE_CP_4U | _PAGE_CV_4U | + _PAGE_P_4U | _PAGE_W_4U); + if (tlb_type == hypervisor) + pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4V | + _PAGE_CP_4V | _PAGE_CV_4V | + _PAGE_P_4V | _PAGE_W_4V); + + for (; addr < end; addr += VMEMMAP_CHUNK) { + unsigned long *vmem_pp = + vmemmap_table + (addr >> VMEMMAP_CHUNK_SHIFT); + void *block; + + if (!(*vmem_pp & _PAGE_VALID)) { + block = vmemmap_alloc_block(1UL << 22, node); + if (!block) + return -ENOMEM; + + *vmem_pp = pte_base | __pa(block); + + printk(KERN_INFO "[%p-%p] page_structs=%lu " + "node=%d entry=%lu/%lu\n", start, block, nr, + node, + addr >> VMEMMAP_CHUNK_SHIFT, + VMEMMAP_SIZE >> VMEMMAP_CHUNK_SHIFT); + } + } + return 0; +} +#endif /* CONFIG_SPARSEMEM_VMEMMAP */ + static void prot_init_common(unsigned long page_none, unsigned long page_shared, unsigned long page_copy, |