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 | |
parent | 209fb87a259ead17e966627b7f053d16a96898da (diff) | |
parent | 9fe6206f400646a2322096b56c59891d530e8d51 (diff) |
Merge branch 'v2.6.35'
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/hash_low_64.S | 9 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 53 | ||||
-rw-r--r-- | arch/powerpc/mm/hugetlbpage-hash64.c | 40 | ||||
-rw-r--r-- | arch/powerpc/mm/numa.c | 24 |
4 files changed, 74 insertions, 52 deletions
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index a719f53921a5..3079f6b44cf5 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S | |||
@@ -68,9 +68,6 @@ _GLOBAL(__hash_page_4K) | |||
68 | std r8,STK_PARM(r8)(r1) | 68 | std r8,STK_PARM(r8)(r1) |
69 | std r9,STK_PARM(r9)(r1) | 69 | std r9,STK_PARM(r9)(r1) |
70 | 70 | ||
71 | /* Add _PAGE_PRESENT to access */ | ||
72 | ori r4,r4,_PAGE_PRESENT | ||
73 | |||
74 | /* Save non-volatile registers. | 71 | /* Save non-volatile registers. |
75 | * r31 will hold "old PTE" | 72 | * r31 will hold "old PTE" |
76 | * r30 is "new PTE" | 73 | * r30 is "new PTE" |
@@ -347,9 +344,6 @@ _GLOBAL(__hash_page_4K) | |||
347 | std r8,STK_PARM(r8)(r1) | 344 | std r8,STK_PARM(r8)(r1) |
348 | std r9,STK_PARM(r9)(r1) | 345 | std r9,STK_PARM(r9)(r1) |
349 | 346 | ||
350 | /* Add _PAGE_PRESENT to access */ | ||
351 | ori r4,r4,_PAGE_PRESENT | ||
352 | |||
353 | /* Save non-volatile registers. | 347 | /* Save non-volatile registers. |
354 | * r31 will hold "old PTE" | 348 | * r31 will hold "old PTE" |
355 | * r30 is "new PTE" | 349 | * r30 is "new PTE" |
@@ -687,9 +681,6 @@ _GLOBAL(__hash_page_64K) | |||
687 | std r8,STK_PARM(r8)(r1) | 681 | std r8,STK_PARM(r8)(r1) |
688 | std r9,STK_PARM(r9)(r1) | 682 | std r9,STK_PARM(r9)(r1) |
689 | 683 | ||
690 | /* Add _PAGE_PRESENT to access */ | ||
691 | ori r4,r4,_PAGE_PRESENT | ||
692 | |||
693 | /* Save non-volatile registers. | 684 | /* Save non-volatile registers. |
694 | * r31 will hold "old PTE" | 685 | * r31 will hold "old PTE" |
695 | * r30 is "new PTE" | 686 | * r30 is "new PTE" |
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 | } |
diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c index 199539882f92..cc5c273086cf 100644 --- a/arch/powerpc/mm/hugetlbpage-hash64.c +++ b/arch/powerpc/mm/hugetlbpage-hash64.c | |||
@@ -21,21 +21,13 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | |||
21 | unsigned long old_pte, new_pte; | 21 | unsigned long old_pte, new_pte; |
22 | unsigned long va, rflags, pa, sz; | 22 | unsigned long va, rflags, pa, sz; |
23 | long slot; | 23 | long slot; |
24 | int err = 1; | ||
25 | 24 | ||
26 | BUG_ON(shift != mmu_psize_defs[mmu_psize].shift); | 25 | BUG_ON(shift != mmu_psize_defs[mmu_psize].shift); |
27 | 26 | ||
28 | /* Search the Linux page table for a match with va */ | 27 | /* Search the Linux page table for a match with va */ |
29 | va = hpt_va(ea, vsid, ssize); | 28 | va = hpt_va(ea, vsid, ssize); |
30 | 29 | ||
31 | /* | 30 | /* At this point, we have a pte (old_pte) which can be used to build |
32 | * Check the user's access rights to the page. If access should be | ||
33 | * prevented then send the problem up to do_page_fault. | ||
34 | */ | ||
35 | if (unlikely(access & ~pte_val(*ptep))) | ||
36 | goto out; | ||
37 | /* | ||
38 | * At this point, we have a pte (old_pte) which can be used to build | ||
39 | * or update an HPTE. There are 2 cases: | 31 | * or update an HPTE. There are 2 cases: |
40 | * | 32 | * |
41 | * 1. There is a valid (present) pte with no associated HPTE (this is | 33 | * 1. There is a valid (present) pte with no associated HPTE (this is |
@@ -49,9 +41,17 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | |||
49 | 41 | ||
50 | do { | 42 | do { |
51 | old_pte = pte_val(*ptep); | 43 | old_pte = pte_val(*ptep); |
52 | if (old_pte & _PAGE_BUSY) | 44 | /* If PTE busy, retry the access */ |
53 | goto out; | 45 | if (unlikely(old_pte & _PAGE_BUSY)) |
46 | return 0; | ||
47 | /* If PTE permissions don't match, take page fault */ | ||
48 | if (unlikely(access & ~old_pte)) | ||
49 | return 1; | ||
50 | /* Try to lock the PTE, add ACCESSED and DIRTY if it was | ||
51 | * a write access */ | ||
54 | new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED; | 52 | new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED; |
53 | if (access & _PAGE_RW) | ||
54 | new_pte |= _PAGE_DIRTY; | ||
55 | } while(old_pte != __cmpxchg_u64((unsigned long *)ptep, | 55 | } while(old_pte != __cmpxchg_u64((unsigned long *)ptep, |
56 | old_pte, new_pte)); | 56 | old_pte, new_pte)); |
57 | 57 | ||
@@ -121,8 +121,16 @@ repeat: | |||
121 | } | 121 | } |
122 | } | 122 | } |
123 | 123 | ||
124 | if (unlikely(slot == -2)) | 124 | /* |
125 | panic("hash_huge_page: pte_insert failed\n"); | 125 | * Hypervisor failure. Restore old pte and return -1 |
126 | * similar to __hash_page_* | ||
127 | */ | ||
128 | if (unlikely(slot == -2)) { | ||
129 | *ptep = __pte(old_pte); | ||
130 | hash_failure_debug(ea, access, vsid, trap, ssize, | ||
131 | mmu_psize, old_pte); | ||
132 | return -1; | ||
133 | } | ||
126 | 134 | ||
127 | new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX); | 135 | new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX); |
128 | } | 136 | } |
@@ -131,9 +139,5 @@ repeat: | |||
131 | * No need to use ldarx/stdcx here | 139 | * No need to use ldarx/stdcx here |
132 | */ | 140 | */ |
133 | *ptep = __pte(new_pte & ~_PAGE_BUSY); | 141 | *ptep = __pte(new_pte & ~_PAGE_BUSY); |
134 | 142 | return 0; | |
135 | err = 0; | ||
136 | |||
137 | out: | ||
138 | return err; | ||
139 | } | 143 | } |
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index f47364585ecd..aa731af720c0 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c | |||
@@ -398,15 +398,15 @@ static int of_get_drconf_memory(struct device_node *memory, const u32 **dm) | |||
398 | } | 398 | } |
399 | 399 | ||
400 | /* | 400 | /* |
401 | * Retreive and validate the ibm,memblock-size property for drconf memory | 401 | * Retreive and validate the ibm,lmb-size property for drconf memory |
402 | * from the device tree. | 402 | * from the device tree. |
403 | */ | 403 | */ |
404 | static u64 of_get_memblock_size(struct device_node *memory) | 404 | static u64 of_get_lmb_size(struct device_node *memory) |
405 | { | 405 | { |
406 | const u32 *prop; | 406 | const u32 *prop; |
407 | u32 len; | 407 | u32 len; |
408 | 408 | ||
409 | prop = of_get_property(memory, "ibm,memblock-size", &len); | 409 | prop = of_get_property(memory, "ibm,lmb-size", &len); |
410 | if (!prop || len < sizeof(unsigned int)) | 410 | if (!prop || len < sizeof(unsigned int)) |
411 | return 0; | 411 | return 0; |
412 | 412 | ||
@@ -562,7 +562,7 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start, | |||
562 | static inline int __init read_usm_ranges(const u32 **usm) | 562 | static inline int __init read_usm_ranges(const u32 **usm) |
563 | { | 563 | { |
564 | /* | 564 | /* |
565 | * For each memblock in ibm,dynamic-memory a corresponding | 565 | * For each lmb in ibm,dynamic-memory a corresponding |
566 | * entry in linux,drconf-usable-memory property contains | 566 | * entry in linux,drconf-usable-memory property contains |
567 | * a counter followed by that many (base, size) duple. | 567 | * a counter followed by that many (base, size) duple. |
568 | * read the counter from linux,drconf-usable-memory | 568 | * read the counter from linux,drconf-usable-memory |
@@ -578,7 +578,7 @@ static void __init parse_drconf_memory(struct device_node *memory) | |||
578 | { | 578 | { |
579 | const u32 *dm, *usm; | 579 | const u32 *dm, *usm; |
580 | unsigned int n, rc, ranges, is_kexec_kdump = 0; | 580 | unsigned int n, rc, ranges, is_kexec_kdump = 0; |
581 | unsigned long memblock_size, base, size, sz; | 581 | unsigned long lmb_size, base, size, sz; |
582 | int nid; | 582 | int nid; |
583 | struct assoc_arrays aa; | 583 | struct assoc_arrays aa; |
584 | 584 | ||
@@ -586,8 +586,8 @@ static void __init parse_drconf_memory(struct device_node *memory) | |||
586 | if (!n) | 586 | if (!n) |
587 | return; | 587 | return; |
588 | 588 | ||
589 | memblock_size = of_get_memblock_size(memory); | 589 | lmb_size = of_get_lmb_size(memory); |
590 | if (!memblock_size) | 590 | if (!lmb_size) |
591 | return; | 591 | return; |
592 | 592 | ||
593 | rc = of_get_assoc_arrays(memory, &aa); | 593 | rc = of_get_assoc_arrays(memory, &aa); |
@@ -611,7 +611,7 @@ static void __init parse_drconf_memory(struct device_node *memory) | |||
611 | continue; | 611 | continue; |
612 | 612 | ||
613 | base = drmem.base_addr; | 613 | base = drmem.base_addr; |
614 | size = memblock_size; | 614 | size = lmb_size; |
615 | ranges = 1; | 615 | ranges = 1; |
616 | 616 | ||
617 | if (is_kexec_kdump) { | 617 | if (is_kexec_kdump) { |
@@ -1072,7 +1072,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, | |||
1072 | { | 1072 | { |
1073 | const u32 *dm; | 1073 | const u32 *dm; |
1074 | unsigned int drconf_cell_cnt, rc; | 1074 | unsigned int drconf_cell_cnt, rc; |
1075 | unsigned long memblock_size; | 1075 | unsigned long lmb_size; |
1076 | struct assoc_arrays aa; | 1076 | struct assoc_arrays aa; |
1077 | int nid = -1; | 1077 | int nid = -1; |
1078 | 1078 | ||
@@ -1080,8 +1080,8 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, | |||
1080 | if (!drconf_cell_cnt) | 1080 | if (!drconf_cell_cnt) |
1081 | return -1; | 1081 | return -1; |
1082 | 1082 | ||
1083 | memblock_size = of_get_memblock_size(memory); | 1083 | lmb_size = of_get_lmb_size(memory); |
1084 | if (!memblock_size) | 1084 | if (!lmb_size) |
1085 | return -1; | 1085 | return -1; |
1086 | 1086 | ||
1087 | rc = of_get_assoc_arrays(memory, &aa); | 1087 | rc = of_get_assoc_arrays(memory, &aa); |
@@ -1100,7 +1100,7 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory, | |||
1100 | continue; | 1100 | continue; |
1101 | 1101 | ||
1102 | if ((scn_addr < drmem.base_addr) | 1102 | if ((scn_addr < drmem.base_addr) |
1103 | || (scn_addr >= (drmem.base_addr + memblock_size))) | 1103 | || (scn_addr >= (drmem.base_addr + lmb_size))) |
1104 | continue; | 1104 | continue; |
1105 | 1105 | ||
1106 | nid = of_drconf_to_nid_single(&drmem, &aa); | 1106 | nid = of_drconf_to_nid_single(&drmem, &aa); |