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

Merge tag 'x86_core_for_v6.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 cpu updates from Borislav Petkov:

- Add helpers for WB{NO,}INVD with the purpose of using them in KVM and
thus diminish the number of invalidations needed. With preceding
cleanups, as always

* tag 'x86_core_for_v6.17_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/lib: Add WBINVD and WBNOINVD helpers to target multiple CPUs
x86/lib: Add WBNOINVD helper functions
x86/lib: Drop the unused return value from wbinvd_on_all_cpus()
drm/gpu: Remove dead checks on wbinvd_on_all_cpus()'s return value

+76 -14
+20 -3
arch/x86/include/asm/smp.h
··· 112 112 void native_play_dead(void); 113 113 void play_dead_common(void); 114 114 void wbinvd_on_cpu(int cpu); 115 - int wbinvd_on_all_cpus(void); 115 + void wbinvd_on_all_cpus(void); 116 + void wbinvd_on_cpus_mask(struct cpumask *cpus); 117 + void wbnoinvd_on_all_cpus(void); 118 + void wbnoinvd_on_cpus_mask(struct cpumask *cpus); 116 119 117 120 void smp_kick_mwait_play_dead(void); 118 121 void __noreturn mwait_play_dead(unsigned int eax_hint); ··· 151 148 152 149 #else /* !CONFIG_SMP */ 153 150 #define wbinvd_on_cpu(cpu) wbinvd() 154 - static inline int wbinvd_on_all_cpus(void) 151 + static inline void wbinvd_on_all_cpus(void) 155 152 { 156 153 wbinvd(); 157 - return 0; 154 + } 155 + 156 + static inline void wbinvd_on_cpus_mask(struct cpumask *cpus) 157 + { 158 + wbinvd(); 159 + } 160 + 161 + static inline void wbnoinvd_on_all_cpus(void) 162 + { 163 + wbnoinvd(); 164 + } 165 + 166 + static inline void wbnoinvd_on_cpus_mask(struct cpumask *cpus) 167 + { 168 + wbnoinvd(); 158 169 } 159 170 160 171 static inline struct cpumask *cpu_llc_shared_mask(int cpu)
+28 -1
arch/x86/include/asm/special_insns.h
··· 104 104 } 105 105 #endif 106 106 107 + /* 108 + * Write back all modified lines in all levels of cache associated with this 109 + * logical processor to main memory, and then invalidate all caches. Depending 110 + * on the micro-architecture, WBINVD (and WBNOINVD below) may or may not affect 111 + * lower level caches associated with another logical processor that shares any 112 + * level of this processor's cache hierarchy. 113 + */ 107 114 static __always_inline void wbinvd(void) 108 115 { 109 - asm volatile("wbinvd": : :"memory"); 116 + asm volatile("wbinvd" : : : "memory"); 117 + } 118 + 119 + /* Instruction encoding provided for binutils backwards compatibility. */ 120 + #define ASM_WBNOINVD _ASM_BYTES(0xf3,0x0f,0x09) 121 + 122 + /* 123 + * Write back all modified lines in all levels of cache associated with this 124 + * logical processor to main memory, but do NOT explicitly invalidate caches, 125 + * i.e. leave all/most cache lines in the hierarchy in non-modified state. 126 + */ 127 + static __always_inline void wbnoinvd(void) 128 + { 129 + /* 130 + * Explicitly encode WBINVD if X86_FEATURE_WBNOINVD is unavailable even 131 + * though WBNOINVD is backwards compatible (it's simply WBINVD with an 132 + * ignored REP prefix), to guarantee that WBNOINVD isn't used if it 133 + * needs to be avoided for any reason. For all supported usage in the 134 + * kernel, WBINVD is functionally a superset of WBNOINVD. 135 + */ 136 + alternative("wbinvd", ASM_WBNOINVD, X86_FEATURE_WBNOINVD); 110 137 } 111 138 112 139 static inline unsigned long __read_cr4(void)
+1 -2
arch/x86/kvm/x86.c
··· 8295 8295 int cpu = get_cpu(); 8296 8296 8297 8297 cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask); 8298 - on_each_cpu_mask(vcpu->arch.wbinvd_dirty_mask, 8299 - wbinvd_ipi, NULL, 1); 8298 + wbinvd_on_cpus_mask(vcpu->arch.wbinvd_dirty_mask); 8300 8299 put_cpu(); 8301 8300 cpumask_clear(vcpu->arch.wbinvd_dirty_mask); 8302 8301 } else
+24 -2
arch/x86/lib/cache-smp.c
··· 14 14 } 15 15 EXPORT_SYMBOL(wbinvd_on_cpu); 16 16 17 - int wbinvd_on_all_cpus(void) 17 + void wbinvd_on_all_cpus(void) 18 18 { 19 19 on_each_cpu(__wbinvd, NULL, 1); 20 - return 0; 21 20 } 22 21 EXPORT_SYMBOL(wbinvd_on_all_cpus); 22 + 23 + void wbinvd_on_cpus_mask(struct cpumask *cpus) 24 + { 25 + on_each_cpu_mask(cpus, __wbinvd, NULL, 1); 26 + } 27 + EXPORT_SYMBOL_GPL(wbinvd_on_cpus_mask); 28 + 29 + static void __wbnoinvd(void *dummy) 30 + { 31 + wbnoinvd(); 32 + } 33 + 34 + void wbnoinvd_on_all_cpus(void) 35 + { 36 + on_each_cpu(__wbnoinvd, NULL, 1); 37 + } 38 + EXPORT_SYMBOL_GPL(wbnoinvd_on_all_cpus); 39 + 40 + void wbnoinvd_on_cpus_mask(struct cpumask *cpus) 41 + { 42 + on_each_cpu_mask(cpus, __wbnoinvd, NULL, 1); 43 + } 44 + EXPORT_SYMBOL_GPL(wbnoinvd_on_cpus_mask);
+3 -6
drivers/gpu/drm/drm_cache.c
··· 93 93 return; 94 94 } 95 95 96 - if (wbinvd_on_all_cpus()) 97 - pr_err("Timed out waiting for cache flush\n"); 96 + wbinvd_on_all_cpus(); 98 97 99 98 #elif defined(__powerpc__) 100 99 unsigned long i; ··· 138 139 return; 139 140 } 140 141 141 - if (wbinvd_on_all_cpus()) 142 - pr_err("Timed out waiting for cache flush\n"); 142 + wbinvd_on_all_cpus(); 143 143 #else 144 144 WARN_ONCE(1, "Architecture has no drm_cache.c support\n"); 145 145 #endif ··· 170 172 return; 171 173 } 172 174 173 - if (wbinvd_on_all_cpus()) 174 - pr_err("Timed out waiting for cache flush\n"); 175 + wbinvd_on_all_cpus(); 175 176 #else 176 177 WARN_ONCE(1, "Architecture has no drm_cache.c support\n"); 177 178 #endif