As we are shadowing the SCA we need to add and remove the pointers to the shadowed control blocks and sca entries whenever the mcn / processors in the configuration changes. It is not expected that the mcn changes frequently for an already running guest-3 configuration. So we can simply fully re-init the ssca whenever the mcn changes. To detect the mcn change we store the expected mcn in the struct vsie_sca when running _shadow_sca(). Signed-off-by: Christoph Schlameuss --- arch/s390/kvm/vsie.c | 68 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 154772278d0a..6088a9c31564 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -2052,6 +2052,43 @@ static struct vsie_page *get_vsie_page_cpu_nr(struct kvm_vcpu *vcpu, struct vsie return vsie_page; } +/* + * Copy the mcn from the osca to the vsie_sca to be able to detect mcn changes later on. + * + * @vsie_sca: vsie_sca to copy mcn to. + * @sca: Pointer to a struct bsca_block or struct esca_block to read from. + */ +static void sca_mcn_copy(struct vsie_sca *vsie_sca, void *sca) +{ + int offset = offsetof(struct bsca_block, mcn); + int size = sizeof(unsigned long); + + if (test_bit(VSIE_SCA_ESCA, &vsie_sca->flags)) { + offset = offsetof(struct esca_block, mcn); + size = size * 4; + } + memcpy(&vsie_sca->mcn, sca + offset, size); +} + +/* + * Compare the mcn from the given sca to the vsie_sca to be able to detect mcn changes. + * + * @vsie_sca: vsie_sca to compare mcn to. + * @sca: Pointer to a struct bsca_block or struct esca_block to compare to. + */ +static bool sca_mcn_equals(struct vsie_sca *vsie_sca, void *sca) +{ + int offset = offsetof(struct bsca_block, mcn); + int size = sizeof(unsigned long); + + if (test_bit(VSIE_SCA_ESCA, &vsie_sca->flags)) { + size = size * 4; + offset = offsetof(struct esca_block, mcn); + } + + return !memcmp(&vsie_sca->mcn, sca + offset, size); +} + static void vsie_sca_update(struct vsie_sca *vsie_sca, unsigned int cpu_nr, struct vsie_page *vsie_page_n, hpa_t sca_o_entry_hpa) { @@ -2071,18 +2108,16 @@ static int _shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct vsie_page *vsie_page_n; hpa_t sca_o_entry_hpa; hva_t sca_o_entry_hva; - unsigned long *mcn; gpa_t scb_o_gpa; int rc; if (is_esca) - mcn = phys_to_virt(sca_o_hpa(vsie_sca)) + offsetof(struct esca_block, mcn); - else - mcn = phys_to_virt(sca_o_hpa(vsie_sca)) + offsetof(struct bsca_block, mcn); + __set_bit(VSIE_SCA_ESCA, &vsie_sca->flags); + sca_mcn_copy(vsie_sca, phys_to_virt(sca_o_hpa(vsie_sca))); /* pin and make shadow for ALL scb in the sca */ cpu_slots = is_esca ? KVM_S390_MAX_VSIE_VCPUS : KVM_S390_BSCA_CPU_SLOTS; - for_each_set_bit_inv(cpu_nr, mcn, cpu_slots) { + for_each_set_bit_inv(cpu_nr, (unsigned long *)&vsie_sca->mcn, cpu_slots) { rc = get_sca_entry_addr(vcpu->kvm, vsie_sca, cpu_nr, NULL, &sca_o_entry_hpa); if (rc) goto err; @@ -2118,23 +2153,36 @@ static int _shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, return 0; err: - for_each_set_bit_inv(cpu_nr, mcn, cpu_slots) { + vsie_sca->ssca.osca = 0; + for_each_set_bit_inv(cpu_nr, (unsigned long *)&vsie_sca->mcn, cpu_slots) { vsie_sca->ssca.cpu[cpu_nr].ssda = 0; vsie_sca->ssca.cpu[cpu_nr].ossea = 0; } return rc; } +static bool config_changed(struct vsie_page *vsie_page, struct vsie_sca *vsie_sca) +{ + bool changed = !vsie_sca->ssca.osca; + + changed = changed || sie_uses_esca(vsie_page->scb_o) != + test_bit(VSIE_SCA_ESCA, &vsie_sca->flags); + return changed || !sca_mcn_equals(vsie_sca, phys_to_virt(sca_o_hpa(vsie_sca))); +} + /* Shadow or reshadow the SCA on VSIE enter. */ static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct vsie_sca *vsie_sca) { - int rc = 0; + scoped_guard(rwsem_read, &vcpu->kvm->arch.vsie.vsie_sca_lock) { + if (!config_changed(vsie_page, vsie_sca)) + return 0; + } guard(rwsem_write)(&vcpu->kvm->arch.vsie.vsie_sca_lock); - if (!vsie_sca->ssca.osca) - rc = _shadow_sca(vcpu, vsie_page, vsie_sca); + if (!config_changed(vsie_page, vsie_sca)) + return 0; - return rc; + return _shadow_sca(vcpu, vsie_page, vsie_sca); } int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu) -- 2.55.0