diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/mm/init_64.c | 67 |
2 files changed, 68 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 | ||