[POWERPC] Fix spu SLB invalidations

The SPU code doesn't properly invalidate SPUs SLBs when necessary,
for example when changing a segment size from the hugetlbfs code. In
addition, it saves and restores the SLB content on context switches
which makes it harder to properly handle those invalidations.

This patch removes the saving & restoring for now, something more
efficient might be found later on. It also adds a spu_flush_all_slbs(mm)
that can be used by the core mm code to flush the SLBs of all SPEs that
are running a given mm at the time of the flush.

In order to do that, it adds a spinlock to the list of all SPEs and move
some bits & pieces from spufs to spu_base.c

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by Benjamin Herrenschmidt and committed by Arnd Bergmann 94b2a439 50b520d4

+91 -86
+6
arch/powerpc/mm/hash_utils_64.c
··· 685 685 "non-cacheable mapping\n"); 686 686 psize = mmu_vmalloc_psize = MMU_PAGE_4K; 687 687 } 688 + #ifdef CONFIG_SPE_BASE 689 + spu_flush_all_slbs(mm); 690 + #endif 688 691 } 689 692 if (user_region) { 690 693 if (psize != get_paca()->context.user_psize) { ··· 762 759 mmu_psize_defs[MMU_PAGE_4K].sllp; 763 760 get_paca()->context = mm->context; 764 761 slb_flush_and_rebolt(); 762 + #ifdef CONFIG_SPE_BASE 763 + spu_flush_all_slbs(mm); 764 + #endif 765 765 } 766 766 } 767 767 if (mm->context.user_psize == MMU_PAGE_64K)
+4
arch/powerpc/mm/hugetlbpage.c
··· 24 24 #include <asm/machdep.h> 25 25 #include <asm/cputable.h> 26 26 #include <asm/tlb.h> 27 + #include <asm/spu.h> 27 28 28 29 #include <linux/sysctl.h> 29 30 ··· 514 513 if ((addr + len) > 0x100000000UL) 515 514 err = open_high_hpage_areas(current->mm, 516 515 HTLB_AREA_MASK(addr, len)); 516 + #ifdef CONFIG_SPE_BASE 517 + spu_flush_all_slbs(current->mm); 518 + #endif 517 519 if (err) { 518 520 printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)" 519 521 " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
+69 -12
arch/powerpc/platforms/cell/spu_base.c
··· 38 38 const struct spu_management_ops *spu_management_ops; 39 39 const struct spu_priv1_ops *spu_priv1_ops; 40 40 41 + static struct list_head spu_list[MAX_NUMNODES]; 42 + static LIST_HEAD(spu_full_list); 43 + static DEFINE_MUTEX(spu_mutex); 44 + static spinlock_t spu_list_lock = SPIN_LOCK_UNLOCKED; 45 + 41 46 EXPORT_SYMBOL_GPL(spu_priv1_ops); 47 + 48 + void spu_invalidate_slbs(struct spu *spu) 49 + { 50 + struct spu_priv2 __iomem *priv2 = spu->priv2; 51 + 52 + if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) 53 + out_be64(&priv2->slb_invalidate_all_W, 0UL); 54 + } 55 + EXPORT_SYMBOL_GPL(spu_invalidate_slbs); 56 + 57 + /* This is called by the MM core when a segment size is changed, to 58 + * request a flush of all the SPEs using a given mm 59 + */ 60 + void spu_flush_all_slbs(struct mm_struct *mm) 61 + { 62 + struct spu *spu; 63 + unsigned long flags; 64 + 65 + spin_lock_irqsave(&spu_list_lock, flags); 66 + list_for_each_entry(spu, &spu_full_list, full_list) { 67 + if (spu->mm == mm) 68 + spu_invalidate_slbs(spu); 69 + } 70 + spin_unlock_irqrestore(&spu_list_lock, flags); 71 + } 72 + 73 + /* The hack below stinks... try to do something better one of 74 + * these days... Does it even work properly with NR_CPUS == 1 ? 75 + */ 76 + static inline void mm_needs_global_tlbie(struct mm_struct *mm) 77 + { 78 + int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1; 79 + 80 + /* Global TLBIE broadcast required with SPEs. */ 81 + __cpus_setall(&mm->cpu_vm_mask, nr); 82 + } 83 + 84 + void spu_associate_mm(struct spu *spu, struct mm_struct *mm) 85 + { 86 + unsigned long flags; 87 + 88 + spin_lock_irqsave(&spu_list_lock, flags); 89 + spu->mm = mm; 90 + spin_unlock_irqrestore(&spu_list_lock, flags); 91 + if (mm) 92 + mm_needs_global_tlbie(mm); 93 + } 94 + EXPORT_SYMBOL_GPL(spu_associate_mm); 42 95 43 96 static int __spu_trap_invalid_dma(struct spu *spu) 44 97 { ··· 127 74 struct spu_priv2 __iomem *priv2 = spu->priv2; 128 75 struct mm_struct *mm = spu->mm; 129 76 u64 esid, vsid, llp; 77 + int psize; 130 78 131 79 pr_debug("%s\n", __FUNCTION__); 132 80 ··· 144 90 case USER_REGION_ID: 145 91 #ifdef CONFIG_HUGETLB_PAGE 146 92 if (in_hugepage_area(mm->context, ea)) 147 - llp = mmu_psize_defs[mmu_huge_psize].sllp; 93 + psize = mmu_huge_psize; 148 94 else 149 95 #endif 150 - llp = mmu_psize_defs[mmu_virtual_psize].sllp; 96 + psize = mm->context.user_psize; 151 97 vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) | 152 - SLB_VSID_USER | llp; 98 + SLB_VSID_USER; 153 99 break; 154 100 case VMALLOC_REGION_ID: 155 - llp = mmu_psize_defs[mmu_virtual_psize].sllp; 101 + if (ea < VMALLOC_END) 102 + psize = mmu_vmalloc_psize; 103 + else 104 + psize = mmu_io_psize; 156 105 vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | 157 - SLB_VSID_KERNEL | llp; 106 + SLB_VSID_KERNEL; 158 107 break; 159 108 case KERNEL_REGION_ID: 160 - llp = mmu_psize_defs[mmu_linear_psize].sllp; 109 + psize = mmu_linear_psize; 161 110 vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) | 162 - SLB_VSID_KERNEL | llp; 111 + SLB_VSID_KERNEL; 163 112 break; 164 113 default: 165 114 /* Future: support kernel segments so that drivers ··· 171 114 pr_debug("invalid region access at %016lx\n", ea); 172 115 return 1; 173 116 } 117 + llp = mmu_psize_defs[psize].sllp; 174 118 175 119 out_be64(&priv2->slb_index_W, spu->slb_replace); 176 - out_be64(&priv2->slb_vsid_RW, vsid); 120 + out_be64(&priv2->slb_vsid_RW, vsid | llp); 177 121 out_be64(&priv2->slb_esid_RW, esid); 178 122 179 123 spu->slb_replace++; ··· 387 329 if (spu->irqs[2] != NO_IRQ) 388 330 free_irq(spu->irqs[2], spu); 389 331 } 390 - 391 - static struct list_head spu_list[MAX_NUMNODES]; 392 - static LIST_HEAD(spu_full_list); 393 - static DEFINE_MUTEX(spu_mutex); 394 332 395 333 static void spu_init_channels(struct spu *spu) 396 334 { ··· 647 593 struct spu *spu; 648 594 int ret; 649 595 static int number; 596 + unsigned long flags; 650 597 651 598 ret = -ENOMEM; 652 599 spu = kzalloc(sizeof (*spu), GFP_KERNEL); ··· 675 620 goto out_free_irqs; 676 621 677 622 mutex_lock(&spu_mutex); 623 + spin_lock_irqsave(&spu_list_lock, flags); 678 624 list_add(&spu->list, &spu_list[spu->node]); 679 625 list_add(&spu->full_list, &spu_full_list); 626 + spin_unlock_irqrestore(&spu_list_lock, flags); 680 627 mutex_unlock(&spu_mutex); 681 628 682 629 goto out;
+2 -11
arch/powerpc/platforms/cell/spufs/sched.c
··· 127 127 mutex_unlock(&spu_prio->active_mutex[node]); 128 128 } 129 129 130 - static inline void mm_needs_global_tlbie(struct mm_struct *mm) 131 - { 132 - int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1; 133 - 134 - /* Global TLBIE broadcast required with SPEs. */ 135 - __cpus_setall(&mm->cpu_vm_mask, nr); 136 - } 137 - 138 130 static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier); 139 131 140 132 static void spu_switch_notify(struct spu *spu, struct spu_context *ctx) ··· 159 167 ctx->spu = spu; 160 168 ctx->ops = &spu_hw_ops; 161 169 spu->pid = current->pid; 162 - spu->mm = ctx->owner; 163 - mm_needs_global_tlbie(spu->mm); 170 + spu_associate_mm(spu, ctx->owner); 164 171 spu->ibox_callback = spufs_ibox_callback; 165 172 spu->wbox_callback = spufs_wbox_callback; 166 173 spu->stop_callback = spufs_stop_callback; ··· 196 205 spu->stop_callback = NULL; 197 206 spu->mfc_callback = NULL; 198 207 spu->dma_callback = NULL; 199 - spu->mm = NULL; 208 + spu_associate_mm(spu, NULL); 200 209 spu->pid = 0; 201 210 ctx->ops = &spu_backing_ops; 202 211 ctx->spu = NULL;
+3 -59
arch/powerpc/platforms/cell/spufs/switch.c
··· 468 468 MFC_CNTL_PURGE_DMA_COMPLETE); 469 469 } 470 470 471 - static inline void save_mfc_slbs(struct spu_state *csa, struct spu *spu) 472 - { 473 - struct spu_priv2 __iomem *priv2 = spu->priv2; 474 - int i; 475 - 476 - /* Save, Step 29: 477 - * If MFC_SR1[R]='1', save SLBs in CSA. 478 - */ 479 - if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) { 480 - csa->priv2.slb_index_W = in_be64(&priv2->slb_index_W); 481 - for (i = 0; i < 8; i++) { 482 - out_be64(&priv2->slb_index_W, i); 483 - eieio(); 484 - csa->slb_esid_RW[i] = in_be64(&priv2->slb_esid_RW); 485 - csa->slb_vsid_RW[i] = in_be64(&priv2->slb_vsid_RW); 486 - eieio(); 487 - } 488 - } 489 - } 490 - 491 471 static inline void setup_mfc_sr1(struct spu_state *csa, struct spu *spu) 492 472 { 493 473 /* Save, Step 30: ··· 688 708 out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE); 689 709 } 690 710 691 - static inline void invalidate_slbs(struct spu_state *csa, struct spu *spu) 692 - { 693 - struct spu_priv2 __iomem *priv2 = spu->priv2; 694 - 695 - /* Save, Step 45: 696 - * Restore, Step 19: 697 - * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All. 698 - */ 699 - if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK) { 700 - out_be64(&priv2->slb_invalidate_all_W, 0UL); 701 - eieio(); 702 - } 703 - } 704 - 705 711 static inline void get_kernel_slb(u64 ea, u64 slb[2]) 706 712 { 707 713 u64 llp; ··· 731 765 * MFC_SR1[R]=1 (in other words, assume that 732 766 * translation is desired by OS environment). 733 767 */ 734 - invalidate_slbs(csa, spu); 768 + spu_invalidate_slbs(spu); 735 769 get_kernel_slb((unsigned long)&spu_save_code[0], code_slb); 736 770 get_kernel_slb((unsigned long)csa->lscsa, lscsa_slb); 737 771 load_mfc_slb(spu, code_slb, 0); ··· 1684 1718 } 1685 1719 } 1686 1720 1687 - static inline void restore_mfc_slbs(struct spu_state *csa, struct spu *spu) 1688 - { 1689 - struct spu_priv2 __iomem *priv2 = spu->priv2; 1690 - int i; 1691 - 1692 - /* Restore, Step 68: 1693 - * If MFC_SR1[R]='1', restore SLBs from CSA. 1694 - */ 1695 - if (csa->priv1.mfc_sr1_RW & MFC_STATE1_RELOCATE_MASK) { 1696 - for (i = 0; i < 8; i++) { 1697 - out_be64(&priv2->slb_index_W, i); 1698 - eieio(); 1699 - out_be64(&priv2->slb_esid_RW, csa->slb_esid_RW[i]); 1700 - out_be64(&priv2->slb_vsid_RW, csa->slb_vsid_RW[i]); 1701 - eieio(); 1702 - } 1703 - out_be64(&priv2->slb_index_W, csa->priv2.slb_index_W); 1704 - eieio(); 1705 - } 1706 - } 1707 - 1708 1721 static inline void restore_mfc_sr1(struct spu_state *csa, struct spu *spu) 1709 1722 { 1710 1723 /* Restore, Step 69: ··· 1820 1875 set_mfc_tclass_id(prev, spu); /* Step 26. */ 1821 1876 purge_mfc_queue(prev, spu); /* Step 27. */ 1822 1877 wait_purge_complete(prev, spu); /* Step 28. */ 1823 - save_mfc_slbs(prev, spu); /* Step 29. */ 1824 1878 setup_mfc_sr1(prev, spu); /* Step 30. */ 1825 1879 save_spu_npc(prev, spu); /* Step 31. */ 1826 1880 save_spu_privcntl(prev, spu); /* Step 32. */ ··· 1931 1987 reset_spu_privcntl(prev, spu); /* Step 16. */ 1932 1988 reset_spu_lslr(prev, spu); /* Step 17. */ 1933 1989 setup_mfc_sr1(prev, spu); /* Step 18. */ 1934 - invalidate_slbs(prev, spu); /* Step 19. */ 1990 + spu_invalidate_slbs(spu); /* Step 19. */ 1935 1991 reset_ch_part1(prev, spu); /* Step 20. */ 1936 1992 reset_ch_part2(prev, spu); /* Step 21. */ 1937 1993 enable_interrupts(prev, spu); /* Step 22. */ ··· 1999 2055 restore_spu_mb(next, spu); /* Step 65. */ 2000 2056 check_ppu_mb_stat(next, spu); /* Step 66. */ 2001 2057 check_ppuint_mb_stat(next, spu); /* Step 67. */ 2002 - restore_mfc_slbs(next, spu); /* Step 68. */ 2058 + spu_invalidate_slbs(spu); /* Modified Step 68. */ 2003 2059 restore_mfc_sr1(next, spu); /* Step 69. */ 2004 2060 restore_other_spu_access(next, spu); /* Step 70. */ 2005 2061 restore_spu_runcntl(next, spu); /* Step 71. */
+7
include/asm-powerpc/spu.h
··· 165 165 int spu_irq_class_1_bottom(struct spu *spu); 166 166 void spu_irq_setaffinity(struct spu *spu, int cpu); 167 167 168 + extern void spu_invalidate_slbs(struct spu *spu); 169 + extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm); 170 + 171 + /* Calls from the memory management to the SPU */ 172 + struct mm_struct; 173 + extern void spu_flush_all_slbs(struct mm_struct *mm); 174 + 168 175 /* system callbacks from the SPU */ 169 176 struct spu_syscall_block { 170 177 u64 nr_ret;
-4
include/asm-powerpc/spu_csa.h
··· 221 221 * @spu_chnlcnt_RW: Array of saved channel counts. 222 222 * @spu_chnldata_RW: Array of saved channel data. 223 223 * @suspend_time: Time stamp when decrementer disabled. 224 - * @slb_esid_RW: Array of saved SLB esid entries. 225 - * @slb_vsid_RW: Array of saved SLB vsid entries. 226 224 * 227 225 * Structure representing the whole of the SPU 228 226 * context save area (CSA). This struct contains ··· 243 245 u32 spu_mailbox_data[4]; 244 246 u32 pu_mailbox_data[1]; 245 247 unsigned long suspend_time; 246 - u64 slb_esid_RW[8]; 247 - u64 slb_vsid_RW[8]; 248 248 spinlock_t register_lock; 249 249 }; 250 250