diff options
Diffstat (limited to 'arch/powerpc/mm/hash_utils_64.c')
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 114 |
1 files changed, 83 insertions, 31 deletions
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index d525f2eba313..611ad084b7e7 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -93,6 +93,8 @@ int mmu_linear_psize = MMU_PAGE_4K; | |||
93 | int mmu_virtual_psize = MMU_PAGE_4K; | 93 | int mmu_virtual_psize = MMU_PAGE_4K; |
94 | int mmu_vmalloc_psize = MMU_PAGE_4K; | 94 | int mmu_vmalloc_psize = MMU_PAGE_4K; |
95 | int mmu_io_psize = MMU_PAGE_4K; | 95 | int mmu_io_psize = MMU_PAGE_4K; |
96 | int mmu_kernel_ssize = MMU_SEGSIZE_256M; | ||
97 | int mmu_highuser_ssize = MMU_SEGSIZE_256M; | ||
96 | #ifdef CONFIG_HUGETLB_PAGE | 98 | #ifdef CONFIG_HUGETLB_PAGE |
97 | int mmu_huge_psize = MMU_PAGE_16M; | 99 | int mmu_huge_psize = MMU_PAGE_16M; |
98 | unsigned int HPAGE_SHIFT; | 100 | unsigned int HPAGE_SHIFT; |
@@ -145,7 +147,8 @@ struct mmu_psize_def mmu_psize_defaults_gp[] = { | |||
145 | 147 | ||
146 | 148 | ||
147 | int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | 149 | int htab_bolt_mapping(unsigned long vstart, unsigned long vend, |
148 | unsigned long pstart, unsigned long mode, int psize) | 150 | unsigned long pstart, unsigned long mode, |
151 | int psize, int ssize) | ||
149 | { | 152 | { |
150 | unsigned long vaddr, paddr; | 153 | unsigned long vaddr, paddr; |
151 | unsigned int step, shift; | 154 | unsigned int step, shift; |
@@ -158,8 +161,8 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
158 | for (vaddr = vstart, paddr = pstart; vaddr < vend; | 161 | for (vaddr = vstart, paddr = pstart; vaddr < vend; |
159 | vaddr += step, paddr += step) { | 162 | vaddr += step, paddr += step) { |
160 | unsigned long hash, hpteg; | 163 | unsigned long hash, hpteg; |
161 | unsigned long vsid = get_kernel_vsid(vaddr); | 164 | unsigned long vsid = get_kernel_vsid(vaddr, ssize); |
162 | unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); | 165 | unsigned long va = hpt_va(vaddr, vsid, ssize); |
163 | 166 | ||
164 | tmp_mode = mode; | 167 | tmp_mode = mode; |
165 | 168 | ||
@@ -167,14 +170,14 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
167 | if (!in_kernel_text(vaddr)) | 170 | if (!in_kernel_text(vaddr)) |
168 | tmp_mode = mode | HPTE_R_N; | 171 | tmp_mode = mode | HPTE_R_N; |
169 | 172 | ||
170 | hash = hpt_hash(va, shift); | 173 | hash = hpt_hash(va, shift, ssize); |
171 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); | 174 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); |
172 | 175 | ||
173 | DBG("htab_bolt_mapping: calling %p\n", ppc_md.hpte_insert); | 176 | DBG("htab_bolt_mapping: calling %p\n", ppc_md.hpte_insert); |
174 | 177 | ||
175 | BUG_ON(!ppc_md.hpte_insert); | 178 | BUG_ON(!ppc_md.hpte_insert); |
176 | ret = ppc_md.hpte_insert(hpteg, va, paddr, | 179 | ret = ppc_md.hpte_insert(hpteg, va, paddr, |
177 | tmp_mode, HPTE_V_BOLTED, psize); | 180 | tmp_mode, HPTE_V_BOLTED, psize, ssize); |
178 | 181 | ||
179 | if (ret < 0) | 182 | if (ret < 0) |
180 | break; | 183 | break; |
@@ -186,6 +189,37 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
186 | return ret < 0 ? ret : 0; | 189 | return ret < 0 ? ret : 0; |
187 | } | 190 | } |
188 | 191 | ||
192 | static int __init htab_dt_scan_seg_sizes(unsigned long node, | ||
193 | const char *uname, int depth, | ||
194 | void *data) | ||
195 | { | ||
196 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | ||
197 | u32 *prop; | ||
198 | unsigned long size = 0; | ||
199 | |||
200 | /* We are scanning "cpu" nodes only */ | ||
201 | if (type == NULL || strcmp(type, "cpu") != 0) | ||
202 | return 0; | ||
203 | |||
204 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,processor-segment-sizes", | ||
205 | &size); | ||
206 | if (prop == NULL) | ||
207 | return 0; | ||
208 | for (; size >= 4; size -= 4, ++prop) { | ||
209 | if (prop[0] == 40) { | ||
210 | DBG("1T segment support detected\n"); | ||
211 | cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT; | ||
212 | } | ||
213 | return 1; | ||
214 | } | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void __init htab_init_seg_sizes(void) | ||
219 | { | ||
220 | of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL); | ||
221 | } | ||
222 | |||
189 | static int __init htab_dt_scan_page_sizes(unsigned long node, | 223 | static int __init htab_dt_scan_page_sizes(unsigned long node, |
190 | const char *uname, int depth, | 224 | const char *uname, int depth, |
191 | void *data) | 225 | void *data) |
@@ -265,7 +299,6 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, | |||
265 | return 0; | 299 | return 0; |
266 | } | 300 | } |
267 | 301 | ||
268 | |||
269 | static void __init htab_init_page_sizes(void) | 302 | static void __init htab_init_page_sizes(void) |
270 | { | 303 | { |
271 | int rc; | 304 | int rc; |
@@ -398,7 +431,7 @@ void create_section_mapping(unsigned long start, unsigned long end) | |||
398 | { | 431 | { |
399 | BUG_ON(htab_bolt_mapping(start, end, __pa(start), | 432 | BUG_ON(htab_bolt_mapping(start, end, __pa(start), |
400 | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX, | 433 | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX, |
401 | mmu_linear_psize)); | 434 | mmu_linear_psize, mmu_kernel_ssize)); |
402 | } | 435 | } |
403 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 436 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
404 | 437 | ||
@@ -449,9 +482,18 @@ void __init htab_initialize(void) | |||
449 | 482 | ||
450 | DBG(" -> htab_initialize()\n"); | 483 | DBG(" -> htab_initialize()\n"); |
451 | 484 | ||
485 | /* Initialize segment sizes */ | ||
486 | htab_init_seg_sizes(); | ||
487 | |||
452 | /* Initialize page sizes */ | 488 | /* Initialize page sizes */ |
453 | htab_init_page_sizes(); | 489 | htab_init_page_sizes(); |
454 | 490 | ||
491 | if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { | ||
492 | mmu_kernel_ssize = MMU_SEGSIZE_1T; | ||
493 | mmu_highuser_ssize = MMU_SEGSIZE_1T; | ||
494 | printk(KERN_INFO "Using 1TB segments\n"); | ||
495 | } | ||
496 | |||
455 | /* | 497 | /* |
456 | * Calculate the required size of the htab. We want the number of | 498 | * Calculate the required size of the htab. We want the number of |
457 | * PTEGs to equal one half the number of real pages. | 499 | * PTEGs to equal one half the number of real pages. |
@@ -523,18 +565,20 @@ void __init htab_initialize(void) | |||
523 | if (base != dart_tablebase) | 565 | if (base != dart_tablebase) |
524 | BUG_ON(htab_bolt_mapping(base, dart_tablebase, | 566 | BUG_ON(htab_bolt_mapping(base, dart_tablebase, |
525 | __pa(base), mode_rw, | 567 | __pa(base), mode_rw, |
526 | mmu_linear_psize)); | 568 | mmu_linear_psize, |
569 | mmu_kernel_ssize)); | ||
527 | if ((base + size) > dart_table_end) | 570 | if ((base + size) > dart_table_end) |
528 | BUG_ON(htab_bolt_mapping(dart_tablebase+16*MB, | 571 | BUG_ON(htab_bolt_mapping(dart_tablebase+16*MB, |
529 | base + size, | 572 | base + size, |
530 | __pa(dart_table_end), | 573 | __pa(dart_table_end), |
531 | mode_rw, | 574 | mode_rw, |
532 | mmu_linear_psize)); | 575 | mmu_linear_psize, |
576 | mmu_kernel_ssize)); | ||
533 | continue; | 577 | continue; |
534 | } | 578 | } |
535 | #endif /* CONFIG_U3_DART */ | 579 | #endif /* CONFIG_U3_DART */ |
536 | BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), | 580 | BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), |
537 | mode_rw, mmu_linear_psize)); | 581 | mode_rw, mmu_linear_psize, mmu_kernel_ssize)); |
538 | } | 582 | } |
539 | 583 | ||
540 | /* | 584 | /* |
@@ -553,7 +597,7 @@ void __init htab_initialize(void) | |||
553 | 597 | ||
554 | BUG_ON(htab_bolt_mapping(tce_alloc_start, tce_alloc_end, | 598 | BUG_ON(htab_bolt_mapping(tce_alloc_start, tce_alloc_end, |
555 | __pa(tce_alloc_start), mode_rw, | 599 | __pa(tce_alloc_start), mode_rw, |
556 | mmu_linear_psize)); | 600 | mmu_linear_psize, mmu_kernel_ssize)); |
557 | } | 601 | } |
558 | 602 | ||
559 | htab_finish_init(); | 603 | htab_finish_init(); |
@@ -621,7 +665,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
621 | pte_t *ptep; | 665 | pte_t *ptep; |
622 | cpumask_t tmp; | 666 | cpumask_t tmp; |
623 | int rc, user_region = 0, local = 0; | 667 | int rc, user_region = 0, local = 0; |
624 | int psize; | 668 | int psize, ssize; |
625 | 669 | ||
626 | DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", | 670 | DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", |
627 | ea, access, trap); | 671 | ea, access, trap); |
@@ -640,20 +684,22 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
640 | DBG_LOW(" user region with no mm !\n"); | 684 | DBG_LOW(" user region with no mm !\n"); |
641 | return 1; | 685 | return 1; |
642 | } | 686 | } |
643 | vsid = get_vsid(mm->context.id, ea); | ||
644 | #ifdef CONFIG_PPC_MM_SLICES | 687 | #ifdef CONFIG_PPC_MM_SLICES |
645 | psize = get_slice_psize(mm, ea); | 688 | psize = get_slice_psize(mm, ea); |
646 | #else | 689 | #else |
647 | psize = mm->context.user_psize; | 690 | psize = mm->context.user_psize; |
648 | #endif | 691 | #endif |
692 | ssize = user_segment_size(ea); | ||
693 | vsid = get_vsid(mm->context.id, ea, ssize); | ||
649 | break; | 694 | break; |
650 | case VMALLOC_REGION_ID: | 695 | case VMALLOC_REGION_ID: |
651 | mm = &init_mm; | 696 | mm = &init_mm; |
652 | vsid = get_kernel_vsid(ea); | 697 | vsid = get_kernel_vsid(ea, mmu_kernel_ssize); |
653 | if (ea < VMALLOC_END) | 698 | if (ea < VMALLOC_END) |
654 | psize = mmu_vmalloc_psize; | 699 | psize = mmu_vmalloc_psize; |
655 | else | 700 | else |
656 | psize = mmu_io_psize; | 701 | psize = mmu_io_psize; |
702 | ssize = mmu_kernel_ssize; | ||
657 | break; | 703 | break; |
658 | default: | 704 | default: |
659 | /* Not a valid range | 705 | /* Not a valid range |
@@ -758,10 +804,10 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
758 | 804 | ||
759 | #ifdef CONFIG_PPC_HAS_HASH_64K | 805 | #ifdef CONFIG_PPC_HAS_HASH_64K |
760 | if (psize == MMU_PAGE_64K) | 806 | if (psize == MMU_PAGE_64K) |
761 | rc = __hash_page_64K(ea, access, vsid, ptep, trap, local); | 807 | rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); |
762 | else | 808 | else |
763 | #endif /* CONFIG_PPC_HAS_HASH_64K */ | 809 | #endif /* CONFIG_PPC_HAS_HASH_64K */ |
764 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local); | 810 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize); |
765 | 811 | ||
766 | #ifndef CONFIG_PPC_64K_PAGES | 812 | #ifndef CONFIG_PPC_64K_PAGES |
767 | DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep)); | 813 | DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep)); |
@@ -783,6 +829,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
783 | cpumask_t mask; | 829 | cpumask_t mask; |
784 | unsigned long flags; | 830 | unsigned long flags; |
785 | int local = 0; | 831 | int local = 0; |
832 | int ssize; | ||
786 | 833 | ||
787 | BUG_ON(REGION_ID(ea) != USER_REGION_ID); | 834 | BUG_ON(REGION_ID(ea) != USER_REGION_ID); |
788 | 835 | ||
@@ -815,7 +862,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
815 | #endif /* CONFIG_PPC_64K_PAGES */ | 862 | #endif /* CONFIG_PPC_64K_PAGES */ |
816 | 863 | ||
817 | /* Get VSID */ | 864 | /* Get VSID */ |
818 | vsid = get_vsid(mm->context.id, ea); | 865 | ssize = user_segment_size(ea); |
866 | vsid = get_vsid(mm->context.id, ea, ssize); | ||
819 | 867 | ||
820 | /* Hash doesn't like irqs */ | 868 | /* Hash doesn't like irqs */ |
821 | local_irq_save(flags); | 869 | local_irq_save(flags); |
@@ -828,28 +876,29 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
828 | /* Hash it in */ | 876 | /* Hash it in */ |
829 | #ifdef CONFIG_PPC_HAS_HASH_64K | 877 | #ifdef CONFIG_PPC_HAS_HASH_64K |
830 | if (mm->context.user_psize == MMU_PAGE_64K) | 878 | if (mm->context.user_psize == MMU_PAGE_64K) |
831 | __hash_page_64K(ea, access, vsid, ptep, trap, local); | 879 | __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); |
832 | else | 880 | else |
833 | #endif /* CONFIG_PPC_HAS_HASH_64K */ | 881 | #endif /* CONFIG_PPC_HAS_HASH_64K */ |
834 | __hash_page_4K(ea, access, vsid, ptep, trap, local); | 882 | __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize); |
835 | 883 | ||
836 | local_irq_restore(flags); | 884 | local_irq_restore(flags); |
837 | } | 885 | } |
838 | 886 | ||
839 | void flush_hash_page(unsigned long va, real_pte_t pte, int psize, int local) | 887 | void flush_hash_page(unsigned long va, real_pte_t pte, int psize, int ssize, |
888 | int local) | ||
840 | { | 889 | { |
841 | unsigned long hash, index, shift, hidx, slot; | 890 | unsigned long hash, index, shift, hidx, slot; |
842 | 891 | ||
843 | DBG_LOW("flush_hash_page(va=%016x)\n", va); | 892 | DBG_LOW("flush_hash_page(va=%016x)\n", va); |
844 | pte_iterate_hashed_subpages(pte, psize, va, index, shift) { | 893 | pte_iterate_hashed_subpages(pte, psize, va, index, shift) { |
845 | hash = hpt_hash(va, shift); | 894 | hash = hpt_hash(va, shift, ssize); |
846 | hidx = __rpte_to_hidx(pte, index); | 895 | hidx = __rpte_to_hidx(pte, index); |
847 | if (hidx & _PTEIDX_SECONDARY) | 896 | if (hidx & _PTEIDX_SECONDARY) |
848 | hash = ~hash; | 897 | hash = ~hash; |
849 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | 898 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; |
850 | slot += hidx & _PTEIDX_GROUP_IX; | 899 | slot += hidx & _PTEIDX_GROUP_IX; |
851 | DBG_LOW(" sub %d: hash=%x, hidx=%x\n", index, slot, hidx); | 900 | DBG_LOW(" sub %d: hash=%x, hidx=%x\n", index, slot, hidx); |
852 | ppc_md.hpte_invalidate(slot, va, psize, local); | 901 | ppc_md.hpte_invalidate(slot, va, psize, ssize, local); |
853 | } pte_iterate_hashed_end(); | 902 | } pte_iterate_hashed_end(); |
854 | } | 903 | } |
855 | 904 | ||
@@ -864,7 +913,7 @@ void flush_hash_range(unsigned long number, int local) | |||
864 | 913 | ||
865 | for (i = 0; i < number; i++) | 914 | for (i = 0; i < number; i++) |
866 | flush_hash_page(batch->vaddr[i], batch->pte[i], | 915 | flush_hash_page(batch->vaddr[i], batch->pte[i], |
867 | batch->psize, local); | 916 | batch->psize, batch->ssize, local); |
868 | } | 917 | } |
869 | } | 918 | } |
870 | 919 | ||
@@ -890,17 +939,19 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address) | |||
890 | #ifdef CONFIG_DEBUG_PAGEALLOC | 939 | #ifdef CONFIG_DEBUG_PAGEALLOC |
891 | static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) | 940 | static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) |
892 | { | 941 | { |
893 | unsigned long hash, hpteg, vsid = get_kernel_vsid(vaddr); | 942 | unsigned long hash, hpteg; |
894 | unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); | 943 | unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); |
944 | unsigned long va = hpt_va(vaddr, vsid, mmu_kernel_ssize); | ||
895 | unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY | | 945 | unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY | |
896 | _PAGE_COHERENT | PP_RWXX | HPTE_R_N; | 946 | _PAGE_COHERENT | PP_RWXX | HPTE_R_N; |
897 | int ret; | 947 | int ret; |
898 | 948 | ||
899 | hash = hpt_hash(va, PAGE_SHIFT); | 949 | hash = hpt_hash(va, PAGE_SHIFT, mmu_kernel_ssize); |
900 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); | 950 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); |
901 | 951 | ||
902 | ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr), | 952 | ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr), |
903 | mode, HPTE_V_BOLTED, mmu_linear_psize); | 953 | mode, HPTE_V_BOLTED, |
954 | mmu_linear_psize, mmu_kernel_ssize); | ||
904 | BUG_ON (ret < 0); | 955 | BUG_ON (ret < 0); |
905 | spin_lock(&linear_map_hash_lock); | 956 | spin_lock(&linear_map_hash_lock); |
906 | BUG_ON(linear_map_hash_slots[lmi] & 0x80); | 957 | BUG_ON(linear_map_hash_slots[lmi] & 0x80); |
@@ -910,10 +961,11 @@ static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) | |||
910 | 961 | ||
911 | static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) | 962 | static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) |
912 | { | 963 | { |
913 | unsigned long hash, hidx, slot, vsid = get_kernel_vsid(vaddr); | 964 | unsigned long hash, hidx, slot; |
914 | unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); | 965 | unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); |
966 | unsigned long va = hpt_va(vaddr, vsid, mmu_kernel_ssize); | ||
915 | 967 | ||
916 | hash = hpt_hash(va, PAGE_SHIFT); | 968 | hash = hpt_hash(va, PAGE_SHIFT, mmu_kernel_ssize); |
917 | spin_lock(&linear_map_hash_lock); | 969 | spin_lock(&linear_map_hash_lock); |
918 | BUG_ON(!(linear_map_hash_slots[lmi] & 0x80)); | 970 | BUG_ON(!(linear_map_hash_slots[lmi] & 0x80)); |
919 | hidx = linear_map_hash_slots[lmi] & 0x7f; | 971 | hidx = linear_map_hash_slots[lmi] & 0x7f; |
@@ -923,7 +975,7 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) | |||
923 | hash = ~hash; | 975 | hash = ~hash; |
924 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | 976 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; |
925 | slot += hidx & _PTEIDX_GROUP_IX; | 977 | slot += hidx & _PTEIDX_GROUP_IX; |
926 | ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, 0); | 978 | ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, mmu_kernel_ssize, 0); |
927 | } | 979 | } |
928 | 980 | ||
929 | void kernel_map_pages(struct page *page, int numpages, int enable) | 981 | void kernel_map_pages(struct page *page, int numpages, int enable) |