diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/Kconfig | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/ktlb.S | 16 | ||||
-rw-r--r-- | arch/sparc64/mm/init.c | 52 |
3 files changed, 69 insertions, 1 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 33dabf588bdd..2f22fa90461a 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig | |||
@@ -240,10 +240,10 @@ config ARCH_SELECT_MEMORY_MODEL | |||
240 | 240 | ||
241 | config ARCH_SPARSEMEM_ENABLE | 241 | config ARCH_SPARSEMEM_ENABLE |
242 | def_bool y | 242 | def_bool y |
243 | select SPARSEMEM_VMEMMAP_ENABLE | ||
243 | 244 | ||
244 | config ARCH_SPARSEMEM_DEFAULT | 245 | config ARCH_SPARSEMEM_DEFAULT |
245 | def_bool y | 246 | def_bool y |
246 | select SPARSEMEM_STATIC | ||
247 | 247 | ||
248 | source "mm/Kconfig" | 248 | source "mm/Kconfig" |
249 | 249 | ||
diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S index d4024ac0d619..964527d2ffa0 100644 --- a/arch/sparc64/kernel/ktlb.S +++ b/arch/sparc64/kernel/ktlb.S | |||
@@ -226,6 +226,15 @@ kvmap_dtlb_load: | |||
226 | ba,pt %xcc, sun4v_dtlb_load | 226 | ba,pt %xcc, sun4v_dtlb_load |
227 | mov %g5, %g3 | 227 | mov %g5, %g3 |
228 | 228 | ||
229 | kvmap_vmemmap: | ||
230 | sub %g4, %g5, %g5 | ||
231 | srlx %g5, 22, %g5 | ||
232 | sethi %hi(vmemmap_table), %g1 | ||
233 | sllx %g5, 3, %g5 | ||
234 | or %g1, %lo(vmemmap_table), %g1 | ||
235 | ba,pt %xcc, kvmap_dtlb_load | ||
236 | ldx [%g1 + %g5], %g5 | ||
237 | |||
229 | kvmap_dtlb_nonlinear: | 238 | kvmap_dtlb_nonlinear: |
230 | /* Catch kernel NULL pointer derefs. */ | 239 | /* Catch kernel NULL pointer derefs. */ |
231 | sethi %hi(PAGE_SIZE), %g5 | 240 | sethi %hi(PAGE_SIZE), %g5 |
@@ -233,6 +242,13 @@ kvmap_dtlb_nonlinear: | |||
233 | bleu,pn %xcc, kvmap_dtlb_longpath | 242 | bleu,pn %xcc, kvmap_dtlb_longpath |
234 | nop | 243 | nop |
235 | 244 | ||
245 | /* Do not use the TSB for vmemmap. */ | ||
246 | mov (VMEMMAP_BASE >> 24), %g5 | ||
247 | sllx %g5, 24, %g5 | ||
248 | cmp %g4,%g5 | ||
249 | bgeu,pn %xcc, kvmap_vmemmap | ||
250 | nop | ||
251 | |||
236 | KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load) | 252 | KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load) |
237 | 253 | ||
238 | kvmap_dtlb_tsbmiss: | 254 | kvmap_dtlb_tsbmiss: |
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index f0ab9aab308f..69538d1aa0ad 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -1645,6 +1645,58 @@ EXPORT_SYMBOL(_PAGE_E); | |||
1645 | unsigned long _PAGE_CACHE __read_mostly; | 1645 | unsigned long _PAGE_CACHE __read_mostly; |
1646 | EXPORT_SYMBOL(_PAGE_CACHE); | 1646 | EXPORT_SYMBOL(_PAGE_CACHE); |
1647 | 1647 | ||
1648 | #ifdef CONFIG_SPARSEMEM_VMEMMAP | ||
1649 | |||
1650 | #define VMEMMAP_CHUNK_SHIFT 22 | ||
1651 | #define VMEMMAP_CHUNK (1UL << VMEMMAP_CHUNK_SHIFT) | ||
1652 | #define VMEMMAP_CHUNK_MASK ~(VMEMMAP_CHUNK - 1UL) | ||
1653 | #define VMEMMAP_ALIGN(x) (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK) | ||
1654 | |||
1655 | #define VMEMMAP_SIZE ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \ | ||
1656 | sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT) | ||
1657 | unsigned long vmemmap_table[VMEMMAP_SIZE]; | ||
1658 | |||
1659 | int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | ||
1660 | { | ||
1661 | unsigned long vstart = (unsigned long) start; | ||
1662 | unsigned long vend = (unsigned long) (start + nr); | ||
1663 | unsigned long phys_start = (vstart - VMEMMAP_BASE); | ||
1664 | unsigned long phys_end = (vend - VMEMMAP_BASE); | ||
1665 | unsigned long addr = phys_start & VMEMMAP_CHUNK_MASK; | ||
1666 | unsigned long end = VMEMMAP_ALIGN(phys_end); | ||
1667 | unsigned long pte_base; | ||
1668 | |||
1669 | pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4U | | ||
1670 | _PAGE_CP_4U | _PAGE_CV_4U | | ||
1671 | _PAGE_P_4U | _PAGE_W_4U); | ||
1672 | if (tlb_type == hypervisor) | ||
1673 | pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4V | | ||
1674 | _PAGE_CP_4V | _PAGE_CV_4V | | ||
1675 | _PAGE_P_4V | _PAGE_W_4V); | ||
1676 | |||
1677 | for (; addr < end; addr += VMEMMAP_CHUNK) { | ||
1678 | unsigned long *vmem_pp = | ||
1679 | vmemmap_table + (addr >> VMEMMAP_CHUNK_SHIFT); | ||
1680 | void *block; | ||
1681 | |||
1682 | if (!(*vmem_pp & _PAGE_VALID)) { | ||
1683 | block = vmemmap_alloc_block(1UL << 22, node); | ||
1684 | if (!block) | ||
1685 | return -ENOMEM; | ||
1686 | |||
1687 | *vmem_pp = pte_base | __pa(block); | ||
1688 | |||
1689 | printk(KERN_INFO "[%p-%p] page_structs=%lu " | ||
1690 | "node=%d entry=%lu/%lu\n", start, block, nr, | ||
1691 | node, | ||
1692 | addr >> VMEMMAP_CHUNK_SHIFT, | ||
1693 | VMEMMAP_SIZE >> VMEMMAP_CHUNK_SHIFT); | ||
1694 | } | ||
1695 | } | ||
1696 | return 0; | ||
1697 | } | ||
1698 | #endif /* CONFIG_SPARSEMEM_VMEMMAP */ | ||
1699 | |||
1648 | static void prot_init_common(unsigned long page_none, | 1700 | static void prot_init_common(unsigned long page_none, |
1649 | unsigned long page_shared, | 1701 | unsigned long page_shared, |
1650 | unsigned long page_copy, | 1702 | unsigned long page_copy, |