diff options
author | Alex Elder <aelder@sgi.com> | 2010-08-02 11:24:57 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-08-02 11:24:57 -0400 |
commit | 6b0a2996a0c023d84bc27ec7528a6e54cb5ea264 (patch) | |
tree | 9fa9a85d5d871b3cb3c28daf57d8ef8f05becd66 /arch/powerpc/mm/hash_utils_64.c | |
parent | 209fb87a259ead17e966627b7f053d16a96898da (diff) | |
parent | 9fe6206f400646a2322096b56c59891d530e8d51 (diff) |
Merge branch 'v2.6.35'
Diffstat (limited to 'arch/powerpc/mm/hash_utils_64.c')
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 98f262de5585..09dffe6efa46 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -871,6 +871,18 @@ static inline int subpage_protection(struct mm_struct *mm, unsigned long ea) | |||
871 | } | 871 | } |
872 | #endif | 872 | #endif |
873 | 873 | ||
874 | void hash_failure_debug(unsigned long ea, unsigned long access, | ||
875 | unsigned long vsid, unsigned long trap, | ||
876 | int ssize, int psize, unsigned long pte) | ||
877 | { | ||
878 | if (!printk_ratelimit()) | ||
879 | return; | ||
880 | pr_info("mm: Hashing failure ! EA=0x%lx access=0x%lx current=%s\n", | ||
881 | ea, access, current->comm); | ||
882 | pr_info(" trap=0x%lx vsid=0x%lx ssize=%d psize=%d pte=0x%lx\n", | ||
883 | trap, vsid, ssize, psize, pte); | ||
884 | } | ||
885 | |||
874 | /* Result code is: | 886 | /* Result code is: |
875 | * 0 - handled | 887 | * 0 - handled |
876 | * 1 - normal page fault | 888 | * 1 - normal page fault |
@@ -955,6 +967,17 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
955 | return 1; | 967 | return 1; |
956 | } | 968 | } |
957 | 969 | ||
970 | /* Add _PAGE_PRESENT to the required access perm */ | ||
971 | access |= _PAGE_PRESENT; | ||
972 | |||
973 | /* Pre-check access permissions (will be re-checked atomically | ||
974 | * in __hash_page_XX but this pre-check is a fast path | ||
975 | */ | ||
976 | if (access & ~pte_val(*ptep)) { | ||
977 | DBG_LOW(" no access !\n"); | ||
978 | return 1; | ||
979 | } | ||
980 | |||
958 | #ifdef CONFIG_HUGETLB_PAGE | 981 | #ifdef CONFIG_HUGETLB_PAGE |
959 | if (hugeshift) | 982 | if (hugeshift) |
960 | return __hash_page_huge(ea, access, vsid, ptep, trap, local, | 983 | return __hash_page_huge(ea, access, vsid, ptep, trap, local, |
@@ -967,14 +990,6 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
967 | DBG_LOW(" i-pte: %016lx %016lx\n", pte_val(*ptep), | 990 | DBG_LOW(" i-pte: %016lx %016lx\n", pte_val(*ptep), |
968 | pte_val(*(ptep + PTRS_PER_PTE))); | 991 | pte_val(*(ptep + PTRS_PER_PTE))); |
969 | #endif | 992 | #endif |
970 | /* Pre-check access permissions (will be re-checked atomically | ||
971 | * in __hash_page_XX but this pre-check is a fast path | ||
972 | */ | ||
973 | if (access & ~pte_val(*ptep)) { | ||
974 | DBG_LOW(" no access !\n"); | ||
975 | return 1; | ||
976 | } | ||
977 | |||
978 | /* Do actual hashing */ | 993 | /* Do actual hashing */ |
979 | #ifdef CONFIG_PPC_64K_PAGES | 994 | #ifdef CONFIG_PPC_64K_PAGES |
980 | /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */ | 995 | /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */ |
@@ -1033,6 +1048,12 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
1033 | local, ssize, spp); | 1048 | local, ssize, spp); |
1034 | } | 1049 | } |
1035 | 1050 | ||
1051 | /* Dump some info in case of hash insertion failure, they should | ||
1052 | * never happen so it is really useful to know if/when they do | ||
1053 | */ | ||
1054 | if (rc == -1) | ||
1055 | hash_failure_debug(ea, access, vsid, trap, ssize, psize, | ||
1056 | pte_val(*ptep)); | ||
1036 | #ifndef CONFIG_PPC_64K_PAGES | 1057 | #ifndef CONFIG_PPC_64K_PAGES |
1037 | DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep)); | 1058 | DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep)); |
1038 | #else | 1059 | #else |
@@ -1051,8 +1072,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1051 | void *pgdir; | 1072 | void *pgdir; |
1052 | pte_t *ptep; | 1073 | pte_t *ptep; |
1053 | unsigned long flags; | 1074 | unsigned long flags; |
1054 | int local = 0; | 1075 | int rc, ssize, local = 0; |
1055 | int ssize; | ||
1056 | 1076 | ||
1057 | BUG_ON(REGION_ID(ea) != USER_REGION_ID); | 1077 | BUG_ON(REGION_ID(ea) != USER_REGION_ID); |
1058 | 1078 | ||
@@ -1098,11 +1118,18 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, | |||
1098 | /* Hash it in */ | 1118 | /* Hash it in */ |
1099 | #ifdef CONFIG_PPC_HAS_HASH_64K | 1119 | #ifdef CONFIG_PPC_HAS_HASH_64K |
1100 | if (mm->context.user_psize == MMU_PAGE_64K) | 1120 | if (mm->context.user_psize == MMU_PAGE_64K) |
1101 | __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); | 1121 | rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize); |
1102 | else | 1122 | else |
1103 | #endif /* CONFIG_PPC_HAS_HASH_64K */ | 1123 | #endif /* CONFIG_PPC_HAS_HASH_64K */ |
1104 | __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize, | 1124 | rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize, |
1105 | subpage_protection(pgdir, ea)); | 1125 | subpage_protection(pgdir, ea)); |
1126 | |||
1127 | /* Dump some info in case of hash insertion failure, they should | ||
1128 | * never happen so it is really useful to know if/when they do | ||
1129 | */ | ||
1130 | if (rc == -1) | ||
1131 | hash_failure_debug(ea, access, vsid, trap, ssize, | ||
1132 | mm->context.user_psize, pte_val(*ptep)); | ||
1106 | 1133 | ||
1107 | local_irq_restore(flags); | 1134 | local_irq_restore(flags); |
1108 | } | 1135 | } |