diff options
Diffstat (limited to 'arch/powerpc/mm/hash_utils_64.c')
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 67 |
1 files changed, 47 insertions, 20 deletions
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index e303a6d74e3a..6ecc38bd5b24 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -807,7 +807,7 @@ void __init early_init_mmu(void) | |||
807 | } | 807 | } |
808 | 808 | ||
809 | #ifdef CONFIG_SMP | 809 | #ifdef CONFIG_SMP |
810 | void __cpuinit early_init_mmu_secondary(void) | 810 | void early_init_mmu_secondary(void) |
811 | { | 811 | { |
812 | /* Initialize hash table for that CPU */ | 812 | /* Initialize hash table for that CPU */ |
813 | if (!firmware_has_feature(FW_FEATURE_LPAR)) | 813 | if (!firmware_has_feature(FW_FEATURE_LPAR)) |
@@ -1050,13 +1050,26 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1050 | goto bail; | 1050 | goto bail; |
1051 | } | 1051 | } |
1052 | 1052 | ||
1053 | #ifdef CONFIG_HUGETLB_PAGE | ||
1054 | if (hugeshift) { | 1053 | if (hugeshift) { |
1055 | rc = __hash_page_huge(ea, access, vsid, ptep, trap, local, | 1054 | if (pmd_trans_huge(*(pmd_t *)ptep)) |
1056 | ssize, hugeshift, psize); | 1055 | rc = __hash_page_thp(ea, access, vsid, (pmd_t *)ptep, |
1056 | trap, local, ssize, psize); | ||
1057 | #ifdef CONFIG_HUGETLB_PAGE | ||
1058 | else | ||
1059 | rc = __hash_page_huge(ea, access, vsid, ptep, trap, | ||
1060 | local, ssize, hugeshift, psize); | ||
1061 | #else | ||
1062 | else { | ||
1063 | /* | ||
1064 | * if we have hugeshift, and is not transhuge with | ||
1065 | * hugetlb disabled, something is really wrong. | ||
1066 | */ | ||
1067 | rc = 1; | ||
1068 | WARN_ON(1); | ||
1069 | } | ||
1070 | #endif | ||
1057 | goto bail; | 1071 | goto bail; |
1058 | } | 1072 | } |
1059 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
1060 | 1073 | ||
1061 | #ifndef CONFIG_PPC_64K_PAGES | 1074 | #ifndef CONFIG_PPC_64K_PAGES |
1062 | DBG_LOW(" i-pte: %016lx\n", pte_val(*ptep)); | 1075 | DBG_LOW(" i-pte: %016lx\n", pte_val(*ptep)); |
@@ -1145,6 +1158,7 @@ EXPORT_SYMBOL_GPL(hash_page); | |||
1145 | void hash_preload(struct mm_struct *mm, unsigned long ea, | 1158 | void hash_preload(struct mm_struct *mm, unsigned long ea, |
1146 | unsigned long access, unsigned long trap) | 1159 | unsigned long access, unsigned long trap) |
1147 | { | 1160 | { |
1161 | int hugepage_shift; | ||
1148 | unsigned long vsid; | 1162 | unsigned long vsid; |
1149 | pgd_t *pgdir; | 1163 | pgd_t *pgdir; |
1150 | pte_t *ptep; | 1164 | pte_t *ptep; |
@@ -1166,10 +1180,27 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1166 | pgdir = mm->pgd; | 1180 | pgdir = mm->pgd; |
1167 | if (pgdir == NULL) | 1181 | if (pgdir == NULL) |
1168 | return; | 1182 | return; |
1169 | ptep = find_linux_pte(pgdir, ea); | 1183 | |
1170 | if (!ptep) | 1184 | /* Get VSID */ |
1185 | ssize = user_segment_size(ea); | ||
1186 | vsid = get_vsid(mm->context.id, ea, ssize); | ||
1187 | if (!vsid) | ||
1171 | return; | 1188 | return; |
1189 | /* | ||
1190 | * Hash doesn't like irqs. Walking linux page table with irq disabled | ||
1191 | * saves us from holding multiple locks. | ||
1192 | */ | ||
1193 | local_irq_save(flags); | ||
1194 | |||
1195 | /* | ||
1196 | * THP pages use update_mmu_cache_pmd. We don't do | ||
1197 | * hash preload there. Hence can ignore THP here | ||
1198 | */ | ||
1199 | ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugepage_shift); | ||
1200 | if (!ptep) | ||
1201 | goto out_exit; | ||
1172 | 1202 | ||
1203 | WARN_ON(hugepage_shift); | ||
1173 | #ifdef CONFIG_PPC_64K_PAGES | 1204 | #ifdef CONFIG_PPC_64K_PAGES |
1174 | /* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on | 1205 | /* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on |
1175 | * a 64K kernel), then we don't preload, hash_page() will take | 1206 | * a 64K kernel), then we don't preload, hash_page() will take |
@@ -1178,18 +1209,9 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1178 | * page size demotion here | 1209 | * page size demotion here |
1179 | */ | 1210 | */ |
1180 | if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE)) | 1211 | if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE)) |
1181 | return; | 1212 | goto out_exit; |
1182 | #endif /* CONFIG_PPC_64K_PAGES */ | 1213 | #endif /* CONFIG_PPC_64K_PAGES */ |
1183 | 1214 | ||
1184 | /* Get VSID */ | ||
1185 | ssize = user_segment_size(ea); | ||
1186 | vsid = get_vsid(mm->context.id, ea, ssize); | ||
1187 | if (!vsid) | ||
1188 | return; | ||
1189 | |||
1190 | /* Hash doesn't like irqs */ | ||
1191 | local_irq_save(flags); | ||
1192 | |||
1193 | /* Is that local to this CPU ? */ | 1215 | /* Is that local to this CPU ? */ |
1194 | if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) | 1216 | if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) |
1195 | local = 1; | 1217 | local = 1; |
@@ -1211,7 +1233,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1211 | mm->context.user_psize, | 1233 | mm->context.user_psize, |
1212 | mm->context.user_psize, | 1234 | mm->context.user_psize, |
1213 | pte_val(*ptep)); | 1235 | pte_val(*ptep)); |
1214 | 1236 | out_exit: | |
1215 | local_irq_restore(flags); | 1237 | local_irq_restore(flags); |
1216 | } | 1238 | } |
1217 | 1239 | ||
@@ -1232,7 +1254,11 @@ void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize, | |||
1232 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | 1254 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; |
1233 | slot += hidx & _PTEIDX_GROUP_IX; | 1255 | slot += hidx & _PTEIDX_GROUP_IX; |
1234 | DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx); | 1256 | DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx); |
1235 | ppc_md.hpte_invalidate(slot, vpn, psize, ssize, local); | 1257 | /* |
1258 | * We use same base page size and actual psize, because we don't | ||
1259 | * use these functions for hugepage | ||
1260 | */ | ||
1261 | ppc_md.hpte_invalidate(slot, vpn, psize, psize, ssize, local); | ||
1236 | } pte_iterate_hashed_end(); | 1262 | } pte_iterate_hashed_end(); |
1237 | 1263 | ||
1238 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | 1264 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
@@ -1365,7 +1391,8 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) | |||
1365 | hash = ~hash; | 1391 | hash = ~hash; |
1366 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | 1392 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; |
1367 | slot += hidx & _PTEIDX_GROUP_IX; | 1393 | slot += hidx & _PTEIDX_GROUP_IX; |
1368 | ppc_md.hpte_invalidate(slot, vpn, mmu_linear_psize, mmu_kernel_ssize, 0); | 1394 | ppc_md.hpte_invalidate(slot, vpn, mmu_linear_psize, mmu_linear_psize, |
1395 | mmu_kernel_ssize, 0); | ||
1369 | } | 1396 | } |
1370 | 1397 | ||
1371 | void kernel_map_pages(struct page *page, int numpages, int enable) | 1398 | void kernel_map_pages(struct page *page, int numpages, int enable) |