Re: [PATCH 24/32] KVM: s390: intercept the rpcit instruction

From: Matthew Rosato
Date: Tue Dec 14 2021 - 13:00:16 EST


On 12/14/21 12:04 PM, Pierre Morel wrote:


On 12/7/21 21:57, Matthew Rosato wrote:
For faster handling of PCI translation refreshes, intercept in KVM
and call the associated handler.

Signed-off-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx>
---
  arch/s390/kvm/pci.h  |  4 ++++
  arch/s390/kvm/priv.c | 41 +++++++++++++++++++++++++++++++++++++++++
  2 files changed, 45 insertions(+)

diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h
index d252a631b693..3f96eff432aa 100644
--- a/arch/s390/kvm/pci.h
+++ b/arch/s390/kvm/pci.h
@@ -18,6 +18,10 @@
  #define KVM_S390_PCI_DTSM_MASK 0x40
+#define KVM_S390_RPCIT_STAT_MASK 0xffffffff00ffffffUL
+#define KVM_S390_RPCIT_INS_RES (0x10 << 24)
+#define KVM_S390_RPCIT_ERR (0x28 << 24)

I

+
  struct zpci_gaite {
      unsigned int gisa;
      u8 gisc;
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 417154b314a6..768ae92ecc59 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -29,6 +29,7 @@
  #include <asm/ap.h>
  #include "gaccess.h"
  #include "kvm-s390.h"
+#include "pci.h"
  #include "trace.h"
  static int handle_ri(struct kvm_vcpu *vcpu)
@@ -335,6 +336,44 @@ static int handle_rrbe(struct kvm_vcpu *vcpu)
      return 0;
  }
+static int handle_rpcit(struct kvm_vcpu *vcpu)
+{
+    int reg1, reg2;
+    int rc;
+
+    if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+        return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+    kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+

I would prefer to take care of the interception immediately here

        fh = vcpu->run->s.regs.gprs[reg1] >> 32;
        if ((fh & aift.mdd) != 0)
                return -EOPNOTSUP

instead of doing it inside kvm_s390_pci_refresh_trans.
It would simplify in my opinion.

OK


+    rc = kvm_s390_pci_refresh_trans(vcpu, vcpu->run->s.regs.gprs[reg1],
+                    vcpu->run->s.regs.gprs[reg2],
+                    vcpu->run->s.regs.gprs[reg2+1]);
+


+    switch (rc) {
+    case 0:
+        kvm_s390_set_psw_cc(vcpu, 0);
+        break;
+    case -EOPNOTSUPP:
+        return -EOPNOTSUPP;
+    case -EINVAL:
+        kvm_s390_set_psw_cc(vcpu, 3);
+        break;
+    case -ENOMEM:
+        vcpu->run->s.regs.gprs[reg1] &= KVM_S390_RPCIT_STAT_MASK;
+        vcpu->run->s.regs.gprs[reg1] |= KVM_S390_RPCIT_INS_RES;
+        kvm_s390_set_psw_cc(vcpu, 1);
+        break;
+    default:
+        vcpu->run->s.regs.gprs[reg1] &= KVM_S390_RPCIT_STAT_MASK;
+        vcpu->run->s.regs.gprs[reg1] |= KVM_S390_RPCIT_ERR;

I think you should use the status reported by the hardware, reporting "Error recovery in progress" what ever the hardware error was does not seem right.


OK, this ties into your other comment about calling __rpcit() directly so we have a status to look at -- will look into it

+        kvm_s390_set_psw_cc(vcpu, 1);
+        break;
+    }

NIT: This switch above could be much more simple if you set CC after the switch.

We are setting 3 different CCs over 4 cases, so there's only 1 duplication in the switch, so I'm not sure how much simpler?

But anyway this might not be relevant if I change to call __rpcit() directly.


+
+    return 0;
+}
+
  #define SSKE_NQ 0x8
  #define SSKE_MR 0x4
  #define SSKE_MC 0x2
@@ -1275,6 +1314,8 @@ int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
          return handle_essa(vcpu);
      case 0xaf:
          return handle_pfmf(vcpu);
+    case 0xd3:
+        return handle_rpcit(vcpu);
      default:
          return -EOPNOTSUPP;
      }