diff options
author | Andy Whitcroft <apw@shadowen.org> | 2007-10-16 04:24:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:42:51 -0400 |
commit | d29eff7bca60c9ee401d691d4562a4abca8de543 (patch) | |
tree | 86715dfec0470a59d3bbad032b3032321f101766 | |
parent | 46644c2477c58906e95281636d04e9cc42b39352 (diff) |
ppc64: SPARSEMEM_VMEMMAP support
Enable virtual memmap support for SPARSEMEM on PPC64 systems. Slice a 16th
off the end of the linear mapping space and use that to hold the vmemmap.
Uses the same size mapping as uses in the linear 1:1 kernel mapping.
[pbadari@gmail.com: fix warning]
Signed-off-by: Andy Whitcroft <apw@shadowen.org>
Acked-by: Mel Gorman <mel@csn.ul.ie>
Cc: Christoph Lameter <clameter@sgi.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/mm/init_64.c | 67 | ||||
-rw-r--r-- | include/asm-powerpc/pgtable-ppc64.h | 8 |
3 files changed, 76 insertions, 0 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 037664d496d7..5e001ad588a7 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -295,6 +295,7 @@ config ARCH_FLATMEM_ENABLE | |||
295 | config ARCH_SPARSEMEM_ENABLE | 295 | config ARCH_SPARSEMEM_ENABLE |
296 | def_bool y | 296 | def_bool y |
297 | depends on PPC64 | 297 | depends on PPC64 |
298 | select SPARSEMEM_VMEMMAP_ENABLE | ||
298 | 299 | ||
299 | config ARCH_SPARSEMEM_DEFAULT | 300 | config ARCH_SPARSEMEM_DEFAULT |
300 | def_bool y | 301 | def_bool y |
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index fa90f6561b9f..29ed495444f5 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c | |||
@@ -183,3 +183,70 @@ void pgtable_cache_init(void) | |||
183 | zero_ctor); | 183 | zero_ctor); |
184 | } | 184 | } |
185 | } | 185 | } |
186 | |||
187 | #ifdef CONFIG_SPARSEMEM_VMEMMAP | ||
188 | /* | ||
189 | * Given an address within the vmemmap, determine the pfn of the page that | ||
190 | * represents the start of the section it is within. Note that we have to | ||
191 | * do this by hand as the proffered address may not be correctly aligned. | ||
192 | * Subtraction of non-aligned pointers produces undefined results. | ||
193 | */ | ||
194 | unsigned long __meminit vmemmap_section_start(unsigned long page) | ||
195 | { | ||
196 | unsigned long offset = page - ((unsigned long)(vmemmap)); | ||
197 | |||
198 | /* Return the pfn of the start of the section. */ | ||
199 | return (offset / sizeof(struct page)) & PAGE_SECTION_MASK; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Check if this vmemmap page is already initialised. If any section | ||
204 | * which overlaps this vmemmap page is initialised then this page is | ||
205 | * initialised already. | ||
206 | */ | ||
207 | int __meminit vmemmap_populated(unsigned long start, int page_size) | ||
208 | { | ||
209 | unsigned long end = start + page_size; | ||
210 | |||
211 | for (; start < end; start += (PAGES_PER_SECTION * sizeof(struct page))) | ||
212 | if (pfn_valid(vmemmap_section_start(start))) | ||
213 | return 1; | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | int __meminit vmemmap_populate(struct page *start_page, | ||
219 | unsigned long nr_pages, int node) | ||
220 | { | ||
221 | unsigned long mode_rw; | ||
222 | unsigned long start = (unsigned long)start_page; | ||
223 | unsigned long end = (unsigned long)(start_page + nr_pages); | ||
224 | unsigned long page_size = 1 << mmu_psize_defs[mmu_linear_psize].shift; | ||
225 | |||
226 | mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX; | ||
227 | |||
228 | /* Align to the page size of the linear mapping. */ | ||
229 | start = _ALIGN_DOWN(start, page_size); | ||
230 | |||
231 | for (; start < end; start += page_size) { | ||
232 | int mapped; | ||
233 | void *p; | ||
234 | |||
235 | if (vmemmap_populated(start, page_size)) | ||
236 | continue; | ||
237 | |||
238 | p = vmemmap_alloc_block(page_size, node); | ||
239 | if (!p) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | printk(KERN_WARNING "vmemmap %08lx allocated at %p, " | ||
243 | "physical %p.\n", start, p, __pa(p)); | ||
244 | |||
245 | mapped = htab_bolt_mapping(start, start + page_size, | ||
246 | __pa(p), mode_rw, mmu_linear_psize); | ||
247 | BUG_ON(mapped < 0); | ||
248 | } | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | #endif | ||
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h index 300f9a199bf2..dd4c26dc57d2 100644 --- a/include/asm-powerpc/pgtable-ppc64.h +++ b/include/asm-powerpc/pgtable-ppc64.h | |||
@@ -68,6 +68,14 @@ | |||
68 | #define USER_REGION_ID (0UL) | 68 | #define USER_REGION_ID (0UL) |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Defines the address of the vmemap area, in the top 16th of the | ||
72 | * kernel region. | ||
73 | */ | ||
74 | #define VMEMMAP_BASE (ASM_CONST(CONFIG_KERNEL_START) + \ | ||
75 | (0xfUL << (REGION_SHIFT - 4))) | ||
76 | #define vmemmap ((struct page *)VMEMMAP_BASE) | ||
77 | |||
78 | /* | ||
71 | * Common bits in a linux-style PTE. These match the bits in the | 79 | * Common bits in a linux-style PTE. These match the bits in the |
72 | * (hardware-defined) PowerPC PTE as closely as possible. Additional | 80 | * (hardware-defined) PowerPC PTE as closely as possible. Additional |
73 | * bits may be defined in pgtable-*.h | 81 | * bits may be defined in pgtable-*.h |