]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Merge tag 'kvm-s390-next-7.1-1' of https://git.kernel.org/pub/scm/linux/kernel/git...
authorPaolo Bonzini <pbonzini@redhat.com>
Mon, 13 Apr 2026 17:01:15 +0000 (19:01 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 13 Apr 2026 17:01:15 +0000 (19:01 +0200)
- ESA nesting support
- 4k memslots
- LPSW/E fix

1  2 
Documentation/virt/kvm/api.rst
arch/s390/include/asm/kvm_host.h
arch/s390/kvm/dat.h
arch/s390/kvm/gaccess.c
arch/s390/kvm/gmap.c
arch/s390/kvm/gmap.h
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/vsie.c
include/uapi/linux/kvm.h
tools/testing/selftests/kvm/Makefile.kvm

Simple merge
Simple merge
Simple merge
Simple merge
index 0111d31e038656da5672bd7dd88fce71cd89f7ad,e3c1b070a11dc3fdb677e7087a090c9843a3f98f..3c26e35af0ef7c4d97008e460b77a038ef0051bf
@@@ -623,78 -619,48 +624,97 @@@ static inline bool gmap_2g_allowed(stru
        return false;
  }
  
- static inline bool gmap_1m_allowed(struct gmap *gmap, gfn_t gfn)
+ /**
+  * gmap_1m_allowed() - Check whether a 1M hugepage is allowed.
+  * @gmap: The gmap of the guest.
+  * @f: Describes the fault that is being resolved.
+  * @slot: The memslot the faulting address belongs to.
+  *
+  * The function checks whether the GMAP_FLAG_ALLOW_HPAGE_1M flag is set for
+  * @gmap, whether the offset of the address in the 1M virtual frame is the
+  * same as the offset in the physical 1M frame, and finally whether the whole
+  * 1M page would fit in the given memslot.
+  *
+  * Return: true if a 1M hugepage is allowed to back the faulting address, false
+  *         otherwise.
+  */
+ static inline bool gmap_1m_allowed(struct gmap *gmap, struct guest_fault *f,
+                                  struct kvm_memory_slot *slot)
  {
-       return test_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &gmap->flags);
+       return test_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &gmap->flags) &&
+              !((f->gfn ^ f->pfn) & ~_SEGMENT_FR_MASK) &&
+              slot->base_gfn <= ALIGN_DOWN(f->gfn, _PAGES_PER_SEGMENT) &&
+              slot->base_gfn + slot->npages >= ALIGN(f->gfn + 1, _PAGES_PER_SEGMENT);
  }
  
- int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *f)
 +static int _gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, int level,
 +                    struct guest_fault *f)
 +{
 +      union crste oldval, newval;
 +      union pte newpte, oldpte;
 +      union pgste pgste;
 +      int rc = 0;
 +
 +      rc = dat_entry_walk(mc, f->gfn, gmap->asce, DAT_WALK_ALLOC_CONTINUE, level,
 +                          &f->crstep, &f->ptep);
 +      if (rc == -ENOMEM)
 +              return rc;
 +      if (KVM_BUG_ON(rc == -EINVAL, gmap->kvm))
 +              return rc;
 +      if (rc)
 +              return -EAGAIN;
 +      if (KVM_BUG_ON(get_level(f->crstep, f->ptep) > level, gmap->kvm))
 +              return -EINVAL;
 +
 +      if (f->ptep) {
 +              pgste = pgste_get_lock(f->ptep);
 +              oldpte = *f->ptep;
 +              newpte = _pte(f->pfn, f->writable, f->write_attempt | oldpte.s.d, !f->page);
 +              newpte.s.sd = oldpte.s.sd;
 +              oldpte.s.sd = 0;
 +              if (oldpte.val == _PTE_EMPTY.val || oldpte.h.pfra == f->pfn) {
 +                      pgste = gmap_ptep_xchg(gmap, f->ptep, newpte, pgste, f->gfn);
 +                      if (f->callback)
 +                              f->callback(f);
 +              } else {
 +                      rc = -EAGAIN;
 +              }
 +              pgste_set_unlock(f->ptep, pgste);
 +      } else {
 +              do {
 +                      oldval = READ_ONCE(*f->crstep);
 +                      newval = _crste_fc1(f->pfn, oldval.h.tt, f->writable,
 +                                          f->write_attempt | oldval.s.fc1.d);
 +                      newval.s.fc1.s = !f->page;
 +                      newval.s.fc1.sd = oldval.s.fc1.sd;
 +                      if (oldval.val != _CRSTE_EMPTY(oldval.h.tt).val &&
 +                          crste_origin_large(oldval) != crste_origin_large(newval))
 +                              return -EAGAIN;
 +              } while (!gmap_crstep_xchg_atomic(gmap, f->crstep, oldval, newval, f->gfn));
 +              if (f->callback)
 +                      f->callback(f);
 +      }
 +
 +      return rc;
 +}
 +
+ int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *f,
+             struct kvm_memory_slot *slot)
  {
        unsigned int order;
 -      int rc, level;
 +      int level;
  
        lockdep_assert_held(&gmap->kvm->mmu_lock);
  
        level = TABLE_TYPE_PAGE_TABLE;
        if (f->page) {
                order = folio_order(page_folio(f->page));
-               if (order >= get_order(_REGION3_SIZE) && gmap_2g_allowed(gmap, f->gfn))
+               if (order >= get_order(_REGION3_SIZE) && gmap_2g_allowed(gmap, f, slot))
                        level = TABLE_TYPE_REGION3;
-               else if (order >= get_order(_SEGMENT_SIZE) && gmap_1m_allowed(gmap, f->gfn))
+               else if (order >= get_order(_SEGMENT_SIZE) && gmap_1m_allowed(gmap, f, slot))
                        level = TABLE_TYPE_SEGMENT;
        }
 -      rc = dat_link(mc, gmap->asce, level, uses_skeys(gmap), f);
 -      KVM_BUG_ON(rc == -EINVAL, gmap->kvm);
 -      return rc;
 +      return _gmap_link(mc, gmap, level, f);
  }
  
  static int gmap_ucas_map_one(struct kvm_s390_mmu_cache *mc, struct gmap *gmap,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index e79561deffbf20a470e2f3e9c0b230e234a2108e,057f17d6b896d6f960bfd3c36decaed6a98201cc..9118a5a51b89fdc696976eff0dc5dd1b57bd6b79
@@@ -210,7 -203,7 +208,8 @@@ TEST_GEN_PROGS_s390 += s390/ucontrol_te
  TEST_GEN_PROGS_s390 += s390/user_operexec
  TEST_GEN_PROGS_s390 += s390/keyop
  TEST_GEN_PROGS_s390 += rseq_test
 +TEST_GEN_PROGS_s390 += s390/irq_routing
+ TEST_GEN_PROGS_s390 += mmu_stress_test
  
  TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON)
  TEST_GEN_PROGS_riscv += riscv/sbi_pmu_test