Commit d9213319 authored by Nathan Lynch's avatar Nathan Lynch Committed by Michael Ellerman
Browse files

powerpc/pseries/mobility: extract VASI session polling logic



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: default avatarNathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20201207215200.1785968-12-nathanl@linux.ibm.com
parent c3ae9781
Loading
Loading
Loading
Loading
+64 −5
Original line number Diff line number Diff line
@@ -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;