diff options
Diffstat (limited to 'arch/powerpc/mm/hash_utils_64.c')
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 186 |
1 files changed, 91 insertions, 95 deletions
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 88fdd9d25077..d5339a3b9945 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #include <asm/cacheflush.h> | 51 | #include <asm/cacheflush.h> |
52 | #include <asm/cputable.h> | 52 | #include <asm/cputable.h> |
53 | #include <asm/sections.h> | 53 | #include <asm/sections.h> |
54 | #include <asm/spu.h> | 54 | #include <asm/copro.h> |
55 | #include <asm/udbg.h> | 55 | #include <asm/udbg.h> |
56 | #include <asm/code-patching.h> | 56 | #include <asm/code-patching.h> |
57 | #include <asm/fadump.h> | 57 | #include <asm/fadump.h> |
@@ -92,12 +92,14 @@ extern unsigned long dart_tablebase; | |||
92 | 92 | ||
93 | static unsigned long _SDR1; | 93 | static unsigned long _SDR1; |
94 | struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; | 94 | struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; |
95 | EXPORT_SYMBOL_GPL(mmu_psize_defs); | ||
95 | 96 | ||
96 | struct hash_pte *htab_address; | 97 | struct hash_pte *htab_address; |
97 | unsigned long htab_size_bytes; | 98 | unsigned long htab_size_bytes; |
98 | unsigned long htab_hash_mask; | 99 | unsigned long htab_hash_mask; |
99 | EXPORT_SYMBOL_GPL(htab_hash_mask); | 100 | EXPORT_SYMBOL_GPL(htab_hash_mask); |
100 | int mmu_linear_psize = MMU_PAGE_4K; | 101 | int mmu_linear_psize = MMU_PAGE_4K; |
102 | EXPORT_SYMBOL_GPL(mmu_linear_psize); | ||
101 | int mmu_virtual_psize = MMU_PAGE_4K; | 103 | int mmu_virtual_psize = MMU_PAGE_4K; |
102 | int mmu_vmalloc_psize = MMU_PAGE_4K; | 104 | int mmu_vmalloc_psize = MMU_PAGE_4K; |
103 | #ifdef CONFIG_SPARSEMEM_VMEMMAP | 105 | #ifdef CONFIG_SPARSEMEM_VMEMMAP |
@@ -105,6 +107,7 @@ int mmu_vmemmap_psize = MMU_PAGE_4K; | |||
105 | #endif | 107 | #endif |
106 | int mmu_io_psize = MMU_PAGE_4K; | 108 | int mmu_io_psize = MMU_PAGE_4K; |
107 | int mmu_kernel_ssize = MMU_SEGSIZE_256M; | 109 | int mmu_kernel_ssize = MMU_SEGSIZE_256M; |
110 | EXPORT_SYMBOL_GPL(mmu_kernel_ssize); | ||
108 | int mmu_highuser_ssize = MMU_SEGSIZE_256M; | 111 | int mmu_highuser_ssize = MMU_SEGSIZE_256M; |
109 | u16 mmu_slb_size = 64; | 112 | u16 mmu_slb_size = 64; |
110 | EXPORT_SYMBOL_GPL(mmu_slb_size); | 113 | EXPORT_SYMBOL_GPL(mmu_slb_size); |
@@ -243,7 +246,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | |||
243 | } | 246 | } |
244 | 247 | ||
245 | #ifdef CONFIG_MEMORY_HOTPLUG | 248 | #ifdef CONFIG_MEMORY_HOTPLUG |
246 | static int htab_remove_mapping(unsigned long vstart, unsigned long vend, | 249 | int htab_remove_mapping(unsigned long vstart, unsigned long vend, |
247 | int psize, int ssize) | 250 | int psize, int ssize) |
248 | { | 251 | { |
249 | unsigned long vaddr; | 252 | unsigned long vaddr; |
@@ -333,70 +336,69 @@ static int __init htab_dt_scan_page_sizes(unsigned long node, | |||
333 | return 0; | 336 | return 0; |
334 | 337 | ||
335 | prop = of_get_flat_dt_prop(node, "ibm,segment-page-sizes", &size); | 338 | prop = of_get_flat_dt_prop(node, "ibm,segment-page-sizes", &size); |
336 | if (prop != NULL) { | 339 | if (!prop) |
337 | pr_info("Page sizes from device-tree:\n"); | 340 | return 0; |
338 | size /= 4; | 341 | |
339 | cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE); | 342 | pr_info("Page sizes from device-tree:\n"); |
340 | while(size > 0) { | 343 | size /= 4; |
341 | unsigned int base_shift = be32_to_cpu(prop[0]); | 344 | cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE); |
342 | unsigned int slbenc = be32_to_cpu(prop[1]); | 345 | while(size > 0) { |
343 | unsigned int lpnum = be32_to_cpu(prop[2]); | 346 | unsigned int base_shift = be32_to_cpu(prop[0]); |
344 | struct mmu_psize_def *def; | 347 | unsigned int slbenc = be32_to_cpu(prop[1]); |
345 | int idx, base_idx; | 348 | unsigned int lpnum = be32_to_cpu(prop[2]); |
346 | 349 | struct mmu_psize_def *def; | |
347 | size -= 3; prop += 3; | 350 | int idx, base_idx; |
348 | base_idx = get_idx_from_shift(base_shift); | 351 | |
349 | if (base_idx < 0) { | 352 | size -= 3; prop += 3; |
350 | /* | 353 | base_idx = get_idx_from_shift(base_shift); |
351 | * skip the pte encoding also | 354 | if (base_idx < 0) { |
352 | */ | 355 | /* skip the pte encoding also */ |
353 | prop += lpnum * 2; size -= lpnum * 2; | 356 | prop += lpnum * 2; size -= lpnum * 2; |
357 | continue; | ||
358 | } | ||
359 | def = &mmu_psize_defs[base_idx]; | ||
360 | if (base_idx == MMU_PAGE_16M) | ||
361 | cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE; | ||
362 | |||
363 | def->shift = base_shift; | ||
364 | if (base_shift <= 23) | ||
365 | def->avpnm = 0; | ||
366 | else | ||
367 | def->avpnm = (1 << (base_shift - 23)) - 1; | ||
368 | def->sllp = slbenc; | ||
369 | /* | ||
370 | * We don't know for sure what's up with tlbiel, so | ||
371 | * for now we only set it for 4K and 64K pages | ||
372 | */ | ||
373 | if (base_idx == MMU_PAGE_4K || base_idx == MMU_PAGE_64K) | ||
374 | def->tlbiel = 1; | ||
375 | else | ||
376 | def->tlbiel = 0; | ||
377 | |||
378 | while (size > 0 && lpnum) { | ||
379 | unsigned int shift = be32_to_cpu(prop[0]); | ||
380 | int penc = be32_to_cpu(prop[1]); | ||
381 | |||
382 | prop += 2; size -= 2; | ||
383 | lpnum--; | ||
384 | |||
385 | idx = get_idx_from_shift(shift); | ||
386 | if (idx < 0) | ||
354 | continue; | 387 | continue; |
355 | } | 388 | |
356 | def = &mmu_psize_defs[base_idx]; | 389 | if (penc == -1) |
357 | if (base_idx == MMU_PAGE_16M) | 390 | pr_err("Invalid penc for base_shift=%d " |
358 | cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE; | 391 | "shift=%d\n", base_shift, shift); |
359 | 392 | ||
360 | def->shift = base_shift; | 393 | def->penc[idx] = penc; |
361 | if (base_shift <= 23) | 394 | pr_info("base_shift=%d: shift=%d, sllp=0x%04lx," |
362 | def->avpnm = 0; | 395 | " avpnm=0x%08lx, tlbiel=%d, penc=%d\n", |
363 | else | 396 | base_shift, shift, def->sllp, |
364 | def->avpnm = (1 << (base_shift - 23)) - 1; | 397 | def->avpnm, def->tlbiel, def->penc[idx]); |
365 | def->sllp = slbenc; | ||
366 | /* | ||
367 | * We don't know for sure what's up with tlbiel, so | ||
368 | * for now we only set it for 4K and 64K pages | ||
369 | */ | ||
370 | if (base_idx == MMU_PAGE_4K || base_idx == MMU_PAGE_64K) | ||
371 | def->tlbiel = 1; | ||
372 | else | ||
373 | def->tlbiel = 0; | ||
374 | |||
375 | while (size > 0 && lpnum) { | ||
376 | unsigned int shift = be32_to_cpu(prop[0]); | ||
377 | int penc = be32_to_cpu(prop[1]); | ||
378 | |||
379 | prop += 2; size -= 2; | ||
380 | lpnum--; | ||
381 | |||
382 | idx = get_idx_from_shift(shift); | ||
383 | if (idx < 0) | ||
384 | continue; | ||
385 | |||
386 | if (penc == -1) | ||
387 | pr_err("Invalid penc for base_shift=%d " | ||
388 | "shift=%d\n", base_shift, shift); | ||
389 | |||
390 | def->penc[idx] = penc; | ||
391 | pr_info("base_shift=%d: shift=%d, sllp=0x%04lx," | ||
392 | " avpnm=0x%08lx, tlbiel=%d, penc=%d\n", | ||
393 | base_shift, shift, def->sllp, | ||
394 | def->avpnm, def->tlbiel, def->penc[idx]); | ||
395 | } | ||
396 | } | 398 | } |
397 | return 1; | ||
398 | } | 399 | } |
399 | return 0; | 400 | |
401 | return 1; | ||
400 | } | 402 | } |
401 | 403 | ||
402 | #ifdef CONFIG_HUGETLB_PAGE | 404 | #ifdef CONFIG_HUGETLB_PAGE |
@@ -821,21 +823,14 @@ static void __init htab_initialize(void) | |||
821 | 823 | ||
822 | void __init early_init_mmu(void) | 824 | void __init early_init_mmu(void) |
823 | { | 825 | { |
824 | /* Setup initial STAB address in the PACA */ | ||
825 | get_paca()->stab_real = __pa((u64)&initial_stab); | ||
826 | get_paca()->stab_addr = (u64)&initial_stab; | ||
827 | |||
828 | /* Initialize the MMU Hash table and create the linear mapping | 826 | /* Initialize the MMU Hash table and create the linear mapping |
829 | * of memory. Has to be done before stab/slb initialization as | 827 | * of memory. Has to be done before SLB initialization as this is |
830 | * this is currently where the page size encoding is obtained | 828 | * currently where the page size encoding is obtained. |
831 | */ | 829 | */ |
832 | htab_initialize(); | 830 | htab_initialize(); |
833 | 831 | ||
834 | /* Initialize stab / SLB management */ | 832 | /* Initialize SLB management */ |
835 | if (mmu_has_feature(MMU_FTR_SLB)) | 833 | slb_initialize(); |
836 | slb_initialize(); | ||
837 | else | ||
838 | stab_initialize(get_paca()->stab_real); | ||
839 | } | 834 | } |
840 | 835 | ||
841 | #ifdef CONFIG_SMP | 836 | #ifdef CONFIG_SMP |
@@ -845,13 +840,8 @@ void early_init_mmu_secondary(void) | |||
845 | if (!firmware_has_feature(FW_FEATURE_LPAR)) | 840 | if (!firmware_has_feature(FW_FEATURE_LPAR)) |
846 | mtspr(SPRN_SDR1, _SDR1); | 841 | mtspr(SPRN_SDR1, _SDR1); |
847 | 842 | ||
848 | /* Initialize STAB/SLB. We use a virtual address as it works | 843 | /* Initialize SLB */ |
849 | * in real mode on pSeries. | 844 | slb_initialize(); |
850 | */ | ||
851 | if (mmu_has_feature(MMU_FTR_SLB)) | ||
852 | slb_initialize(); | ||
853 | else | ||
854 | stab_initialize(get_paca()->stab_addr); | ||
855 | } | 845 | } |
856 | #endif /* CONFIG_SMP */ | 846 | #endif /* CONFIG_SMP */ |
857 | 847 | ||
@@ -879,7 +869,7 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) | |||
879 | } | 869 | } |
880 | 870 | ||
881 | #ifdef CONFIG_PPC_MM_SLICES | 871 | #ifdef CONFIG_PPC_MM_SLICES |
882 | unsigned int get_paca_psize(unsigned long addr) | 872 | static unsigned int get_paca_psize(unsigned long addr) |
883 | { | 873 | { |
884 | u64 lpsizes; | 874 | u64 lpsizes; |
885 | unsigned char *hpsizes; | 875 | unsigned char *hpsizes; |
@@ -913,10 +903,8 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr) | |||
913 | if (get_slice_psize(mm, addr) == MMU_PAGE_4K) | 903 | if (get_slice_psize(mm, addr) == MMU_PAGE_4K) |
914 | return; | 904 | return; |
915 | slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K); | 905 | slice_set_range_psize(mm, addr, 1, MMU_PAGE_4K); |
916 | #ifdef CONFIG_SPU_BASE | 906 | copro_flush_all_slbs(mm); |
917 | spu_flush_all_slbs(mm); | 907 | if ((get_paca_psize(addr) != MMU_PAGE_4K) && (current->mm == mm)) { |
918 | #endif | ||
919 | if (get_paca_psize(addr) != MMU_PAGE_4K) { | ||
920 | get_paca()->context = mm->context; | 908 | get_paca()->context = mm->context; |
921 | slb_flush_and_rebolt(); | 909 | slb_flush_and_rebolt(); |
922 | } | 910 | } |
@@ -1001,12 +989,11 @@ static void check_paca_psize(unsigned long ea, struct mm_struct *mm, | |||
1001 | * -1 - critical hash insertion error | 989 | * -1 - critical hash insertion error |
1002 | * -2 - access not permitted by subpage protection mechanism | 990 | * -2 - access not permitted by subpage protection mechanism |
1003 | */ | 991 | */ |
1004 | int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | 992 | int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap) |
1005 | { | 993 | { |
1006 | enum ctx_state prev_state = exception_enter(); | 994 | enum ctx_state prev_state = exception_enter(); |
1007 | pgd_t *pgdir; | 995 | pgd_t *pgdir; |
1008 | unsigned long vsid; | 996 | unsigned long vsid; |
1009 | struct mm_struct *mm; | ||
1010 | pte_t *ptep; | 997 | pte_t *ptep; |
1011 | unsigned hugeshift; | 998 | unsigned hugeshift; |
1012 | const struct cpumask *tmp; | 999 | const struct cpumask *tmp; |
@@ -1020,7 +1007,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1020 | switch (REGION_ID(ea)) { | 1007 | switch (REGION_ID(ea)) { |
1021 | case USER_REGION_ID: | 1008 | case USER_REGION_ID: |
1022 | user_region = 1; | 1009 | user_region = 1; |
1023 | mm = current->mm; | ||
1024 | if (! mm) { | 1010 | if (! mm) { |
1025 | DBG_LOW(" user region with no mm !\n"); | 1011 | DBG_LOW(" user region with no mm !\n"); |
1026 | rc = 1; | 1012 | rc = 1; |
@@ -1031,7 +1017,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1031 | vsid = get_vsid(mm->context.id, ea, ssize); | 1017 | vsid = get_vsid(mm->context.id, ea, ssize); |
1032 | break; | 1018 | break; |
1033 | case VMALLOC_REGION_ID: | 1019 | case VMALLOC_REGION_ID: |
1034 | mm = &init_mm; | ||
1035 | vsid = get_kernel_vsid(ea, mmu_kernel_ssize); | 1020 | vsid = get_kernel_vsid(ea, mmu_kernel_ssize); |
1036 | if (ea < VMALLOC_END) | 1021 | if (ea < VMALLOC_END) |
1037 | psize = mmu_vmalloc_psize; | 1022 | psize = mmu_vmalloc_psize; |
@@ -1116,7 +1101,8 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1116 | WARN_ON(1); | 1101 | WARN_ON(1); |
1117 | } | 1102 | } |
1118 | #endif | 1103 | #endif |
1119 | check_paca_psize(ea, mm, psize, user_region); | 1104 | if (current->mm == mm) |
1105 | check_paca_psize(ea, mm, psize, user_region); | ||
1120 | 1106 | ||
1121 | goto bail; | 1107 | goto bail; |
1122 | } | 1108 | } |
@@ -1153,13 +1139,12 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1153 | "to 4kB pages because of " | 1139 | "to 4kB pages because of " |
1154 | "non-cacheable mapping\n"); | 1140 | "non-cacheable mapping\n"); |
1155 | psize = mmu_vmalloc_psize = MMU_PAGE_4K; | 1141 | psize = mmu_vmalloc_psize = MMU_PAGE_4K; |
1156 | #ifdef CONFIG_SPU_BASE | 1142 | copro_flush_all_slbs(mm); |
1157 | spu_flush_all_slbs(mm); | ||
1158 | #endif | ||
1159 | } | 1143 | } |
1160 | } | 1144 | } |
1161 | 1145 | ||
1162 | check_paca_psize(ea, mm, psize, user_region); | 1146 | if (current->mm == mm) |
1147 | check_paca_psize(ea, mm, psize, user_region); | ||
1163 | #endif /* CONFIG_PPC_64K_PAGES */ | 1148 | #endif /* CONFIG_PPC_64K_PAGES */ |
1164 | 1149 | ||
1165 | #ifdef CONFIG_PPC_HAS_HASH_64K | 1150 | #ifdef CONFIG_PPC_HAS_HASH_64K |
@@ -1194,6 +1179,17 @@ bail: | |||
1194 | exception_exit(prev_state); | 1179 | exception_exit(prev_state); |
1195 | return rc; | 1180 | return rc; |
1196 | } | 1181 | } |
1182 | EXPORT_SYMBOL_GPL(hash_page_mm); | ||
1183 | |||
1184 | int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | ||
1185 | { | ||
1186 | struct mm_struct *mm = current->mm; | ||
1187 | |||
1188 | if (REGION_ID(ea) == VMALLOC_REGION_ID) | ||
1189 | mm = &init_mm; | ||
1190 | |||
1191 | return hash_page_mm(mm, ea, access, trap); | ||
1192 | } | ||
1197 | EXPORT_SYMBOL_GPL(hash_page); | 1193 | EXPORT_SYMBOL_GPL(hash_page); |
1198 | 1194 | ||
1199 | void hash_preload(struct mm_struct *mm, unsigned long ea, | 1195 | void hash_preload(struct mm_struct *mm, unsigned long ea, |