diff options
-rw-r--r-- | arch/powerpc/include/asm/mmu-hash64.h | 6 | ||||
-rw-r--r-- | arch/powerpc/include/asm/page_64.h | 6 | ||||
-rw-r--r-- | arch/powerpc/mm/hash_utils_64.c | 15 | ||||
-rw-r--r-- | arch/powerpc/mm/slb_low.S | 30 | ||||
-rw-r--r-- | arch/powerpc/mm/slice.c | 107 |
5 files changed, 109 insertions, 55 deletions
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index 6aeb4986a373..7cbd541f915f 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h | |||
@@ -460,7 +460,11 @@ typedef struct { | |||
460 | 460 | ||
461 | #ifdef CONFIG_PPC_MM_SLICES | 461 | #ifdef CONFIG_PPC_MM_SLICES |
462 | u64 low_slices_psize; /* SLB page size encodings */ | 462 | u64 low_slices_psize; /* SLB page size encodings */ |
463 | u64 high_slices_psize; /* 4 bits per slice for now */ | 463 | /* |
464 | * Right now we support 64TB and 4 bits for each | ||
465 | * 1TB slice we need 32 bytes for 64TB. | ||
466 | */ | ||
467 | unsigned char high_slices_psize[32]; /* 4 bits per slice for now */ | ||
464 | #else | 468 | #else |
465 | u16 sllp; /* SLB page size encoding */ | 469 | u16 sllp; /* SLB page size encoding */ |
466 | #endif | 470 | #endif |
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index fed85e6290e1..6c9bef4cb6a0 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h | |||
@@ -82,7 +82,11 @@ extern u64 ppc64_pft_size; | |||
82 | 82 | ||
83 | struct slice_mask { | 83 | struct slice_mask { |
84 | u16 low_slices; | 84 | u16 low_slices; |
85 | u16 high_slices; | 85 | /* |
86 | * This should be derived out of PGTABLE_RANGE. For the current | ||
87 | * max 64TB, u64 should be ok. | ||
88 | */ | ||
89 | u64 high_slices; | ||
86 | }; | 90 | }; |
87 | 91 | ||
88 | struct mm_struct; | 92 | struct mm_struct; |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 7d4ffd79cc82..3a292be2e079 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -803,16 +803,19 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) | |||
803 | #ifdef CONFIG_PPC_MM_SLICES | 803 | #ifdef CONFIG_PPC_MM_SLICES |
804 | unsigned int get_paca_psize(unsigned long addr) | 804 | unsigned int get_paca_psize(unsigned long addr) |
805 | { | 805 | { |
806 | unsigned long index, slices; | 806 | u64 lpsizes; |
807 | unsigned char *hpsizes; | ||
808 | unsigned long index, mask_index; | ||
807 | 809 | ||
808 | if (addr < SLICE_LOW_TOP) { | 810 | if (addr < SLICE_LOW_TOP) { |
809 | slices = get_paca()->context.low_slices_psize; | 811 | lpsizes = get_paca()->context.low_slices_psize; |
810 | index = GET_LOW_SLICE_INDEX(addr); | 812 | index = GET_LOW_SLICE_INDEX(addr); |
811 | } else { | 813 | return (lpsizes >> (index * 4)) & 0xF; |
812 | slices = get_paca()->context.high_slices_psize; | ||
813 | index = GET_HIGH_SLICE_INDEX(addr); | ||
814 | } | 814 | } |
815 | return (slices >> (index * 4)) & 0xF; | 815 | hpsizes = get_paca()->context.high_slices_psize; |
816 | index = GET_HIGH_SLICE_INDEX(addr); | ||
817 | mask_index = index & 0x1; | ||
818 | return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xF; | ||
816 | } | 819 | } |
817 | 820 | ||
818 | #else | 821 | #else |
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index b9ee79ce2200..e132dc6ed1a9 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S | |||
@@ -108,17 +108,31 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) | |||
108 | * between 4k and 64k standard page size | 108 | * between 4k and 64k standard page size |
109 | */ | 109 | */ |
110 | #ifdef CONFIG_PPC_MM_SLICES | 110 | #ifdef CONFIG_PPC_MM_SLICES |
111 | /* r10 have esid */ | ||
111 | cmpldi r10,16 | 112 | cmpldi r10,16 |
112 | 113 | /* below SLICE_LOW_TOP */ | |
113 | /* Get the slice index * 4 in r11 and matching slice size mask in r9 */ | ||
114 | ld r9,PACALOWSLICESPSIZE(r13) | ||
115 | sldi r11,r10,2 | ||
116 | blt 5f | 114 | blt 5f |
117 | ld r9,PACAHIGHSLICEPSIZE(r13) | 115 | /* |
118 | srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2) | 116 | * Handle hpsizes, |
119 | andi. r11,r11,0x3c | 117 | * r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index |
118 | */ | ||
119 | srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT + 1) /* index */ | ||
120 | addi r9,r11,PACAHIGHSLICEPSIZE | ||
121 | lbzx r9,r13,r9 /* r9 is hpsizes[r11] */ | ||
122 | /* r11 = (r10 >> (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)) & 0x1 */ | ||
123 | rldicl r11,r10,(64 - (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)),63 | ||
124 | b 6f | ||
120 | 125 | ||
121 | 5: /* Extract the psize and multiply to get an array offset */ | 126 | 5: |
127 | /* | ||
128 | * Handle lpsizes | ||
129 | * r9 is get_paca()->context.low_slices_psize, r11 is index | ||
130 | */ | ||
131 | ld r9,PACALOWSLICESPSIZE(r13) | ||
132 | mr r11,r10 | ||
133 | 6: | ||
134 | sldi r11,r11,2 /* index * 4 */ | ||
135 | /* Extract the psize and multiply to get an array offset */ | ||
122 | srd r9,r9,r11 | 136 | srd r9,r9,r11 |
123 | andi. r9,r9,0xf | 137 | andi. r9,r9,0xf |
124 | mulli r9,r9,MMUPSIZEDEFSIZE | 138 | mulli r9,r9,MMUPSIZEDEFSIZE |
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 73709f7ce92c..b4e996a398bd 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c | |||
@@ -42,7 +42,7 @@ int _slice_debug = 1; | |||
42 | 42 | ||
43 | static void slice_print_mask(const char *label, struct slice_mask mask) | 43 | static void slice_print_mask(const char *label, struct slice_mask mask) |
44 | { | 44 | { |
45 | char *p, buf[16 + 3 + 16 + 1]; | 45 | char *p, buf[16 + 3 + 64 + 1]; |
46 | int i; | 46 | int i; |
47 | 47 | ||
48 | if (!_slice_debug) | 48 | if (!_slice_debug) |
@@ -54,7 +54,7 @@ static void slice_print_mask(const char *label, struct slice_mask mask) | |||
54 | *(p++) = '-'; | 54 | *(p++) = '-'; |
55 | *(p++) = ' '; | 55 | *(p++) = ' '; |
56 | for (i = 0; i < SLICE_NUM_HIGH; i++) | 56 | for (i = 0; i < SLICE_NUM_HIGH; i++) |
57 | *(p++) = (mask.high_slices & (1 << i)) ? '1' : '0'; | 57 | *(p++) = (mask.high_slices & (1ul << i)) ? '1' : '0'; |
58 | *(p++) = 0; | 58 | *(p++) = 0; |
59 | 59 | ||
60 | printk(KERN_DEBUG "%s:%s\n", label, buf); | 60 | printk(KERN_DEBUG "%s:%s\n", label, buf); |
@@ -84,8 +84,8 @@ static struct slice_mask slice_range_to_mask(unsigned long start, | |||
84 | } | 84 | } |
85 | 85 | ||
86 | if ((start + len) > SLICE_LOW_TOP) | 86 | if ((start + len) > SLICE_LOW_TOP) |
87 | ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1)) | 87 | ret.high_slices = (1ul << (GET_HIGH_SLICE_INDEX(end) + 1)) |
88 | - (1u << GET_HIGH_SLICE_INDEX(start)); | 88 | - (1ul << GET_HIGH_SLICE_INDEX(start)); |
89 | 89 | ||
90 | return ret; | 90 | return ret; |
91 | } | 91 | } |
@@ -135,26 +135,31 @@ static struct slice_mask slice_mask_for_free(struct mm_struct *mm) | |||
135 | 135 | ||
136 | for (i = 0; i < SLICE_NUM_HIGH; i++) | 136 | for (i = 0; i < SLICE_NUM_HIGH; i++) |
137 | if (!slice_high_has_vma(mm, i)) | 137 | if (!slice_high_has_vma(mm, i)) |
138 | ret.high_slices |= 1u << i; | 138 | ret.high_slices |= 1ul << i; |
139 | 139 | ||
140 | return ret; | 140 | return ret; |
141 | } | 141 | } |
142 | 142 | ||
143 | static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize) | 143 | static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize) |
144 | { | 144 | { |
145 | unsigned char *hpsizes; | ||
146 | int index, mask_index; | ||
145 | struct slice_mask ret = { 0, 0 }; | 147 | struct slice_mask ret = { 0, 0 }; |
146 | unsigned long i; | 148 | unsigned long i; |
147 | u64 psizes; | 149 | u64 lpsizes; |
148 | 150 | ||
149 | psizes = mm->context.low_slices_psize; | 151 | lpsizes = mm->context.low_slices_psize; |
150 | for (i = 0; i < SLICE_NUM_LOW; i++) | 152 | for (i = 0; i < SLICE_NUM_LOW; i++) |
151 | if (((psizes >> (i * 4)) & 0xf) == psize) | 153 | if (((lpsizes >> (i * 4)) & 0xf) == psize) |
152 | ret.low_slices |= 1u << i; | 154 | ret.low_slices |= 1u << i; |
153 | 155 | ||
154 | psizes = mm->context.high_slices_psize; | 156 | hpsizes = mm->context.high_slices_psize; |
155 | for (i = 0; i < SLICE_NUM_HIGH; i++) | 157 | for (i = 0; i < SLICE_NUM_HIGH; i++) { |
156 | if (((psizes >> (i * 4)) & 0xf) == psize) | 158 | mask_index = i & 0x1; |
157 | ret.high_slices |= 1u << i; | 159 | index = i >> 1; |
160 | if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == psize) | ||
161 | ret.high_slices |= 1ul << i; | ||
162 | } | ||
158 | 163 | ||
159 | return ret; | 164 | return ret; |
160 | } | 165 | } |
@@ -183,8 +188,10 @@ static void slice_flush_segments(void *parm) | |||
183 | 188 | ||
184 | static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize) | 189 | static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize) |
185 | { | 190 | { |
191 | int index, mask_index; | ||
186 | /* Write the new slice psize bits */ | 192 | /* Write the new slice psize bits */ |
187 | u64 lpsizes, hpsizes; | 193 | unsigned char *hpsizes; |
194 | u64 lpsizes; | ||
188 | unsigned long i, flags; | 195 | unsigned long i, flags; |
189 | 196 | ||
190 | slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize); | 197 | slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize); |
@@ -201,14 +208,18 @@ static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psiz | |||
201 | lpsizes = (lpsizes & ~(0xful << (i * 4))) | | 208 | lpsizes = (lpsizes & ~(0xful << (i * 4))) | |
202 | (((unsigned long)psize) << (i * 4)); | 209 | (((unsigned long)psize) << (i * 4)); |
203 | 210 | ||
204 | hpsizes = mm->context.high_slices_psize; | 211 | /* Assign the value back */ |
205 | for (i = 0; i < SLICE_NUM_HIGH; i++) | ||
206 | if (mask.high_slices & (1u << i)) | ||
207 | hpsizes = (hpsizes & ~(0xful << (i * 4))) | | ||
208 | (((unsigned long)psize) << (i * 4)); | ||
209 | |||
210 | mm->context.low_slices_psize = lpsizes; | 212 | mm->context.low_slices_psize = lpsizes; |
211 | mm->context.high_slices_psize = hpsizes; | 213 | |
214 | hpsizes = mm->context.high_slices_psize; | ||
215 | for (i = 0; i < SLICE_NUM_HIGH; i++) { | ||
216 | mask_index = i & 0x1; | ||
217 | index = i >> 1; | ||
218 | if (mask.high_slices & (1ul << i)) | ||
219 | hpsizes[index] = (hpsizes[index] & | ||
220 | ~(0xf << (mask_index * 4))) | | ||
221 | (((unsigned long)psize) << (mask_index * 4)); | ||
222 | } | ||
212 | 223 | ||
213 | slice_dbg(" lsps=%lx, hsps=%lx\n", | 224 | slice_dbg(" lsps=%lx, hsps=%lx\n", |
214 | mm->context.low_slices_psize, | 225 | mm->context.low_slices_psize, |
@@ -587,18 +598,19 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, | |||
587 | 598 | ||
588 | unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr) | 599 | unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr) |
589 | { | 600 | { |
590 | u64 psizes; | 601 | unsigned char *hpsizes; |
591 | int index; | 602 | int index, mask_index; |
592 | 603 | ||
593 | if (addr < SLICE_LOW_TOP) { | 604 | if (addr < SLICE_LOW_TOP) { |
594 | psizes = mm->context.low_slices_psize; | 605 | u64 lpsizes; |
606 | lpsizes = mm->context.low_slices_psize; | ||
595 | index = GET_LOW_SLICE_INDEX(addr); | 607 | index = GET_LOW_SLICE_INDEX(addr); |
596 | } else { | 608 | return (lpsizes >> (index * 4)) & 0xf; |
597 | psizes = mm->context.high_slices_psize; | ||
598 | index = GET_HIGH_SLICE_INDEX(addr); | ||
599 | } | 609 | } |
600 | 610 | hpsizes = mm->context.high_slices_psize; | |
601 | return (psizes >> (index * 4)) & 0xf; | 611 | index = GET_HIGH_SLICE_INDEX(addr); |
612 | mask_index = index & 0x1; | ||
613 | return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xf; | ||
602 | } | 614 | } |
603 | EXPORT_SYMBOL_GPL(get_slice_psize); | 615 | EXPORT_SYMBOL_GPL(get_slice_psize); |
604 | 616 | ||
@@ -618,7 +630,9 @@ EXPORT_SYMBOL_GPL(get_slice_psize); | |||
618 | */ | 630 | */ |
619 | void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) | 631 | void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) |
620 | { | 632 | { |
621 | unsigned long flags, lpsizes, hpsizes; | 633 | int index, mask_index; |
634 | unsigned char *hpsizes; | ||
635 | unsigned long flags, lpsizes; | ||
622 | unsigned int old_psize; | 636 | unsigned int old_psize; |
623 | int i; | 637 | int i; |
624 | 638 | ||
@@ -639,15 +653,21 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) | |||
639 | if (((lpsizes >> (i * 4)) & 0xf) == old_psize) | 653 | if (((lpsizes >> (i * 4)) & 0xf) == old_psize) |
640 | lpsizes = (lpsizes & ~(0xful << (i * 4))) | | 654 | lpsizes = (lpsizes & ~(0xful << (i * 4))) | |
641 | (((unsigned long)psize) << (i * 4)); | 655 | (((unsigned long)psize) << (i * 4)); |
656 | /* Assign the value back */ | ||
657 | mm->context.low_slices_psize = lpsizes; | ||
642 | 658 | ||
643 | hpsizes = mm->context.high_slices_psize; | 659 | hpsizes = mm->context.high_slices_psize; |
644 | for (i = 0; i < SLICE_NUM_HIGH; i++) | 660 | for (i = 0; i < SLICE_NUM_HIGH; i++) { |
645 | if (((hpsizes >> (i * 4)) & 0xf) == old_psize) | 661 | mask_index = i & 0x1; |
646 | hpsizes = (hpsizes & ~(0xful << (i * 4))) | | 662 | index = i >> 1; |
647 | (((unsigned long)psize) << (i * 4)); | 663 | if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == old_psize) |
664 | hpsizes[index] = (hpsizes[index] & | ||
665 | ~(0xf << (mask_index * 4))) | | ||
666 | (((unsigned long)psize) << (mask_index * 4)); | ||
667 | } | ||
668 | |||
669 | |||
648 | 670 | ||
649 | mm->context.low_slices_psize = lpsizes; | ||
650 | mm->context.high_slices_psize = hpsizes; | ||
651 | 671 | ||
652 | slice_dbg(" lsps=%lx, hsps=%lx\n", | 672 | slice_dbg(" lsps=%lx, hsps=%lx\n", |
653 | mm->context.low_slices_psize, | 673 | mm->context.low_slices_psize, |
@@ -660,18 +680,27 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) | |||
660 | void slice_set_psize(struct mm_struct *mm, unsigned long address, | 680 | void slice_set_psize(struct mm_struct *mm, unsigned long address, |
661 | unsigned int psize) | 681 | unsigned int psize) |
662 | { | 682 | { |
683 | unsigned char *hpsizes; | ||
663 | unsigned long i, flags; | 684 | unsigned long i, flags; |
664 | u64 *p; | 685 | u64 *lpsizes; |
665 | 686 | ||
666 | spin_lock_irqsave(&slice_convert_lock, flags); | 687 | spin_lock_irqsave(&slice_convert_lock, flags); |
667 | if (address < SLICE_LOW_TOP) { | 688 | if (address < SLICE_LOW_TOP) { |
668 | i = GET_LOW_SLICE_INDEX(address); | 689 | i = GET_LOW_SLICE_INDEX(address); |
669 | p = &mm->context.low_slices_psize; | 690 | lpsizes = &mm->context.low_slices_psize; |
691 | *lpsizes = (*lpsizes & ~(0xful << (i * 4))) | | ||
692 | ((unsigned long) psize << (i * 4)); | ||
670 | } else { | 693 | } else { |
694 | int index, mask_index; | ||
671 | i = GET_HIGH_SLICE_INDEX(address); | 695 | i = GET_HIGH_SLICE_INDEX(address); |
672 | p = &mm->context.high_slices_psize; | 696 | hpsizes = mm->context.high_slices_psize; |
697 | mask_index = i & 0x1; | ||
698 | index = i >> 1; | ||
699 | hpsizes[index] = (hpsizes[index] & | ||
700 | ~(0xf << (mask_index * 4))) | | ||
701 | (((unsigned long)psize) << (mask_index * 4)); | ||
673 | } | 702 | } |
674 | *p = (*p & ~(0xful << (i * 4))) | ((unsigned long) psize << (i * 4)); | 703 | |
675 | spin_unlock_irqrestore(&slice_convert_lock, flags); | 704 | spin_unlock_irqrestore(&slice_convert_lock, flags); |
676 | 705 | ||
677 | #ifdef CONFIG_SPU_BASE | 706 | #ifdef CONFIG_SPU_BASE |