diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2014-12-04 00:30:14 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2014-12-05 00:26:15 -0500 |
commit | aefa5688c070727b8729de1aef85cad7b9933fc7 (patch) | |
tree | d6036007b0eca0b325aa3f050defb00f89341209 /arch/powerpc | |
parent | abb90ee7bca5af977b90a0c6be44f631fdacc932 (diff) |
powerpc/mm: don't do tlbie for updatepp request with NO HPTE fault
upatepp can get called for a nohpte fault when we find from the linux
page table that the translation was hashed before. In that case
we are sure that there is no existing translation, hence we could
avoid doing tlbie.
We could possibly race with a parallel fault filling the TLB. But
that should be ok because updatepp is only ever relaxing permissions.
We also look at linux pte permission bits when filling hash pte
permission bits. We also hold the linux pte busy bits while
inserting/updating a hashpte entry, hence a paralle update of
linux pte is not possible. On the other hand mprotect involves
ptep_modify_prot_start which cause a hpte invalidate and not updatepp.
Performance number:
We use randbox_access_bench written by Anton.
Kernel with THP disabled and smaller hash page table size.
86.60% random_access_b [kernel.kallsyms] [k] .native_hpte_updatepp
2.10% random_access_b random_access_bench [.] doit
1.99% random_access_b [kernel.kallsyms] [k] .do_raw_spin_lock
1.85% random_access_b [kernel.kallsyms] [k] .native_hpte_insert
1.26% random_access_b [kernel.kallsyms] [k] .native_flush_hash_range
1.18% random_access_b [kernel.kallsyms] [k] .__delay
0.69% random_access_b [kernel.kallsyms] [k] .native_hpte_remove
0.37% random_access_b [kernel.kallsyms] [k] .clear_user_page
0.34% random_access_b [kernel.kallsyms] [k] .__hash_page_64K
0.32% random_access_b [kernel.kallsyms] [k] fast_exception_return
0.30% random_access_b [kernel.kallsyms] [k] .hash_page_mm
With Fix:
27.54% random_access_b random_access_bench [.] doit
22.90% random_access_b [kernel.kallsyms] [k] .native_hpte_insert
5.76% random_access_b [kernel.kallsyms] [k] .native_hpte_remove
5.20% random_access_b [kernel.kallsyms] [k] fast_exception_return
5.12% random_access_b [kernel.kallsyms] [k] .__hash_page_64K
4.80% random_access_b [kernel.kallsyms] [k] .hash_page_mm
3.31% random_access_b [kernel.kallsyms] [k] data_access_common
1.84% random_access_b [kernel.kallsyms] [k] .trace_hardirqs_on_caller
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/machdep.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/mmu-hash64.h | 22 | ||||
-rw-r--r-- | arch/powerpc/include/asm/tlbflush.h | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 2 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_low_64.S | 15 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_native_64.c | 15 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 44 | ||||
-rw-r--r-- | arch/powerpc/mm/hugepage-hash64.c | 8 | ||||
-rw-r--r-- | arch/powerpc/mm/hugetlbpage-hash64.c | 6 | ||||
-rw-r--r-- | arch/powerpc/mm/pgtable_64.c | 7 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/beat_htab.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 5 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/fault.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/htab.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/lpar.c | 2 |
15 files changed, 85 insertions, 55 deletions
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index e5c0919acca4..c8175a3fe560 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h | |||
@@ -42,7 +42,7 @@ struct machdep_calls { | |||
42 | unsigned long newpp, | 42 | unsigned long newpp, |
43 | unsigned long vpn, | 43 | unsigned long vpn, |
44 | int bpsize, int apsize, | 44 | int bpsize, int apsize, |
45 | int ssize, int local); | 45 | int ssize, unsigned long flags); |
46 | void (*hpte_updateboltedpp)(unsigned long newpp, | 46 | void (*hpte_updateboltedpp)(unsigned long newpp, |
47 | unsigned long ea, | 47 | unsigned long ea, |
48 | int psize, int ssize); | 48 | int psize, int ssize); |
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index aeebc94b2bce..4f13c3ed7acf 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h | |||
@@ -316,27 +316,33 @@ static inline unsigned long hpt_hash(unsigned long vpn, | |||
316 | return hash & 0x7fffffffffUL; | 316 | return hash & 0x7fffffffffUL; |
317 | } | 317 | } |
318 | 318 | ||
319 | #define HPTE_LOCAL_UPDATE 0x1 | ||
320 | #define HPTE_NOHPTE_UPDATE 0x2 | ||
321 | |||
319 | extern int __hash_page_4K(unsigned long ea, unsigned long access, | 322 | extern int __hash_page_4K(unsigned long ea, unsigned long access, |
320 | unsigned long vsid, pte_t *ptep, unsigned long trap, | 323 | unsigned long vsid, pte_t *ptep, unsigned long trap, |
321 | unsigned int local, int ssize, int subpage_prot); | 324 | unsigned long flags, int ssize, int subpage_prot); |
322 | extern int __hash_page_64K(unsigned long ea, unsigned long access, | 325 | extern int __hash_page_64K(unsigned long ea, unsigned long access, |
323 | unsigned long vsid, pte_t *ptep, unsigned long trap, | 326 | unsigned long vsid, pte_t *ptep, unsigned long trap, |
324 | unsigned int local, int ssize); | 327 | unsigned long flags, int ssize); |
325 | struct mm_struct; | 328 | struct mm_struct; |
326 | unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap); | 329 | unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap); |
327 | extern int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap); | 330 | extern int hash_page_mm(struct mm_struct *mm, unsigned long ea, |
328 | extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); | 331 | unsigned long access, unsigned long trap, |
332 | unsigned long flags); | ||
333 | extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap, | ||
334 | unsigned long dsisr); | ||
329 | int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | 335 | int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, |
330 | pte_t *ptep, unsigned long trap, int local, int ssize, | 336 | pte_t *ptep, unsigned long trap, unsigned long flags, |
331 | unsigned int shift, unsigned int mmu_psize); | 337 | int ssize, unsigned int shift, unsigned int mmu_psize); |
332 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 338 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
333 | extern int __hash_page_thp(unsigned long ea, unsigned long access, | 339 | extern int __hash_page_thp(unsigned long ea, unsigned long access, |
334 | unsigned long vsid, pmd_t *pmdp, unsigned long trap, | 340 | unsigned long vsid, pmd_t *pmdp, unsigned long trap, |
335 | int local, int ssize, unsigned int psize); | 341 | unsigned long flags, int ssize, unsigned int psize); |
336 | #else | 342 | #else |
337 | static inline int __hash_page_thp(unsigned long ea, unsigned long access, | 343 | static inline int __hash_page_thp(unsigned long ea, unsigned long access, |
338 | unsigned long vsid, pmd_t *pmdp, | 344 | unsigned long vsid, pmd_t *pmdp, |
339 | unsigned long trap, int local, | 345 | unsigned long trap, unsigned long flags, |
340 | int ssize, unsigned int psize) | 346 | int ssize, unsigned int psize) |
341 | { | 347 | { |
342 | BUG(); | 348 | BUG(); |
diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index 4d3ecd8d8929..23d351ca0303 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h | |||
@@ -125,11 +125,11 @@ static inline void arch_leave_lazy_mmu_mode(void) | |||
125 | 125 | ||
126 | 126 | ||
127 | extern void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, | 127 | extern void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, |
128 | int ssize, int local); | 128 | int ssize, unsigned long flags); |
129 | extern void flush_hash_range(unsigned long number, int local); | 129 | extern void flush_hash_range(unsigned long number, int local); |
130 | extern void flush_hash_hugepage(unsigned long vsid, unsigned long addr, | 130 | extern void flush_hash_hugepage(unsigned long vsid, unsigned long addr, |
131 | pmd_t *pmdp, unsigned int psize, int ssize, | 131 | pmd_t *pmdp, unsigned int psize, int ssize, |
132 | int local); | 132 | unsigned long flags); |
133 | 133 | ||
134 | static inline void local_flush_tlb_mm(struct mm_struct *mm) | 134 | static inline void local_flush_tlb_mm(struct mm_struct *mm) |
135 | { | 135 | { |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index ad62f4d6ce31..6213f494f40b 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -1565,9 +1565,11 @@ do_hash_page: | |||
1565 | * r3 contains the faulting address | 1565 | * r3 contains the faulting address |
1566 | * r4 contains the required access permissions | 1566 | * r4 contains the required access permissions |
1567 | * r5 contains the trap number | 1567 | * r5 contains the trap number |
1568 | * r6 contains dsisr | ||
1568 | * | 1569 | * |
1569 | * at return r3 = 0 for success, 1 for page fault, negative for error | 1570 | * at return r3 = 0 for success, 1 for page fault, negative for error |
1570 | */ | 1571 | */ |
1572 | ld r6,_DSISR(r1) | ||
1571 | bl hash_page /* build HPTE if possible */ | 1573 | bl hash_page /* build HPTE if possible */ |
1572 | cmpdi r3,0 /* see if hash_page succeeded */ | 1574 | cmpdi r3,0 /* see if hash_page succeeded */ |
1573 | 1575 | ||
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 5094f32b706e..463174a4a647 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S | |||
@@ -46,7 +46,8 @@ | |||
46 | 46 | ||
47 | /* | 47 | /* |
48 | * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, | 48 | * _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, |
49 | * pte_t *ptep, unsigned long trap, int local, int ssize) | 49 | * pte_t *ptep, unsigned long trap, unsigned long flags, |
50 | * int ssize) | ||
50 | * | 51 | * |
51 | * Adds a 4K page to the hash table in a segment of 4K pages only | 52 | * Adds a 4K page to the hash table in a segment of 4K pages only |
52 | */ | 53 | */ |
@@ -298,7 +299,7 @@ htab_modify_pte: | |||
298 | li r6,MMU_PAGE_4K /* base page size */ | 299 | li r6,MMU_PAGE_4K /* base page size */ |
299 | li r7,MMU_PAGE_4K /* actual page size */ | 300 | li r7,MMU_PAGE_4K /* actual page size */ |
300 | ld r8,STK_PARAM(R9)(r1) /* segment size */ | 301 | ld r8,STK_PARAM(R9)(r1) /* segment size */ |
301 | ld r9,STK_PARAM(R8)(r1) /* get "local" param */ | 302 | ld r9,STK_PARAM(R8)(r1) /* get "flags" param */ |
302 | .globl htab_call_hpte_updatepp | 303 | .globl htab_call_hpte_updatepp |
303 | htab_call_hpte_updatepp: | 304 | htab_call_hpte_updatepp: |
304 | bl . /* Patched by htab_finish_init() */ | 305 | bl . /* Patched by htab_finish_init() */ |
@@ -338,8 +339,8 @@ htab_pte_insert_failure: | |||
338 | *****************************************************************************/ | 339 | *****************************************************************************/ |
339 | 340 | ||
340 | /* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, | 341 | /* _hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid, |
341 | * pte_t *ptep, unsigned long trap, int local, int ssize, | 342 | * pte_t *ptep, unsigned long trap, unsigned local flags, |
342 | * int subpg_prot) | 343 | * int ssize, int subpg_prot) |
343 | */ | 344 | */ |
344 | 345 | ||
345 | /* | 346 | /* |
@@ -594,7 +595,7 @@ htab_inval_old_hpte: | |||
594 | li r5,0 /* PTE.hidx */ | 595 | li r5,0 /* PTE.hidx */ |
595 | li r6,MMU_PAGE_64K /* psize */ | 596 | li r6,MMU_PAGE_64K /* psize */ |
596 | ld r7,STK_PARAM(R9)(r1) /* ssize */ | 597 | ld r7,STK_PARAM(R9)(r1) /* ssize */ |
597 | ld r8,STK_PARAM(R8)(r1) /* local */ | 598 | ld r8,STK_PARAM(R8)(r1) /* flags */ |
598 | bl flush_hash_page | 599 | bl flush_hash_page |
599 | /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */ | 600 | /* Clear out _PAGE_HPTE_SUB bits in the new linux PTE */ |
600 | lis r0,_PAGE_HPTE_SUB@h | 601 | lis r0,_PAGE_HPTE_SUB@h |
@@ -666,7 +667,7 @@ htab_modify_pte: | |||
666 | li r6,MMU_PAGE_4K /* base page size */ | 667 | li r6,MMU_PAGE_4K /* base page size */ |
667 | li r7,MMU_PAGE_4K /* actual page size */ | 668 | li r7,MMU_PAGE_4K /* actual page size */ |
668 | ld r8,STK_PARAM(R9)(r1) /* segment size */ | 669 | ld r8,STK_PARAM(R9)(r1) /* segment size */ |
669 | ld r9,STK_PARAM(R8)(r1) /* get "local" param */ | 670 | ld r9,STK_PARAM(R8)(r1) /* get "flags" param */ |
670 | .globl htab_call_hpte_updatepp | 671 | .globl htab_call_hpte_updatepp |
671 | htab_call_hpte_updatepp: | 672 | htab_call_hpte_updatepp: |
672 | bl . /* patched by htab_finish_init() */ | 673 | bl . /* patched by htab_finish_init() */ |
@@ -962,7 +963,7 @@ ht64_modify_pte: | |||
962 | li r6,MMU_PAGE_64K /* base page size */ | 963 | li r6,MMU_PAGE_64K /* base page size */ |
963 | li r7,MMU_PAGE_64K /* actual page size */ | 964 | li r7,MMU_PAGE_64K /* actual page size */ |
964 | ld r8,STK_PARAM(R9)(r1) /* segment size */ | 965 | ld r8,STK_PARAM(R9)(r1) /* segment size */ |
965 | ld r9,STK_PARAM(R8)(r1) /* get "local" param */ | 966 | ld r9,STK_PARAM(R8)(r1) /* get "flags" param */ |
966 | .globl ht64_call_hpte_updatepp | 967 | .globl ht64_call_hpte_updatepp |
967 | ht64_call_hpte_updatepp: | 968 | ht64_call_hpte_updatepp: |
968 | bl . /* patched by htab_finish_init() */ | 969 | bl . /* patched by htab_finish_init() */ |
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 13700911b522..9c4880ddecd6 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c | |||
@@ -283,11 +283,11 @@ static long native_hpte_remove(unsigned long hpte_group) | |||
283 | 283 | ||
284 | static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | 284 | static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, |
285 | unsigned long vpn, int bpsize, | 285 | unsigned long vpn, int bpsize, |
286 | int apsize, int ssize, int local) | 286 | int apsize, int ssize, unsigned long flags) |
287 | { | 287 | { |
288 | struct hash_pte *hptep = htab_address + slot; | 288 | struct hash_pte *hptep = htab_address + slot; |
289 | unsigned long hpte_v, want_v; | 289 | unsigned long hpte_v, want_v; |
290 | int ret = 0; | 290 | int ret = 0, local = 0; |
291 | 291 | ||
292 | want_v = hpte_encode_avpn(vpn, bpsize, ssize); | 292 | want_v = hpte_encode_avpn(vpn, bpsize, ssize); |
293 | 293 | ||
@@ -322,8 +322,15 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, | |||
322 | } | 322 | } |
323 | native_unlock_hpte(hptep); | 323 | native_unlock_hpte(hptep); |
324 | } | 324 | } |
325 | /* Ensure it is out of the tlb too. */ | 325 | |
326 | tlbie(vpn, bpsize, apsize, ssize, local); | 326 | if (flags & HPTE_LOCAL_UPDATE) |
327 | local = 1; | ||
328 | /* | ||
329 | * Ensure it is out of the tlb too if it is not a nohpte fault | ||
330 | */ | ||
331 | if (!(flags & HPTE_NOHPTE_UPDATE)) | ||
332 | tlbie(vpn, bpsize, apsize, ssize, local); | ||
333 | |||
327 | return ret; | 334 | return ret; |
328 | } | 335 | } |
329 | 336 | ||
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 68211d398fdb..e56a307bc676 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -989,7 +989,9 @@ static void check_paca_psize(unsigned long ea, struct mm_struct *mm, | |||
989 | * -1 - critical hash insertion error | 989 | * -1 - critical hash insertion error |
990 | * -2 - access not permitted by subpage protection mechanism | 990 | * -2 - access not permitted by subpage protection mechanism |
991 | */ | 991 | */ |
992 | int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, unsigned long trap) | 992 | int hash_page_mm(struct mm_struct *mm, unsigned long ea, |
993 | unsigned long access, unsigned long trap, | ||
994 | unsigned long flags) | ||
993 | { | 995 | { |
994 | enum ctx_state prev_state = exception_enter(); | 996 | enum ctx_state prev_state = exception_enter(); |
995 | pgd_t *pgdir; | 997 | pgd_t *pgdir; |
@@ -997,7 +999,7 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, u | |||
997 | pte_t *ptep; | 999 | pte_t *ptep; |
998 | unsigned hugeshift; | 1000 | unsigned hugeshift; |
999 | const struct cpumask *tmp; | 1001 | const struct cpumask *tmp; |
1000 | int rc, user_region = 0, local = 0; | 1002 | int rc, user_region = 0; |
1001 | int psize, ssize; | 1003 | int psize, ssize; |
1002 | 1004 | ||
1003 | DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", | 1005 | DBG_LOW("hash_page(ea=%016lx, access=%lx, trap=%lx\n", |
@@ -1049,7 +1051,7 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, u | |||
1049 | /* Check CPU locality */ | 1051 | /* Check CPU locality */ |
1050 | tmp = cpumask_of(smp_processor_id()); | 1052 | tmp = cpumask_of(smp_processor_id()); |
1051 | if (user_region && cpumask_equal(mm_cpumask(mm), tmp)) | 1053 | if (user_region && cpumask_equal(mm_cpumask(mm), tmp)) |
1052 | local = 1; | 1054 | flags |= HPTE_LOCAL_UPDATE; |
1053 | 1055 | ||
1054 | #ifndef CONFIG_PPC_64K_PAGES | 1056 | #ifndef CONFIG_PPC_64K_PAGES |
1055 | /* If we use 4K pages and our psize is not 4K, then we might | 1057 | /* If we use 4K pages and our psize is not 4K, then we might |
@@ -1086,11 +1088,11 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, u | |||
1086 | if (hugeshift) { | 1088 | if (hugeshift) { |
1087 | if (pmd_trans_huge(*(pmd_t *)ptep)) | 1089 | if (pmd_trans_huge(*(pmd_t *)ptep)) |
1088 | rc = __hash_page_thp(ea, access, vsid, (pmd_t *)ptep, | 1090 | rc = __hash_page_thp(ea, access, vsid, (pmd_t *)ptep, |
1089 | trap, local, ssize, psize); | 1091 | trap, flags, ssize, psize); |
1090 | #ifdef CONFIG_HUGETLB_PAGE | 1092 | #ifdef CONFIG_HUGETLB_PAGE |
1091 | else | 1093 | else |
1092 | rc = __hash_page_huge(ea, access, vsid, ptep, trap, | 1094 | rc = __hash_page_huge(ea, access, vsid, ptep, trap, |
1093 | local, ssize, hugeshift, psize); | 1095 | flags, ssize, hugeshift, psize); |
1094 | #else | 1096 | #else |
1095 | else { | 1097 | else { |
1096 | /* | 1098 | /* |
@@ -1149,7 +1151,8 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, u | |||
1149 | 1151 | ||
1150 | #ifdef CONFIG_PPC_HAS_HASH_64K | 1152 | #ifdef CONFIG_PPC_HAS_HASH_64K |
1151 | if (psize == MMU_PAGE_64K) | 1153 | if (psize == MMU_PAGE_64K) |
1152 | rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); | 1154 | rc = __hash_page_64K(ea, access, vsid, ptep, trap, |
1155 | flags, ssize); | ||
1153 | else | 1156 | else |
1154 | #endif /* CONFIG_PPC_HAS_HASH_64K */ | 1157 | #endif /* CONFIG_PPC_HAS_HASH_64K */ |
1155 | { | 1158 | { |
@@ -1158,7 +1161,7 @@ int hash_page_mm(struct mm_struct *mm, unsigned long ea, unsigned long access, u | |||
1158 | rc = -2; | 1161 | rc = -2; |
1159 | else | 1162 | else |
1160 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, | 1163 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, |
1161 | local, ssize, spp); | 1164 | flags, ssize, spp); |
1162 | } | 1165 | } |
1163 | 1166 | ||
1164 | /* Dump some info in case of hash insertion failure, they should | 1167 | /* Dump some info in case of hash insertion failure, they should |
@@ -1181,14 +1184,19 @@ bail: | |||
1181 | } | 1184 | } |
1182 | EXPORT_SYMBOL_GPL(hash_page_mm); | 1185 | EXPORT_SYMBOL_GPL(hash_page_mm); |
1183 | 1186 | ||
1184 | int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | 1187 | int hash_page(unsigned long ea, unsigned long access, unsigned long trap, |
1188 | unsigned long dsisr) | ||
1185 | { | 1189 | { |
1190 | unsigned long flags = 0; | ||
1186 | struct mm_struct *mm = current->mm; | 1191 | struct mm_struct *mm = current->mm; |
1187 | 1192 | ||
1188 | if (REGION_ID(ea) == VMALLOC_REGION_ID) | 1193 | if (REGION_ID(ea) == VMALLOC_REGION_ID) |
1189 | mm = &init_mm; | 1194 | mm = &init_mm; |
1190 | 1195 | ||
1191 | return hash_page_mm(mm, ea, access, trap); | 1196 | if (dsisr & DSISR_NOHPTE) |
1197 | flags |= HPTE_NOHPTE_UPDATE; | ||
1198 | |||
1199 | return hash_page_mm(mm, ea, access, trap, flags); | ||
1192 | } | 1200 | } |
1193 | EXPORT_SYMBOL_GPL(hash_page); | 1201 | EXPORT_SYMBOL_GPL(hash_page); |
1194 | 1202 | ||
@@ -1200,7 +1208,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1200 | pgd_t *pgdir; | 1208 | pgd_t *pgdir; |
1201 | pte_t *ptep; | 1209 | pte_t *ptep; |
1202 | unsigned long flags; | 1210 | unsigned long flags; |
1203 | int rc, ssize, local = 0; | 1211 | int rc, ssize, update_flags = 0; |
1204 | 1212 | ||
1205 | BUG_ON(REGION_ID(ea) != USER_REGION_ID); | 1213 | BUG_ON(REGION_ID(ea) != USER_REGION_ID); |
1206 | 1214 | ||
@@ -1251,16 +1259,17 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1251 | 1259 | ||
1252 | /* Is that local to this CPU ? */ | 1260 | /* Is that local to this CPU ? */ |
1253 | if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) | 1261 | if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) |
1254 | local = 1; | 1262 | update_flags |= HPTE_LOCAL_UPDATE; |
1255 | 1263 | ||
1256 | /* Hash it in */ | 1264 | /* Hash it in */ |
1257 | #ifdef CONFIG_PPC_HAS_HASH_64K | 1265 | #ifdef CONFIG_PPC_HAS_HASH_64K |
1258 | if (mm->context.user_psize == MMU_PAGE_64K) | 1266 | if (mm->context.user_psize == MMU_PAGE_64K) |
1259 | rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); | 1267 | rc = __hash_page_64K(ea, access, vsid, ptep, trap, |
1268 | update_flags, ssize); | ||
1260 | else | 1269 | else |
1261 | #endif /* CONFIG_PPC_HAS_HASH_64K */ | 1270 | #endif /* CONFIG_PPC_HAS_HASH_64K */ |
1262 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize, | 1271 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, update_flags, |
1263 | subpage_protection(mm, ea)); | 1272 | ssize, subpage_protection(mm, ea)); |
1264 | 1273 | ||
1265 | /* Dump some info in case of hash insertion failure, they should | 1274 | /* Dump some info in case of hash insertion failure, they should |
1266 | * never happen so it is really useful to know if/when they do | 1275 | * never happen so it is really useful to know if/when they do |
@@ -1278,9 +1287,10 @@ out_exit: | |||
1278 | * do not forget to update the assembly call site ! | 1287 | * do not forget to update the assembly call site ! |
1279 | */ | 1288 | */ |
1280 | void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize, | 1289 | void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize, |
1281 | int local) | 1290 | unsigned long flags) |
1282 | { | 1291 | { |
1283 | unsigned long hash, index, shift, hidx, slot; | 1292 | unsigned long hash, index, shift, hidx, slot; |
1293 | int local = flags & HPTE_LOCAL_UPDATE; | ||
1284 | 1294 | ||
1285 | DBG_LOW("flush_hash_page(vpn=%016lx)\n", vpn); | 1295 | DBG_LOW("flush_hash_page(vpn=%016lx)\n", vpn); |
1286 | pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { | 1296 | pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { |
@@ -1317,12 +1327,14 @@ void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize, | |||
1317 | 1327 | ||
1318 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 1328 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
1319 | void flush_hash_hugepage(unsigned long vsid, unsigned long addr, | 1329 | void flush_hash_hugepage(unsigned long vsid, unsigned long addr, |
1320 | pmd_t *pmdp, unsigned int psize, int ssize, int local) | 1330 | pmd_t *pmdp, unsigned int psize, int ssize, |
1331 | unsigned long flags) | ||
1321 | { | 1332 | { |
1322 | int i, max_hpte_count, valid; | 1333 | int i, max_hpte_count, valid; |
1323 | unsigned long s_addr; | 1334 | unsigned long s_addr; |
1324 | unsigned char *hpte_slot_array; | 1335 | unsigned char *hpte_slot_array; |
1325 | unsigned long hidx, shift, vpn, hash, slot; | 1336 | unsigned long hidx, shift, vpn, hash, slot; |
1337 | int local = flags & HPTE_LOCAL_UPDATE; | ||
1326 | 1338 | ||
1327 | s_addr = addr & HPAGE_PMD_MASK; | 1339 | s_addr = addr & HPAGE_PMD_MASK; |
1328 | hpte_slot_array = get_hpte_slot_array(pmdp); | 1340 | hpte_slot_array = get_hpte_slot_array(pmdp); |
diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c index 3a648cd363ae..86686514ae13 100644 --- a/arch/powerpc/mm/hugepage-hash64.c +++ b/arch/powerpc/mm/hugepage-hash64.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #include <asm/machdep.h> | 19 | #include <asm/machdep.h> |
20 | 20 | ||
21 | int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | 21 | int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, |
22 | pmd_t *pmdp, unsigned long trap, int local, int ssize, | 22 | pmd_t *pmdp, unsigned long trap, unsigned long flags, |
23 | unsigned int psize) | 23 | int ssize, unsigned int psize) |
24 | { | 24 | { |
25 | unsigned int index, valid; | 25 | unsigned int index, valid; |
26 | unsigned char *hpte_slot_array; | 26 | unsigned char *hpte_slot_array; |
@@ -95,7 +95,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | |||
95 | */ | 95 | */ |
96 | if ((old_pmd & _PAGE_HASHPTE) && !(old_pmd & _PAGE_COMBO)) | 96 | if ((old_pmd & _PAGE_HASHPTE) && !(old_pmd & _PAGE_COMBO)) |
97 | flush_hash_hugepage(vsid, ea, pmdp, MMU_PAGE_64K, | 97 | flush_hash_hugepage(vsid, ea, pmdp, MMU_PAGE_64K, |
98 | ssize, local); | 98 | ssize, flags); |
99 | } | 99 | } |
100 | 100 | ||
101 | valid = hpte_valid(hpte_slot_array, index); | 101 | valid = hpte_valid(hpte_slot_array, index); |
@@ -108,7 +108,7 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid, | |||
108 | slot += hidx & _PTEIDX_GROUP_IX; | 108 | slot += hidx & _PTEIDX_GROUP_IX; |
109 | 109 | ||
110 | ret = ppc_md.hpte_updatepp(slot, rflags, vpn, | 110 | ret = ppc_md.hpte_updatepp(slot, rflags, vpn, |
111 | psize, lpsize, ssize, local); | 111 | psize, lpsize, ssize, flags); |
112 | /* | 112 | /* |
113 | * We failed to update, try to insert a new entry. | 113 | * We failed to update, try to insert a new entry. |
114 | */ | 114 | */ |
diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c index a5bcf9301196..d94b1af53a93 100644 --- a/arch/powerpc/mm/hugetlbpage-hash64.c +++ b/arch/powerpc/mm/hugetlbpage-hash64.c | |||
@@ -19,8 +19,8 @@ extern long hpte_insert_repeating(unsigned long hash, unsigned long vpn, | |||
19 | unsigned long vflags, int psize, int ssize); | 19 | unsigned long vflags, int psize, int ssize); |
20 | 20 | ||
21 | int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | 21 | int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, |
22 | pte_t *ptep, unsigned long trap, int local, int ssize, | 22 | pte_t *ptep, unsigned long trap, unsigned long flags, |
23 | unsigned int shift, unsigned int mmu_psize) | 23 | int ssize, unsigned int shift, unsigned int mmu_psize) |
24 | { | 24 | { |
25 | unsigned long vpn; | 25 | unsigned long vpn; |
26 | unsigned long old_pte, new_pte; | 26 | unsigned long old_pte, new_pte; |
@@ -81,7 +81,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | |||
81 | slot += (old_pte & _PAGE_F_GIX) >> 12; | 81 | slot += (old_pte & _PAGE_F_GIX) >> 12; |
82 | 82 | ||
83 | if (ppc_md.hpte_updatepp(slot, rflags, vpn, mmu_psize, | 83 | if (ppc_md.hpte_updatepp(slot, rflags, vpn, mmu_psize, |
84 | mmu_psize, ssize, local) == -1) | 84 | mmu_psize, ssize, flags) == -1) |
85 | old_pte &= ~_PAGE_HPTEFLAGS; | 85 | old_pte &= ~_PAGE_HPTEFLAGS; |
86 | } | 86 | } |
87 | 87 | ||
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index eea9fa1f8ae7..4fe5f64cc179 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c | |||
@@ -739,9 +739,10 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, | |||
739 | void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr, | 739 | void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr, |
740 | pmd_t *pmdp, unsigned long old_pmd) | 740 | pmd_t *pmdp, unsigned long old_pmd) |
741 | { | 741 | { |
742 | int ssize, local = 0; | 742 | int ssize; |
743 | unsigned int psize; | 743 | unsigned int psize; |
744 | unsigned long vsid; | 744 | unsigned long vsid; |
745 | unsigned long flags = 0; | ||
745 | const struct cpumask *tmp; | 746 | const struct cpumask *tmp; |
746 | 747 | ||
747 | /* get the base page size,vsid and segment size */ | 748 | /* get the base page size,vsid and segment size */ |
@@ -765,9 +766,9 @@ void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr, | |||
765 | 766 | ||
766 | tmp = cpumask_of(smp_processor_id()); | 767 | tmp = cpumask_of(smp_processor_id()); |
767 | if (cpumask_equal(mm_cpumask(mm), tmp)) | 768 | if (cpumask_equal(mm_cpumask(mm), tmp)) |
768 | local = 1; | 769 | flags |= HPTE_LOCAL_UPDATE; |
769 | 770 | ||
770 | return flush_hash_hugepage(vsid, addr, pmdp, psize, ssize, local); | 771 | return flush_hash_hugepage(vsid, addr, pmdp, psize, ssize, flags); |
771 | } | 772 | } |
772 | 773 | ||
773 | static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot) | 774 | static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot) |
diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c index d4d245c0d787..bee9232fe619 100644 --- a/arch/powerpc/platforms/cell/beat_htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c | |||
@@ -186,7 +186,7 @@ static long beat_lpar_hpte_updatepp(unsigned long slot, | |||
186 | unsigned long newpp, | 186 | unsigned long newpp, |
187 | unsigned long vpn, | 187 | unsigned long vpn, |
188 | int psize, int apsize, | 188 | int psize, int apsize, |
189 | int ssize, int local) | 189 | int ssize, unsigned long flags) |
190 | { | 190 | { |
191 | unsigned long lpar_rc; | 191 | unsigned long lpar_rc; |
192 | u64 dummy0, dummy1; | 192 | u64 dummy0, dummy1; |
@@ -369,7 +369,7 @@ static long beat_lpar_hpte_updatepp_v3(unsigned long slot, | |||
369 | unsigned long newpp, | 369 | unsigned long newpp, |
370 | unsigned long vpn, | 370 | unsigned long vpn, |
371 | int psize, int apsize, | 371 | int psize, int apsize, |
372 | int ssize, int local) | 372 | int ssize, unsigned long flags) |
373 | { | 373 | { |
374 | unsigned long lpar_rc; | 374 | unsigned long lpar_rc; |
375 | unsigned long want_v; | 375 | unsigned long want_v; |
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index ffcbd242e669..f7af74f83693 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -181,7 +181,8 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
183 | 183 | ||
184 | extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX | 184 | extern int hash_page(unsigned long ea, unsigned long access, |
185 | unsigned long trap, unsigned long dsisr); //XXX | ||
185 | static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) | 186 | static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) |
186 | { | 187 | { |
187 | int ret; | 188 | int ret; |
@@ -196,7 +197,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) | |||
196 | (REGION_ID(ea) != USER_REGION_ID)) { | 197 | (REGION_ID(ea) != USER_REGION_ID)) { |
197 | 198 | ||
198 | spin_unlock(&spu->register_lock); | 199 | spin_unlock(&spu->register_lock); |
199 | ret = hash_page(ea, _PAGE_PRESENT, 0x300); | 200 | ret = hash_page(ea, _PAGE_PRESENT, 0x300, dsisr); |
200 | spin_lock(&spu->register_lock); | 201 | spin_lock(&spu->register_lock); |
201 | 202 | ||
202 | if (!ret) { | 203 | if (!ret) { |
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c index e45894a08118..d98f845ac777 100644 --- a/arch/powerpc/platforms/cell/spufs/fault.c +++ b/arch/powerpc/platforms/cell/spufs/fault.c | |||
@@ -144,7 +144,7 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
144 | access = (_PAGE_PRESENT | _PAGE_USER); | 144 | access = (_PAGE_PRESENT | _PAGE_USER); |
145 | access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; | 145 | access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; |
146 | local_irq_save(flags); | 146 | local_irq_save(flags); |
147 | ret = hash_page(ea, access, 0x300); | 147 | ret = hash_page(ea, access, 0x300, dsisr); |
148 | local_irq_restore(flags); | 148 | local_irq_restore(flags); |
149 | 149 | ||
150 | /* hashing failed, so try the actual fault handler */ | 150 | /* hashing failed, so try the actual fault handler */ |
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 3e270e3412ae..2f95d33cf34a 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c | |||
@@ -110,7 +110,7 @@ static long ps3_hpte_remove(unsigned long hpte_group) | |||
110 | 110 | ||
111 | static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, | 111 | static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, |
112 | unsigned long vpn, int psize, int apsize, | 112 | unsigned long vpn, int psize, int apsize, |
113 | int ssize, int local) | 113 | int ssize, unsigned long inv_flags) |
114 | { | 114 | { |
115 | int result; | 115 | int result; |
116 | u64 hpte_v, want_v, hpte_rs; | 116 | u64 hpte_v, want_v, hpte_rs; |
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 832f221840f2..469751d92004 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -284,7 +284,7 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, | |||
284 | unsigned long newpp, | 284 | unsigned long newpp, |
285 | unsigned long vpn, | 285 | unsigned long vpn, |
286 | int psize, int apsize, | 286 | int psize, int apsize, |
287 | int ssize, int local) | 287 | int ssize, unsigned long inv_flags) |
288 | { | 288 | { |
289 | unsigned long lpar_rc; | 289 | unsigned long lpar_rc; |
290 | unsigned long flags = (newpp & 7) | H_AVPN; | 290 | unsigned long flags = (newpp & 7) | H_AVPN; |