pd: Add timeout for HC flash commands.

For flash commands add timeout so if VDM doesn't return properly host
can receive error message.

Note, for flash erase its performed by page at a cost of 20-40ms
according to datasheet. For hoho/dingdong that leaves maximum erase
time at 40ms * 32 =< 1280ms which is above the host command timeout.

Increasing the host command delay (i2c bus pending) is not an option
and since the erase will complete and subsequent erases will be much
faster do to early out in physical_flash_erase this solution should be
acceptable.

Future CLs could alternatively push the burden of command latency to
host altogether and return EC_RES_SUCCESS in similar fashion to reboot
command.

Signed-off-by: Todd Broch <tbroch@chromium.org>

BRANCH=samus
BUG=chrome-os-partner:33947
TEST=manual, if VDM doesn't return by timeout HC command is properly returned
EC_RES_TIMEOUT error code.

Change-Id: I33c515200c2999dd97fdd690a7e900c5548b2d47
Reviewed-on: https://chromium-review.googlesource.com/238290
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Tested-by: Todd Broch <tbroch@chromium.org>
Commit-Queue: Todd Broch <tbroch@chromium.org>
This commit is contained in:
Todd Broch
2015-01-02 20:30:21 -08:00
committed by ChromeOS Commit Bot
parent c0f64b13e9
commit 5ef45ad19e
3 changed files with 31 additions and 17 deletions

View File

@@ -11,15 +11,13 @@
#include "i2c.h"
#include "task.h"
#include "timer.h"
#include "usb_pd.h"
#include "util.h"
/* Console output macros */
#define CPUTS(outstr) cputs(CC_HOSTCMD, outstr)
#define CPRINTF(format, args...) cprintf(CC_HOSTCMD, format, ## args)
/* Host command timeout */
#define HOST_COMMAND_TIMEOUT_US SECOND
/* Number of attempts for each PD host command */
#define PD_HOST_COMMAND_ATTEMPTS 3
@@ -81,7 +79,7 @@ static int pd_host_command_internal(int command, int version,
* length.
*/
i2c_lock(I2C_PORT_PD_MCU, 1);
i2c_set_timeout(I2C_PORT_PD_MCU, HOST_COMMAND_TIMEOUT_US);
i2c_set_timeout(I2C_PORT_PD_MCU, PD_HOST_COMMAND_TIMEOUT_US);
ret = i2c_xfer(I2C_PORT_PD_MCU, CONFIG_USB_PD_I2C_SLAVE_ADDR,
&req_buf[0], outsize + sizeof(rq) + 1, &resp_buf[0],
2, I2C_XFER_START);

View File

@@ -3053,6 +3053,7 @@ static int hc_remote_flash(struct host_cmd_handler_args *args)
int port = p->port;
const uint32_t *data = &(p->size) + 1;
int i, size;
timestamp_t timeout;
if (p->size + sizeof(*p) > args->params_size)
return EC_RES_INVALID_PARAM;
@@ -3073,23 +3074,24 @@ static int hc_remote_flash(struct host_cmd_handler_args *args)
pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_REBOOT, NULL, 0);
/* Delay to give time for device to reboot */
usleep(900 * MSEC);
usleep(PD_HOST_COMMAND_TIMEOUT_US - 100*MSEC);
return EC_RES_SUCCESS;
case USB_PD_FW_FLASH_ERASE:
pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_FLASH_ERASE, NULL, 0);
/* Wait until VDM is done */
while (pd[port].vdm_state > 0)
task_wait_event(100*MSEC);
/*
* TODO: Note, page erase for 2K is 20-40msec while host command
* timeout is 1sec so this can't be longer. In practice,
* for 32 pages, its passed. Better way to implement may be to
* push burden to HOST to manage latency.
*/
timeout.val = get_time().val +
PD_HOST_COMMAND_TIMEOUT_US - 100*MSEC;
break;
case USB_PD_FW_ERASE_SIG:
pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_ERASE_SIG, NULL, 0);
/* Wait until VDM is done */
while (pd[port].vdm_state > 0)
task_wait_event(100*MSEC);
timeout.val = get_time().val + 500*MSEC;
break;
case USB_PD_FW_FLASH_WRITE:
@@ -3101,22 +3103,33 @@ static int hc_remote_flash(struct host_cmd_handler_args *args)
for (i = 0; i < size; i += VDO_MAX_SIZE - 1) {
pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_FLASH_WRITE,
data + i, MIN(size - i, VDO_MAX_SIZE - 1));
timeout.val = get_time().val + 500*MSEC;
/* Wait until VDM is done */
while (pd[port].vdm_state > 0)
while ((pd[port].vdm_state > 0) &&
(get_time().val < timeout.val))
task_wait_event(10*MSEC);
if (pd[port].vdm_state > 0)
return EC_RES_TIMEOUT;
}
break;
return EC_RES_SUCCESS;
default:
return EC_RES_INVALID_PARAM;
break;
}
/* Wait until VDM is done or timeout */
while ((pd[port].vdm_state > 0) && (get_time().val < timeout.val))
task_wait_event(50*MSEC);
if (pd[port].vdm_state < 0)
return EC_RES_ERROR;
else
return EC_RES_SUCCESS;
if (pd[port].vdm_state > 0)
return EC_RES_TIMEOUT;
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_USB_PD_FW_UPDATE,
hc_remote_flash,

View File

@@ -10,6 +10,9 @@
#include "common.h"
/* PD Host command timeout */
#define PD_HOST_COMMAND_TIMEOUT_US SECOND
enum pd_errors {
PD_ERR_INVAL = -1, /* Invalid packet */
PD_ERR_HARD_RESET = -2, /* Got a Hard-Reset packet */