Commit 25794e30 authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman
Browse files

usb: typec: ucsi: Rework ppm_lock handling



The ppm_lock really only needs to be hold during 2 functions:
ucsi_reset_ppm() and ucsi_run_command().

Push the taking of the lock down into these 2 functions, renaming
ucsi_run_command() to ucsi_send_command() which was an existing
wrapper already taking the lock for its callers.

This simplifies things for the callers and removes the difference
between ucsi_send_command() and ucsi_run_command() which has led
to various locking bugs in the past.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Acked-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20200809141904.4317-4-hdegoede@redhat.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7e90057f
Loading
Loading
Loading
Loading
+22 −34
Original line number Diff line number Diff line
@@ -146,42 +146,33 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd)
	return UCSI_CCI_LENGTH(cci);
}

static int ucsi_run_command(struct ucsi *ucsi, u64 command,
int ucsi_send_command(struct ucsi *ucsi, u64 command,
		      void *data, size_t size)
{
	u8 length;
	int ret;

	WARN_ON(!mutex_is_locked(&ucsi->ppm_lock));
	mutex_lock(&ucsi->ppm_lock);

	ret = ucsi_exec_command(ucsi, command);
	if (ret < 0)
		return ret;
		goto out;

	length = ret;

	if (data) {
		ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size);
		if (ret)
			return ret;
			goto out;
	}

	ret = ucsi_acknowledge_command(ucsi);
	if (ret)
		return ret;

	return length;
}

int ucsi_send_command(struct ucsi *ucsi, u64 command,
		      void *retval, size_t size)
{
	int ret;
		goto out;

	mutex_lock(&ucsi->ppm_lock);
	ret = ucsi_run_command(ucsi, command, retval, size);
	ret = length;
out:
	mutex_unlock(&ucsi->ppm_lock);

	return ret;
}
EXPORT_SYMBOL_GPL(ucsi_send_command);
@@ -738,20 +729,24 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
	u32 cci;
	int ret;

	mutex_lock(&ucsi->ppm_lock);

	ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
				     sizeof(command));
	if (ret < 0)
		return ret;
		goto out;

	tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);

	do {
		if (time_is_before_jiffies(tmo))
			return -ETIMEDOUT;
		if (time_is_before_jiffies(tmo)) {
			ret = -ETIMEDOUT;
			goto out;
		}

		ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci));
		if (ret)
			return ret;
			goto out;

		/* If the PPM is still doing something else, reset it again. */
		if (cci & ~UCSI_CCI_RESET_COMPLETE) {
@@ -759,13 +754,15 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
						     &command,
						     sizeof(command));
			if (ret < 0)
				return ret;
				goto out;
		}

		msleep(20);
	} while (!(cci & UCSI_CCI_RESET_COMPLETE));

	return 0;
out:
	mutex_unlock(&ucsi->ppm_lock);
	return ret;
}

static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
@@ -777,9 +774,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
		u64 c;

		/* PPM most likely stopped responding. Resetting everything. */
		mutex_lock(&con->ucsi->ppm_lock);
		ucsi_reset_ppm(con->ucsi);
		mutex_unlock(&con->ucsi->ppm_lock);

		c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy;
		ucsi_send_command(con->ucsi, c, NULL, 0);
@@ -1010,8 +1005,6 @@ static int ucsi_init(struct ucsi *ucsi)
	int ret;
	int i;

	mutex_lock(&ucsi->ppm_lock);

	/* Reset the PPM */
	ret = ucsi_reset_ppm(ucsi);
	if (ret) {
@@ -1022,13 +1015,13 @@ static int ucsi_init(struct ucsi *ucsi)
	/* Enable basic notifications */
	ucsi->ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
	command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy;
	ret = ucsi_run_command(ucsi, command, NULL, 0);
	ret = ucsi_send_command(ucsi, command, NULL, 0);
	if (ret < 0)
		goto err_reset;

	/* Get PPM capabilities */
	command = UCSI_GET_CAPABILITY;
	ret = ucsi_run_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap));
	ret = ucsi_send_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap));
	if (ret < 0)
		goto err_reset;

@@ -1045,8 +1038,6 @@ static int ucsi_init(struct ucsi *ucsi)
		goto err_reset;
	}

	mutex_unlock(&ucsi->ppm_lock);

	/* Register all connectors */
	for (i = 0; i < ucsi->cap.num_connectors; i++) {
		ret = ucsi_register_port(ucsi, i);
@@ -1072,12 +1063,9 @@ err_unregister:
		con->port = NULL;
	}

	mutex_lock(&ucsi->ppm_lock);
err_reset:
	ucsi_reset_ppm(ucsi);
err:
	mutex_unlock(&ucsi->ppm_lock);

	return ret;
}