Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d86c21fd authored by Andrew Bresticker's avatar Andrew Bresticker Committed by Lee Jones
Browse files

mfd: cros_ec: wait for completion of commands that return IN_PROGRESS



When an EC command returns EC_RES_IN_PROGRESS, we need to query
the state of the EC until it indicates that it is no longer busy.
Do this in cros_ec_cmd_xfer() under the EC's mutex so that other
commands (e.g. keyboard, I2C passtru) aren't issued to the EC while
it is working on the in-progress command.

The 10 milliseconds delay and the number of retries are the values
that were used by the flashrom tool when retrying commands.

Signed-off-by: default avatarAndrew Bresticker <abrestic@chromium.org>
Reviewed-by: default avatarSimon Glass <sjg@chromium.org>
Signed-off-by: default avatarJavier Martinez Canillas <javier.martinez@collabora.co.uk>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
parent 97720706
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@
#include <linux/mfd/core.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
#include <linux/delay.h>

#define EC_COMMAND_RETRIES	50

int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
		       struct cros_ec_command *msg)
@@ -69,6 +72,36 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,

	mutex_lock(&ec_dev->lock);
	ret = ec_dev->cmd_xfer(ec_dev, msg);
	if (msg->result == EC_RES_IN_PROGRESS) {
		int i;
		struct cros_ec_command status_msg;
		struct ec_response_get_comms_status status;

		status_msg.version = 0;
		status_msg.command = EC_CMD_GET_COMMS_STATUS;
		status_msg.outdata = NULL;
		status_msg.outsize = 0;
		status_msg.indata = (uint8_t *)&status;
		status_msg.insize = sizeof(status);

		/*
		 * Query the EC's status until it's no longer busy or
		 * we encounter an error.
		 */
		for (i = 0; i < EC_COMMAND_RETRIES; i++) {
			usleep_range(10000, 11000);

			ret = ec_dev->cmd_xfer(ec_dev, &status_msg);
			if (ret < 0)
				break;

			msg->result = status_msg.result;
			if (status_msg.result != EC_RES_SUCCESS)
				break;
			if (!(status.flags & EC_COMMS_STATUS_PROCESSING))
				break;
		}
	}
	mutex_unlock(&ec_dev->lock);

	return ret;