Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/mm: Increase the slice range to 64TB

This patch makes the high psizes mask as an unsigned char array
so that we can have more than 16TB. Currently we support upto
64TB

Reviewed-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Aneesh Kumar K.V and committed by
Benjamin Herrenschmidt
7aa0727f 67550080

+109 -55
+5 -1
arch/powerpc/include/asm/mmu-hash64.h
··· 460 460 461 461 #ifdef CONFIG_PPC_MM_SLICES 462 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 468 #else 465 469 u16 sllp; /* SLB page size encoding */ 466 470 #endif
+5 -1
arch/powerpc/include/asm/page_64.h
··· 82 82 83 83 struct slice_mask { 84 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 92 struct mm_struct;
+9 -6
arch/powerpc/mm/hash_utils_64.c
··· 803 803 #ifdef CONFIG_PPC_MM_SLICES 804 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 810 if (addr < SLICE_LOW_TOP) { 809 - slices = get_paca()->context.low_slices_psize; 811 + lpsizes = get_paca()->context.low_slices_psize; 810 812 index = GET_LOW_SLICE_INDEX(addr); 811 - } else { 812 - slices = get_paca()->context.high_slices_psize; 813 - index = GET_HIGH_SLICE_INDEX(addr); 813 + return (lpsizes >> (index * 4)) & 0xF; 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 821 #else
+22 -8
arch/powerpc/mm/slb_low.S
··· 108 108 * between 4k and 64k standard page size 109 109 */ 110 110 #ifdef CONFIG_PPC_MM_SLICES 111 + /* r10 have esid */ 111 112 cmpldi r10,16 112 - 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 113 + /* below SLICE_LOW_TOP */ 116 114 blt 5f 117 - ld r9,PACAHIGHSLICEPSIZE(r13) 118 - srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2) 119 - andi. r11,r11,0x3c 115 + /* 116 + * Handle hpsizes, 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 136 srd r9,r9,r11 123 137 andi. r9,r9,0xf 124 138 mulli r9,r9,MMUPSIZEDEFSIZE
+68 -39
arch/powerpc/mm/slice.c
··· 42 42 43 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 46 int i; 47 47 48 48 if (!_slice_debug) ··· 54 54 *(p++) = '-'; 55 55 *(p++) = ' '; 56 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 58 *(p++) = 0; 59 59 60 60 printk(KERN_DEBUG "%s:%s\n", label, buf); ··· 84 84 } 85 85 86 86 if ((start + len) > SLICE_LOW_TOP) 87 - ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1)) 88 - - (1u << GET_HIGH_SLICE_INDEX(start)); 87 + ret.high_slices = (1ul << (GET_HIGH_SLICE_INDEX(end) + 1)) 88 + - (1ul << GET_HIGH_SLICE_INDEX(start)); 89 89 90 90 return ret; 91 91 } ··· 135 135 136 136 for (i = 0; i < SLICE_NUM_HIGH; i++) 137 137 if (!slice_high_has_vma(mm, i)) 138 - ret.high_slices |= 1u << i; 138 + ret.high_slices |= 1ul << i; 139 139 140 140 return ret; 141 141 } 142 142 143 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 147 struct slice_mask ret = { 0, 0 }; 146 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 152 for (i = 0; i < SLICE_NUM_LOW; i++) 151 - if (((psizes >> (i * 4)) & 0xf) == psize) 153 + if (((lpsizes >> (i * 4)) & 0xf) == psize) 152 154 ret.low_slices |= 1u << i; 153 155 154 - psizes = mm->context.high_slices_psize; 155 - for (i = 0; i < SLICE_NUM_HIGH; i++) 156 - if (((psizes >> (i * 4)) & 0xf) == psize) 157 - ret.high_slices |= 1u << i; 156 + hpsizes = mm->context.high_slices_psize; 157 + for (i = 0; i < SLICE_NUM_HIGH; i++) { 158 + mask_index = i & 0x1; 159 + index = i >> 1; 160 + if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == psize) 161 + ret.high_slices |= 1ul << i; 162 + } 158 163 159 164 return ret; 160 165 } ··· 188 183 189 184 static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize) 190 185 { 186 + int index, mask_index; 191 187 /* Write the new slice psize bits */ 192 - u64 lpsizes, hpsizes; 188 + unsigned char *hpsizes; 189 + u64 lpsizes; 193 190 unsigned long i, flags; 194 191 195 192 slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize); ··· 208 201 lpsizes = (lpsizes & ~(0xful << (i * 4))) | 209 202 (((unsigned long)psize) << (i * 4)); 210 203 211 - hpsizes = mm->context.high_slices_psize; 212 - for (i = 0; i < SLICE_NUM_HIGH; i++) 213 - if (mask.high_slices & (1u << i)) 214 - hpsizes = (hpsizes & ~(0xful << (i * 4))) | 215 - (((unsigned long)psize) << (i * 4)); 216 - 204 + /* Assign the value back */ 217 205 mm->context.low_slices_psize = lpsizes; 218 - mm->context.high_slices_psize = hpsizes; 206 + 207 + hpsizes = mm->context.high_slices_psize; 208 + for (i = 0; i < SLICE_NUM_HIGH; i++) { 209 + mask_index = i & 0x1; 210 + index = i >> 1; 211 + if (mask.high_slices & (1ul << i)) 212 + hpsizes[index] = (hpsizes[index] & 213 + ~(0xf << (mask_index * 4))) | 214 + (((unsigned long)psize) << (mask_index * 4)); 215 + } 219 216 220 217 slice_dbg(" lsps=%lx, hsps=%lx\n", 221 218 mm->context.low_slices_psize, ··· 598 587 599 588 unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr) 600 589 { 601 - u64 psizes; 602 - int index; 590 + unsigned char *hpsizes; 591 + int index, mask_index; 603 592 604 593 if (addr < SLICE_LOW_TOP) { 605 - psizes = mm->context.low_slices_psize; 594 + u64 lpsizes; 595 + lpsizes = mm->context.low_slices_psize; 606 596 index = GET_LOW_SLICE_INDEX(addr); 607 - } else { 608 - psizes = mm->context.high_slices_psize; 609 - index = GET_HIGH_SLICE_INDEX(addr); 597 + return (lpsizes >> (index * 4)) & 0xf; 610 598 } 611 - 612 - return (psizes >> (index * 4)) & 0xf; 599 + hpsizes = mm->context.high_slices_psize; 600 + index = GET_HIGH_SLICE_INDEX(addr); 601 + mask_index = index & 0x1; 602 + return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xf; 613 603 } 614 604 EXPORT_SYMBOL_GPL(get_slice_psize); 615 605 ··· 630 618 */ 631 619 void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) 632 620 { 633 - unsigned long flags, lpsizes, hpsizes; 621 + int index, mask_index; 622 + unsigned char *hpsizes; 623 + unsigned long flags, lpsizes; 634 624 unsigned int old_psize; 635 625 int i; 636 626 ··· 653 639 if (((lpsizes >> (i * 4)) & 0xf) == old_psize) 654 640 lpsizes = (lpsizes & ~(0xful << (i * 4))) | 655 641 (((unsigned long)psize) << (i * 4)); 642 + /* Assign the value back */ 643 + mm->context.low_slices_psize = lpsizes; 656 644 657 645 hpsizes = mm->context.high_slices_psize; 658 - for (i = 0; i < SLICE_NUM_HIGH; i++) 659 - if (((hpsizes >> (i * 4)) & 0xf) == old_psize) 660 - hpsizes = (hpsizes & ~(0xful << (i * 4))) | 661 - (((unsigned long)psize) << (i * 4)); 646 + for (i = 0; i < SLICE_NUM_HIGH; i++) { 647 + mask_index = i & 0x1; 648 + index = i >> 1; 649 + if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == old_psize) 650 + hpsizes[index] = (hpsizes[index] & 651 + ~(0xf << (mask_index * 4))) | 652 + (((unsigned long)psize) << (mask_index * 4)); 653 + } 662 654 663 - mm->context.low_slices_psize = lpsizes; 664 - mm->context.high_slices_psize = hpsizes; 655 + 656 + 665 657 666 658 slice_dbg(" lsps=%lx, hsps=%lx\n", 667 659 mm->context.low_slices_psize, ··· 680 660 void slice_set_psize(struct mm_struct *mm, unsigned long address, 681 661 unsigned int psize) 682 662 { 663 + unsigned char *hpsizes; 683 664 unsigned long i, flags; 684 - u64 *p; 665 + u64 *lpsizes; 685 666 686 667 spin_lock_irqsave(&slice_convert_lock, flags); 687 668 if (address < SLICE_LOW_TOP) { 688 669 i = GET_LOW_SLICE_INDEX(address); 689 - p = &mm->context.low_slices_psize; 670 + lpsizes = &mm->context.low_slices_psize; 671 + *lpsizes = (*lpsizes & ~(0xful << (i * 4))) | 672 + ((unsigned long) psize << (i * 4)); 690 673 } else { 674 + int index, mask_index; 691 675 i = GET_HIGH_SLICE_INDEX(address); 692 - p = &mm->context.high_slices_psize; 676 + hpsizes = mm->context.high_slices_psize; 677 + mask_index = i & 0x1; 678 + index = i >> 1; 679 + hpsizes[index] = (hpsizes[index] & 680 + ~(0xf << (mask_index * 4))) | 681 + (((unsigned long)psize) << (mask_index * 4)); 693 682 } 694 - *p = (*p & ~(0xful << (i * 4))) | ((unsigned long) psize << (i * 4)); 683 + 695 684 spin_unlock_irqrestore(&slice_convert_lock, flags); 696 685 697 686 #ifdef CONFIG_SPU_BASE