aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm/hash_utils_64.c
diff options
context:
space:
mode:
authorLi Zhong <zhong@linux.vnet.ibm.com>2013-05-13 12:16:41 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-05-14 02:00:19 -0400
commitba12eedee321eeb5baecaada285daeb3462c35f5 (patch)
tree68e9481dc69d8f5f412b5bba278ade75a4686a8f /arch/powerpc/mm/hash_utils_64.c
parent22ecbe8dcef4f6bf80ed4358600e8f6e03105c5c (diff)
powerpc: Exception hooks for context tracking subsystem
This is the exception hooks for context tracking subsystem, including data access, program check, single step, instruction breakpoint, machine check, alignment, fp unavailable, altivec assist, unknown exception, whose handlers might use RCU. This patch corresponds to [PATCH] x86: Exception hooks for userspace RCU extended QS commit 6ba3c97a38803883c2eee489505796cb0a727122 But after the exception handling moved to generic code, and some changes in following two commits: 56dd9470d7c8734f055da2a6bac553caf4a468eb context_tracking: Move exception handling to generic code 6c1e0256fad84a843d915414e4b5973b7443d48d context_tracking: Restore correct previous context state on exception exit it is able for exception hooks to use the generic code above instead of a redundant arch implementation. Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/mm/hash_utils_64.c')
-rw-r--r--arch/powerpc/mm/hash_utils_64.c36
1 files changed, 27 insertions, 9 deletions
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 88ac0eeaadde..e303a6d74e3a 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -33,6 +33,7 @@
33#include <linux/init.h> 33#include <linux/init.h>
34#include <linux/signal.h> 34#include <linux/signal.h>
35#include <linux/memblock.h> 35#include <linux/memblock.h>
36#include <linux/context_tracking.h>
36 37
37#include <asm/processor.h> 38#include <asm/processor.h>
38#include <asm/pgtable.h> 39#include <asm/pgtable.h>
@@ -954,6 +955,7 @@ void hash_failure_debug(unsigned long ea, unsigned long access,
954 */ 955 */
955int hash_page(unsigned long ea, unsigned long access, unsigned long trap) 956int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
956{ 957{
958 enum ctx_state prev_state = exception_enter();
957 pgd_t *pgdir; 959 pgd_t *pgdir;
958 unsigned long vsid; 960 unsigned long vsid;
959 struct mm_struct *mm; 961 struct mm_struct *mm;
@@ -973,7 +975,8 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
973 mm = current->mm; 975 mm = current->mm;
974 if (! mm) { 976 if (! mm) {
975 DBG_LOW(" user region with no mm !\n"); 977 DBG_LOW(" user region with no mm !\n");
976 return 1; 978 rc = 1;
979 goto bail;
977 } 980 }
978 psize = get_slice_psize(mm, ea); 981 psize = get_slice_psize(mm, ea);
979 ssize = user_segment_size(ea); 982 ssize = user_segment_size(ea);
@@ -992,19 +995,23 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
992 /* Not a valid range 995 /* Not a valid range
993 * Send the problem up to do_page_fault 996 * Send the problem up to do_page_fault
994 */ 997 */
995 return 1; 998 rc = 1;
999 goto bail;
996 } 1000 }
997 DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid); 1001 DBG_LOW(" mm=%p, mm->pgdir=%p, vsid=%016lx\n", mm, mm->pgd, vsid);
998 1002
999 /* Bad address. */ 1003 /* Bad address. */
1000 if (!vsid) { 1004 if (!vsid) {
1001 DBG_LOW("Bad address!\n"); 1005 DBG_LOW("Bad address!\n");
1002 return 1; 1006 rc = 1;
1007 goto bail;
1003 } 1008 }
1004 /* Get pgdir */ 1009 /* Get pgdir */
1005 pgdir = mm->pgd; 1010 pgdir = mm->pgd;
1006 if (pgdir == NULL) 1011 if (pgdir == NULL) {
1007 return 1; 1012 rc = 1;
1013 goto bail;
1014 }
1008 1015
1009 /* Check CPU locality */ 1016 /* Check CPU locality */
1010 tmp = cpumask_of(smp_processor_id()); 1017 tmp = cpumask_of(smp_processor_id());
@@ -1027,7 +1034,8 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
1027 ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugeshift); 1034 ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugeshift);
1028 if (ptep == NULL || !pte_present(*ptep)) { 1035 if (ptep == NULL || !pte_present(*ptep)) {
1029 DBG_LOW(" no PTE !\n"); 1036 DBG_LOW(" no PTE !\n");
1030 return 1; 1037 rc = 1;
1038 goto bail;
1031 } 1039 }
1032 1040
1033 /* Add _PAGE_PRESENT to the required access perm */ 1041 /* Add _PAGE_PRESENT to the required access perm */
@@ -1038,13 +1046,16 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
1038 */ 1046 */
1039 if (access & ~pte_val(*ptep)) { 1047 if (access & ~pte_val(*ptep)) {
1040 DBG_LOW(" no access !\n"); 1048 DBG_LOW(" no access !\n");
1041 return 1; 1049 rc = 1;
1050 goto bail;
1042 } 1051 }
1043 1052
1044#ifdef CONFIG_HUGETLB_PAGE 1053#ifdef CONFIG_HUGETLB_PAGE
1045 if (hugeshift) 1054 if (hugeshift) {
1046 return __hash_page_huge(ea, access, vsid, ptep, trap, local, 1055 rc = __hash_page_huge(ea, access, vsid, ptep, trap, local,
1047 ssize, hugeshift, psize); 1056 ssize, hugeshift, psize);
1057 goto bail;
1058 }
1048#endif /* CONFIG_HUGETLB_PAGE */ 1059#endif /* CONFIG_HUGETLB_PAGE */
1049 1060
1050#ifndef CONFIG_PPC_64K_PAGES 1061#ifndef CONFIG_PPC_64K_PAGES
@@ -1124,6 +1135,9 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
1124 pte_val(*(ptep + PTRS_PER_PTE))); 1135 pte_val(*(ptep + PTRS_PER_PTE)));
1125#endif 1136#endif
1126 DBG_LOW(" -> rc=%d\n", rc); 1137 DBG_LOW(" -> rc=%d\n", rc);
1138
1139bail:
1140 exception_exit(prev_state);
1127 return rc; 1141 return rc;
1128} 1142}
1129EXPORT_SYMBOL_GPL(hash_page); 1143EXPORT_SYMBOL_GPL(hash_page);
@@ -1259,6 +1273,8 @@ void flush_hash_range(unsigned long number, int local)
1259 */ 1273 */
1260void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc) 1274void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc)
1261{ 1275{
1276 enum ctx_state prev_state = exception_enter();
1277
1262 if (user_mode(regs)) { 1278 if (user_mode(regs)) {
1263#ifdef CONFIG_PPC_SUBPAGE_PROT 1279#ifdef CONFIG_PPC_SUBPAGE_PROT
1264 if (rc == -2) 1280 if (rc == -2)
@@ -1268,6 +1284,8 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc)
1268 _exception(SIGBUS, regs, BUS_ADRERR, address); 1284 _exception(SIGBUS, regs, BUS_ADRERR, address);
1269 } else 1285 } else
1270 bad_page_fault(regs, address, SIGBUS); 1286 bad_page_fault(regs, address, SIGBUS);
1287
1288 exception_exit(prev_state);
1271} 1289}
1272 1290
1273long hpte_insert_repeating(unsigned long hash, unsigned long vpn, 1291long hpte_insert_repeating(unsigned long hash, unsigned long vpn,