diff options
Diffstat (limited to 'arch/powerpc/mm/hash_utils_64.c')
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 36 |
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 | */ |
955 | int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | 956 | int 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 | |||
1139 | bail: | ||
1140 | exception_exit(prev_state); | ||
1127 | return rc; | 1141 | return rc; |
1128 | } | 1142 | } |
1129 | EXPORT_SYMBOL_GPL(hash_page); | 1143 | EXPORT_SYMBOL_GPL(hash_page); |
@@ -1259,6 +1273,8 @@ void flush_hash_range(unsigned long number, int local) | |||
1259 | */ | 1273 | */ |
1260 | void low_hash_fault(struct pt_regs *regs, unsigned long address, int rc) | 1274 | void 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 | ||
1273 | long hpte_insert_repeating(unsigned long hash, unsigned long vpn, | 1291 | long hpte_insert_repeating(unsigned long hash, unsigned long vpn, |