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

Merge tag 'kvm-s390-next-6.18-1' of https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD

KVM: s390: A bugfix and a performance improvement

* Improve interrupt cpu for wakeup, change the heuristic to decide wich
vCPU to deliver a floating interrupt to.
* Clear the pte when discarding a swapped page because of CMMA; this
bug was introduced in 6.16 when refactoring gmap code.

+44 -35
+1 -1
arch/s390/include/asm/kvm_host.h
··· 356 356 int counters[FIRQ_MAX_COUNT]; 357 357 struct kvm_s390_mchk_info mchk; 358 358 struct kvm_s390_ext_info srv_signal; 359 - int next_rr_cpu; 359 + int last_sleep_cpu; 360 360 struct mutex ais_lock; 361 361 u8 simm; 362 362 u8 nimm;
+22
arch/s390/include/asm/pgtable.h
··· 2055 2055 return res; 2056 2056 } 2057 2057 2058 + static inline pgste_t pgste_get_lock(pte_t *ptep) 2059 + { 2060 + unsigned long value = 0; 2061 + #ifdef CONFIG_PGSTE 2062 + unsigned long *ptr = (unsigned long *)(ptep + PTRS_PER_PTE); 2063 + 2064 + do { 2065 + value = __atomic64_or_barrier(PGSTE_PCL_BIT, ptr); 2066 + } while (value & PGSTE_PCL_BIT); 2067 + value |= PGSTE_PCL_BIT; 2068 + #endif 2069 + return __pgste(value); 2070 + } 2071 + 2072 + static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) 2073 + { 2074 + #ifdef CONFIG_PGSTE 2075 + barrier(); 2076 + WRITE_ONCE(*(unsigned long *)(ptep + PTRS_PER_PTE), pgste_val(pgste) & ~PGSTE_PCL_BIT); 2077 + #endif 2078 + } 2079 + 2058 2080 #endif /* _S390_PAGE_H */
+9 -11
arch/s390/kvm/interrupt.c
··· 1323 1323 VCPU_EVENT(vcpu, 4, "enabled wait: %llu ns", sltime); 1324 1324 no_timer: 1325 1325 kvm_vcpu_srcu_read_unlock(vcpu); 1326 + vcpu->kvm->arch.float_int.last_sleep_cpu = vcpu->vcpu_idx; 1326 1327 kvm_vcpu_halt(vcpu); 1327 1328 vcpu->valid_wakeup = false; 1328 1329 __unset_cpu_idle(vcpu); ··· 1950 1949 if (!online_vcpus) 1951 1950 return; 1952 1951 1953 - /* find idle VCPUs first, then round robin */ 1954 - sigcpu = find_first_bit(kvm->arch.idle_mask, online_vcpus); 1955 - if (sigcpu == online_vcpus) { 1956 - do { 1957 - sigcpu = kvm->arch.float_int.next_rr_cpu++; 1958 - kvm->arch.float_int.next_rr_cpu %= online_vcpus; 1959 - /* avoid endless loops if all vcpus are stopped */ 1960 - if (nr_tries++ >= online_vcpus) 1961 - return; 1962 - } while (is_vcpu_stopped(kvm_get_vcpu(kvm, sigcpu))); 1952 + for (sigcpu = kvm->arch.float_int.last_sleep_cpu; ; sigcpu++) { 1953 + sigcpu %= online_vcpus; 1954 + dst_vcpu = kvm_get_vcpu(kvm, sigcpu); 1955 + if (!is_vcpu_stopped(dst_vcpu)) 1956 + break; 1957 + /* avoid endless loops if all vcpus are stopped */ 1958 + if (nr_tries++ >= online_vcpus) 1959 + return; 1963 1960 } 1964 - dst_vcpu = kvm_get_vcpu(kvm, sigcpu); 1965 1961 1966 1962 /* make the VCPU drop out of the SIE, or wake it up if sleeping */ 1967 1963 switch (type) {
+11 -1
arch/s390/mm/gmap_helpers.c
··· 15 15 #include <linux/pagewalk.h> 16 16 #include <linux/ksm.h> 17 17 #include <asm/gmap_helpers.h> 18 + #include <asm/pgtable.h> 18 19 19 20 /** 20 21 * ptep_zap_swap_entry() - discard a swap entry. ··· 48 47 { 49 48 struct vm_area_struct *vma; 50 49 spinlock_t *ptl; 50 + pgste_t pgste; 51 51 pte_t *ptep; 52 52 53 53 mmap_assert_locked(mm); ··· 62 60 ptep = get_locked_pte(mm, vmaddr, &ptl); 63 61 if (unlikely(!ptep)) 64 62 return; 65 - if (pte_swap(*ptep)) 63 + if (pte_swap(*ptep)) { 64 + preempt_disable(); 65 + pgste = pgste_get_lock(ptep); 66 + 66 67 ptep_zap_swap_entry(mm, pte_to_swp_entry(*ptep)); 68 + pte_clear(mm, vmaddr, ptep); 69 + 70 + pgste_set_unlock(ptep, pgste); 71 + preempt_enable(); 72 + } 67 73 pte_unmap_unlock(ptep, ptl); 68 74 } 69 75 EXPORT_SYMBOL_GPL(gmap_helper_zap_one_page);
+1 -22
arch/s390/mm/pgtable.c
··· 24 24 #include <asm/tlbflush.h> 25 25 #include <asm/mmu_context.h> 26 26 #include <asm/page-states.h> 27 + #include <asm/pgtable.h> 27 28 #include <asm/machine.h> 28 29 29 30 pgprot_t pgprot_writecombine(pgprot_t prot) ··· 114 113 ptep_ipte_global(mm, addr, ptep, nodat); 115 114 atomic_dec(&mm->context.flush_count); 116 115 return old; 117 - } 118 - 119 - static inline pgste_t pgste_get_lock(pte_t *ptep) 120 - { 121 - unsigned long value = 0; 122 - #ifdef CONFIG_PGSTE 123 - unsigned long *ptr = (unsigned long *)(ptep + PTRS_PER_PTE); 124 - 125 - do { 126 - value = __atomic64_or_barrier(PGSTE_PCL_BIT, ptr); 127 - } while (value & PGSTE_PCL_BIT); 128 - value |= PGSTE_PCL_BIT; 129 - #endif 130 - return __pgste(value); 131 - } 132 - 133 - static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) 134 - { 135 - #ifdef CONFIG_PGSTE 136 - barrier(); 137 - WRITE_ONCE(*(unsigned long *)(ptep + PTRS_PER_PTE), pgste_val(pgste) & ~PGSTE_PCL_BIT); 138 - #endif 139 116 } 140 117 141 118 static inline pgste_t pgste_get(pte_t *ptep)