]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: s390: Add capability to support 2G hugepages
authorClaudio Imbrenda <imbrenda@linux.ibm.com>
Tue, 9 Jun 2026 15:09:28 +0000 (17:09 +0200)
committerClaudio Imbrenda <imbrenda@linux.ibm.com>
Tue, 9 Jun 2026 15:30:57 +0000 (17:30 +0200)
Add KVM_CAP_S390_HPAGE_2G to signal to userspace that 2G hugepages may
be used to back the guest; restrictions apply similar to 1M hugepages.

Enable the (for now still ignored) GMAP_FLAG_ALLOW_HPAGE_2G flag for
the guest gmap, and propagate / disable it as necessary.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260609150930.665370-3-imbrenda@linux.ibm.com>

arch/s390/kvm/gmap.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/pv.c
include/uapi/linux/kvm.h

index fe138d17caaf3a4896f83c5bc5076681068f9d89..f8bd6c135e3c2eb490f0057b49a8fd20c8b8e0ad 100644 (file)
@@ -105,6 +105,11 @@ static void gmap_add_child(struct gmap *parent, struct gmap *child)
        else
                clear_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &child->flags);
 
+       if (test_bit(GMAP_FLAG_ALLOW_HPAGE_2G, &parent->flags))
+               set_bit(GMAP_FLAG_ALLOW_HPAGE_2G, &child->flags);
+       else
+               clear_bit(GMAP_FLAG_ALLOW_HPAGE_2G, &child->flags);
+
        if (kvm_is_ucontrol(parent->kvm))
                clear_bit(GMAP_FLAG_OWNS_PAGETABLES, &child->flags);
        list_add(&child->list, &parent->children);
index abc7941d7bb46cdc68c4201814a34aa160111530..6de36421548c2b2ae1b5acfa1ed1d75d83610a2f 100644 (file)
@@ -646,6 +646,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                if (hpage && !(kvm && kvm_is_ucontrol(kvm)))
                        r = 1;
                break;
+       case KVM_CAP_S390_HPAGE_2G:
+               r = 0;
+               if (hpage_2g && !(kvm && kvm_is_ucontrol(kvm)))
+                       r = 1;
+               break;
        case KVM_CAP_S390_MEM_OP:
                r = MEM_OP_MAX_SIZE;
                break;
@@ -902,6 +907,27 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                VM_EVENT(kvm, 3, "ENABLE: CAP_S390_HPAGE %s",
                         r ? "(not available)" : "(success)");
                break;
+       case KVM_CAP_S390_HPAGE_2G:
+               mutex_lock(&kvm->lock);
+               if (kvm->created_vcpus) {
+                       r = -EBUSY;
+               } else if (!hpage_2g || kvm->arch.use_cmma || kvm_is_ucontrol(kvm)) {
+                       r = -EINVAL;
+               } else {
+                       r = 0;
+                       set_bit(GMAP_FLAG_ALLOW_HPAGE_2G, &kvm->arch.gmap->flags);
+                       /*
+                        * We might have to create fake 4k page
+                        * tables. To avoid that the hardware works on
+                        * stale PGSTEs, we emulate these instructions.
+                        */
+                       kvm->arch.use_skf = 0;
+                       kvm->arch.use_pfmfi = 0;
+               }
+               mutex_unlock(&kvm->lock);
+               VM_EVENT(kvm, 3, "ENABLE: CAP_S390_HPAGE_2G %s",
+                        r ? "(not available)" : "(success)");
+               break;
        case KVM_CAP_S390_USER_STSI:
                VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_STSI");
                kvm->arch.user_stsi = 1;
index c2dafd812a3b2a18e3050a96a3c7a924edf7ca06..b9a23df96f7d06fe182d42a60431480b4bb2fd4b 100644 (file)
@@ -721,7 +721,10 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc)
        uvcb.flags.ap_allow_instr = kvm->arch.model.uv_feat_guest.ap;
        uvcb.flags.ap_instr_intr = kvm->arch.model.uv_feat_guest.ap_intr;
 
-       clear_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &kvm->arch.gmap->flags);
+       scoped_guard(write_lock, &kvm->mmu_lock) {
+               clear_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &kvm->arch.gmap->flags);
+               clear_bit(GMAP_FLAG_ALLOW_HPAGE_2G, &kvm->arch.gmap->flags);
+       }
        gmap_split_huge_pages(kvm->arch.gmap);
 
        cc = uv_call_sched(0, (u64)&uvcb);
index 6c8afa2047bf33a81f5eb469e370d2ece6f21a09..419011097fa8e2c6d2a7181fd7845621e9bd3df0 100644 (file)
@@ -996,6 +996,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_S390_USER_OPEREXEC 246
 #define KVM_CAP_S390_KEYOP 247
 #define KVM_CAP_S390_VSIE_ESAMODE 248
+#define KVM_CAP_S390_HPAGE_2G 249
 
 struct kvm_irq_routing_irqchip {
        __u32 irqchip;