]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
powerpc/pseries/mobility: extract VASI session polling logic
authorNathan Lynch <nathanl@linux.ibm.com>
Mon, 7 Dec 2020 21:51:43 +0000 (15:51 -0600)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 8 Dec 2020 10:40:56 +0000 (21:40 +1100)
The behavior of rtas_ibm_suspend_me_unsafe() is to return -EAGAIN to
the caller until the specified VASI suspend session state makes the
transition from H_VASI_ENABLED to H_VASI_SUSPENDING. In the interest
of separating concerns to prepare for a new implementation of the
join/suspend sequence, extract VASI session polling logic into a
couple of local functions. Waiting for the session state to reach
H_VASI_SUSPENDING before calling rtas_ibm_suspend_me_unsafe() ensures
that we will never get an EAGAIN result necessitating a retry. No
user-visible change in behavior is intended.

Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20201207215200.1785968-12-nathanl@linux.ibm.com
arch/powerpc/platforms/pseries/mobility.c

index 01ac7c03558eb1a43bdfc2bb0def3083feaddf9f..573ed48b43d866c6e9726a8be54b44ff7298ea6d 100644 (file)
@@ -345,6 +345,66 @@ void post_mobility_fixup(void)
        return;
 }
 
+static int poll_vasi_state(u64 handle, unsigned long *res)
+{
+       unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+       long hvrc;
+       int ret;
+
+       hvrc = plpar_hcall(H_VASI_STATE, retbuf, handle);
+       switch (hvrc) {
+       case H_SUCCESS:
+               ret = 0;
+               *res = retbuf[0];
+               break;
+       case H_PARAMETER:
+               ret = -EINVAL;
+               break;
+       case H_FUNCTION:
+               ret = -EOPNOTSUPP;
+               break;
+       case H_HARDWARE:
+       default:
+               pr_err("unexpected H_VASI_STATE result %ld\n", hvrc);
+               ret = -EIO;
+               break;
+       }
+       return ret;
+}
+
+static int wait_for_vasi_session_suspending(u64 handle)
+{
+       unsigned long state;
+       int ret;
+
+       /*
+        * Wait for transition from H_VASI_ENABLED to
+        * H_VASI_SUSPENDING. Treat anything else as an error.
+        */
+       while (true) {
+               ret = poll_vasi_state(handle, &state);
+
+               if (ret != 0 || state == H_VASI_SUSPENDING) {
+                       break;
+               } else if (state == H_VASI_ENABLED) {
+                       ssleep(1);
+               } else {
+                       pr_err("unexpected H_VASI_STATE result %lu\n", state);
+                       ret = -EIO;
+                       break;
+               }
+       }
+
+       /*
+        * Proceed even if H_VASI_STATE is unavailable. If H_JOIN or
+        * ibm,suspend-me are also unimplemented, we'll recover then.
+        */
+       if (ret == -EOPNOTSUPP)
+               ret = 0;
+
+       return ret;
+}
+
 static ssize_t migration_store(struct class *class,
                               struct class_attribute *attr, const char *buf,
                               size_t count)
@@ -356,12 +416,11 @@ static ssize_t migration_store(struct class *class,
        if (rc)
                return rc;
 
-       do {
-               rc = rtas_ibm_suspend_me_unsafe(streamid);
-               if (rc == -EAGAIN)
-                       ssleep(1);
-       } while (rc == -EAGAIN);
+       rc = wait_for_vasi_session_suspending(streamid);
+       if (rc)
+               return rc;
 
+       rc = rtas_ibm_suspend_me_unsafe(streamid);
        if (rc)
                return rc;