Improve the timeout when running on non-Google EC boards.

The udelay() has big overhead so that repeating calling leads big errors
(expect 1 sec of timeout, but actually 12 secs of timeout).

So, the improvement is to double the udelay count when BUSY bit is set.

Even better, if we can check the I/O port content before really running
the EC command, it can save more time.

BUG=chrome-os-partner:10003
TEST=tested on link, alex, zgb, lumpy, stumpy and mario.
Only mario takes 1 second to timeout.
Others stop when checking ports (takes around 0.01 second).

Change-Id: I96c6d8cbe6226d05428a2ab126815e934942f5a9
Signed-off-by: Louis Yung-Chieh Lo <yjlou@chromium.org>
This commit is contained in:
Louis Yung-Chieh Lo
2012-05-29 18:03:42 +08:00
parent 8bb9091f2e
commit 2835e5594e

View File

@@ -6,19 +6,42 @@
#include <stdint.h>
#include <stdio.h>
#include <sys/io.h>
#include <sys/param.h>
#include <unistd.h>
#include "comm-host.h"
#include "ec_commands.h"
#define INITIAL_UDELAY 10 /* 10 us */
#define MAXIMUM_UDELAY 10000 /* 10 ms */
int comm_init(void)
{
int i;
int byte = 0xff;
/* Request I/O privilege */
if (iopl(3) < 0) {
perror("Error getting I/O privilege");
return -3;
}
/* Test if the I/O port has been configured for GEC.
* If they all are 0xff, then very possible you cannot access GEC. */
byte &= inb(EC_LPC_ADDR_USER_CMD);
byte &= inb(EC_LPC_ADDR_USER_DATA);
for (i = 0; i < EC_FLASH_SIZE_MAX /* big enough */; ++i)
byte &= inb(EC_LPC_ADDR_USER_PARAM + i);
if (byte == 0xff) {
fprintf(stderr, "Port 0x%x,0x%x,0x%x-0x%x are all 0xFF.\n",
EC_LPC_ADDR_USER_CMD, EC_LPC_ADDR_USER_DATA,
EC_LPC_ADDR_USER_PARAM,
EC_LPC_ADDR_USER_PARAM + EC_FLASH_SIZE_MAX - 1);
fprintf(stderr, "Very likely this board doesn't have GEC.\n");
return -4;
}
return 0;
}
@@ -28,10 +51,21 @@ int comm_init(void)
static int wait_for_ec(int status_addr, int timeout_usec)
{
int i;
for (i = 0; i < timeout_usec; i += 10) {
usleep(10); /* Delay first, in case we just sent a command */
int delay = INITIAL_UDELAY;
for (i = 0; i < timeout_usec; i += delay) {
/* Delay first, in case we just sent out a command but
* the EC hasn't raise the busy flag. However, I think
* this doesn't happen since the LPC commands are executed
* in order and the busy flag is set by hardware.
* TODO: move this delay after inb(status). */
usleep(MIN(delay, timeout_usec - i));
if (!(inb(status_addr) & EC_LPC_STATUS_BUSY_MASK))
return 0;
/* Increase the delay interval */
delay = MIN(delay * 2, MAXIMUM_UDELAY);
}
return -1; /* Timeout */
}