diff mbox

[v4,5/5] mfd: cros_ec: wait for completion of commands that return IN_PROGRESS

Message ID 1411053538-17237-6-git-send-email-javier.martinez@collabora.co.uk (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Javier Martinez Canillas Sept. 18, 2014, 3:18 p.m. UTC
From: Andrew Bresticker <abrestic@chromium.org>

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: Andrew Bresticker <abrestic@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---

Changes since v3:
 - Fix us time and use raw values instead of a define. Suggested by Lee Jones.

Changes since v2:
 - Explain in the commit message from where the delay and retry values come from.
   Commented by Andrew Bresticker.
 - Move the needed definitions inside the if block. Suggested by Lee Jones.
 - Only check if result is EC_RES_IN_PROGRESS instead of checking also if ret is
   -EAGAIN since the former implies the later. Suggested by Lee Jones.
 - Use usleep_range() instead of msleep() since doesn't handle values between 1~20.
   Suggested by Lee Jones.

Changes since v1:
 - The *xfer() calls don't modify the passed cros_ec_command so there is
   no need to populate it inside the for loop. Suggested by Lee Jones.

 drivers/mfd/cros_ec.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

Comments

Lee Jones Sept. 29, 2014, 7:52 a.m. UTC | #1
On Thu, 18 Sep 2014, Javier Martinez Canillas wrote:

> From: Andrew Bresticker <abrestic@chromium.org>
> 
> 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: Andrew Bresticker <abrestic@chromium.org>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> 
> Changes since v3:
>  - Fix us time and use raw values instead of a define. Suggested by Lee Jones.
> 
> Changes since v2:
>  - Explain in the commit message from where the delay and retry values come from.
>    Commented by Andrew Bresticker.
>  - Move the needed definitions inside the if block. Suggested by Lee Jones.
>  - Only check if result is EC_RES_IN_PROGRESS instead of checking also if ret is
>    -EAGAIN since the former implies the later. Suggested by Lee Jones.
>  - Use usleep_range() instead of msleep() since doesn't handle values between 1~20.
>    Suggested by Lee Jones.
> 
> Changes since v1:
>  - The *xfer() calls don't modify the passed cros_ec_command so there is
>    no need to populate it inside the for loop. Suggested by Lee Jones.
> 
>  drivers/mfd/cros_ec.c | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)

Assuming that it's okay to return success even on failure,

... applied, thanks.

> diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
> index c53804a..fc0c81e 100644
> --- a/drivers/mfd/cros_ec.c
> +++ b/drivers/mfd/cros_ec.c
> @@ -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;
diff mbox

Patch

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index c53804a..fc0c81e 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -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;