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

tile: convert uses of "inv" to "finv"

The "inv" (invalidate) instruction is generally less safe than "finv"
(flush and invalidate), as it will drop dirty data from the cache.
It turns out we have almost no need for "inv" (other than for the
older 32-bit architecture in some limited cases), so convert to
"finv" where possible and delete the extra "inv" infrastructure.

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>

+32 -103
+20 -24
arch/tile/include/asm/cacheflush.h
··· 75 75 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ 76 76 memcpy((dst), (src), (len)) 77 77 78 - /* 79 - * Invalidate a VA range; pads to L2 cacheline boundaries. 80 - * 81 - * Note that on TILE64, __inv_buffer() actually flushes modified 82 - * cache lines in addition to invalidating them, i.e., it's the 83 - * same as __finv_buffer(). 84 - */ 85 - static inline void __inv_buffer(void *buffer, size_t size) 86 - { 87 - char *next = (char *)((long)buffer & -L2_CACHE_BYTES); 88 - char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size); 89 - while (next < finish) { 90 - __insn_inv(next); 91 - next += CHIP_INV_STRIDE(); 92 - } 93 - } 94 - 95 78 /* Flush a VA range; pads to L2 cacheline boundaries. */ 96 79 static inline void __flush_buffer(void *buffer, size_t size) 97 80 { ··· 98 115 } 99 116 100 117 101 - /* Invalidate a VA range and wait for it to be complete. */ 102 - static inline void inv_buffer(void *buffer, size_t size) 103 - { 104 - __inv_buffer(buffer, size); 105 - mb(); 106 - } 107 - 108 118 /* 109 119 * Flush a locally-homecached VA range and wait for the evicted 110 120 * cachelines to hit memory. ··· 117 141 __finv_buffer(buffer, size); 118 142 mb_incoherent(); 119 143 } 144 + 145 + #ifdef __tilepro__ 146 + /* Invalidate a VA range; pads to L2 cacheline boundaries. */ 147 + static inline void __inv_buffer(void *buffer, size_t size) 148 + { 149 + char *next = (char *)((long)buffer & -L2_CACHE_BYTES); 150 + char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size); 151 + while (next < finish) { 152 + __insn_inv(next); 153 + next += CHIP_INV_STRIDE(); 154 + } 155 + } 156 + 157 + /* Invalidate a VA range and wait for it to be complete. */ 158 + static inline void inv_buffer(void *buffer, size_t size) 159 + { 160 + __inv_buffer(buffer, size); 161 + mb(); 162 + } 163 + #endif 120 164 121 165 /* 122 166 * Flush and invalidate a VA range that is homed remotely, waiting
-31
arch/tile/include/asm/uaccess.h
··· 567 567 } 568 568 569 569 /** 570 - * inv_user: - Invalidate a block of memory in user space from cache. 571 - * @mem: Destination address, in user space. 572 - * @len: Number of bytes to invalidate. 573 - * 574 - * Returns number of bytes that could not be invalidated. 575 - * On success, this will be zero. 576 - * 577 - * Note that on Tile64, the "inv" operation is in fact a 578 - * "flush and invalidate", so cache write-backs will occur prior 579 - * to the cache being marked invalid. 580 - */ 581 - extern unsigned long inv_user_asm(void __user *mem, unsigned long len); 582 - static inline unsigned long __must_check __inv_user( 583 - void __user *mem, unsigned long len) 584 - { 585 - int retval; 586 - 587 - might_fault(); 588 - retval = inv_user_asm(mem, len); 589 - mb_incoherent(); 590 - return retval; 591 - } 592 - static inline unsigned long __must_check inv_user( 593 - void __user *mem, unsigned long len) 594 - { 595 - if (access_ok(VERIFY_WRITE, mem, len)) 596 - return __inv_user(mem, len); 597 - return len; 598 - } 599 - 600 - /** 601 570 * finv_user: - Flush-inval a block of memory in user space from cache. 602 571 * @mem: Destination address, in user space. 603 572 * @len: Number of bytes to invalidate.
+2 -2
arch/tile/include/uapi/asm/cachectl.h
··· 29 29 * to honor the arguments at some point.) 30 30 * 31 31 * Flush and invalidation of memory can normally be performed with the 32 - * __insn_flush(), __insn_inv(), and __insn_finv() instructions from 33 - * userspace. The DCACHE option to the system call allows userspace 32 + * __insn_flush() and __insn_finv() instructions from userspace. 33 + * The DCACHE option to the system call allows userspace 34 34 * to flush the entire L1+L2 data cache from the core. In this case, 35 35 * the address and length arguments are not used. The DCACHE flush is 36 36 * restricted to the current core, not all cores in the address space.
+1 -1
arch/tile/kernel/head_32.S
··· 64 64 auli r0, r0, ha16(swapper_pg_dir - PAGE_OFFSET) 65 65 } 66 66 { 67 - inv r6 67 + finv r6 68 68 move r1, zero /* high 32 bits of CPA is zero */ 69 69 } 70 70 {
+1 -1
arch/tile/kernel/head_64.S
··· 77 77 { 78 78 /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */ 79 79 bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL 80 - inv r4 80 + finv r4 81 81 } 82 82 bnez r7, .Lno_write 83 83 {
+8 -5
arch/tile/lib/cacheflush.c
··· 147 147 force_load(p); 148 148 149 149 /* 150 - * Repeat, but with inv's instead of loads, to get rid of the 150 + * Repeat, but with finv's instead of loads, to get rid of the 151 151 * data we just loaded into our own cache and the old home L3. 152 - * No need to unroll since inv's don't target a register. 152 + * No need to unroll since finv's don't target a register. 153 + * The finv's are guaranteed not to actually flush the data in 154 + * the buffer back to their home, since we just read it, so the 155 + * lines are clean in cache; we will only invalidate those lines. 153 156 */ 154 157 p = (char *)buffer + size - 1; 155 - __insn_inv(p); 158 + __insn_finv(p); 156 159 p -= step_size; 157 160 p = (char *)((unsigned long)p | (step_size - 1)); 158 161 for (; p >= base; p -= step_size) 159 - __insn_inv(p); 162 + __insn_finv(p); 160 163 161 - /* Wait for the load+inv's (and thus finvs) to have completed. */ 164 + /* Wait for these finv's (and thus the first finvs) to be done. */ 162 165 __insn_mf(); 163 166 164 167 #ifdef __tilegx__
-1
arch/tile/lib/exports.c
··· 22 22 EXPORT_SYMBOL(strncpy_from_user_asm); 23 23 EXPORT_SYMBOL(clear_user_asm); 24 24 EXPORT_SYMBOL(flush_user_asm); 25 - EXPORT_SYMBOL(inv_user_asm); 26 25 EXPORT_SYMBOL(finv_user_asm); 27 26 28 27 /* arch/tile/kernel/entry.S */
-19
arch/tile/lib/usercopy_32.S
··· 109 109 .popsection 110 110 111 111 /* 112 - * inv_user_asm takes the user target address in r0 and the 113 - * number of bytes to invalidate in r1. 114 - * It returns the number of not inv'able bytes (hopefully zero) in r0. 115 - */ 116 - STD_ENTRY(inv_user_asm) 117 - bz r1, 2f 118 - { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } 119 - { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } 120 - { and r0, r0, r2; and r1, r1, r2 } 121 - { sub r1, r1, r0 } 122 - 1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() } 123 - { addi r0, r0, CHIP_INV_STRIDE(); bnzt r1, 1b } 124 - 2: { move r0, r1; jrp lr } 125 - STD_ENDPROC(inv_user_asm) 126 - .pushsection __ex_table,"a" 127 - .word 1b, 2b 128 - .popsection 129 - 130 - /* 131 112 * finv_user_asm takes the user target address in r0 and the 132 113 * number of bytes to flush-invalidate in r1. 133 114 * It returns the number of not finv'able bytes (hopefully zero) in r0.
-19
arch/tile/lib/usercopy_64.S
··· 109 109 .popsection 110 110 111 111 /* 112 - * inv_user_asm takes the user target address in r0 and the 113 - * number of bytes to invalidate in r1. 114 - * It returns the number of not inv'able bytes (hopefully zero) in r0. 115 - */ 116 - STD_ENTRY(inv_user_asm) 117 - beqz r1, 2f 118 - { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } 119 - { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } 120 - { and r0, r0, r2; and r1, r1, r2 } 121 - { sub r1, r1, r0 } 122 - 1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() } 123 - { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b } 124 - 2: { move r0, r1; jrp lr } 125 - STD_ENDPROC(inv_user_asm) 126 - .pushsection __ex_table,"a" 127 - .quad 1b, 2b 128 - .popsection 129 - 130 - /* 131 112 * finv_user_asm takes the user target address in r0 and the 132 113 * number of bytes to flush-invalidate in r1. 133 114 * It returns the number of not finv'able bytes (hopefully zero) in r0.