Add persistent host storage in EC EEPROM

Signed-off-by: Randall Spangler <rspangler@chromium.org>

BUG=chrome-os-partner:8247
TEST=manual

from root shell on host:
  ectool pstoreinfo   --> should print PstoreSize 1024 AccessSize 4
  echo testing 1 2 3 4 > /tmp/infile
  ectool pstorewrite 8 /tmp/infile
  ectool pstoreread 8 /tmp/outfile
  diff /tmp/infile /tmp/outfile

Change-Id: I565e580307584f7def36c5e53d360c1a897d67d2
This commit is contained in:
Randall Spangler
2012-02-28 12:25:44 -08:00
parent b4edad6922
commit e84fc7b110
8 changed files with 388 additions and 54 deletions

View File

@@ -11,6 +11,7 @@
/* Optional features */
#define CONFIG_PECI
#define CONFIG_TMP006
#define CONFIG_PSTORE
/* 66.667 Mhz clock frequency */
#define CPU_CLOCK 66666667

View File

@@ -14,6 +14,7 @@ common-$(CONFIG_TASK_I8042CMD)+=i8042.o keyboard.o
common-$(CONFIG_TASK_X86POWER)+=x86_power.o
common-$(CONFIG_TASK_GAIAPOWER)+=gaia_power.o
common-$(CONFIG_FLASH)+=flash_commands.o
common-$(CONFIG_PSTORE)+=pstore_commands.o
common-$(CONFIG_PWM)+=pwm_commands.o
common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o
common-$(CONFIG_TMP006)+=tmp006.o

View File

@@ -5,19 +5,20 @@
/* Host command module for Chrome EC */
#include "board.h"
#include "config.h"
#include "console.h"
#include "flash_commands.h"
#include "host_command.h"
#include "pwm_commands.h"
#include "usb_charge_commands.h"
#include "lpc.h"
#include "lpc_commands.h"
#include "pstore_commands.h"
#include "pwm_commands.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
#include "registers.h"
#include "usb_charge_commands.h"
#include "util.h"
static int host_command[2];
@@ -192,6 +193,17 @@ static void command_process(int slot)
case EC_LPC_COMMAND_USB_CHARGE_SET_MODE:
lpc_send_host_response(slot, usb_charge_command_set_mode(data));
return;
#ifdef CONFIG_PSTORE
case EC_LPC_COMMAND_PSTORE_INFO:
lpc_send_host_response(slot, pstore_command_get_info(data));
return;
case EC_LPC_COMMAND_PSTORE_READ:
lpc_send_host_response(slot, pstore_command_read(data));
return;
case EC_LPC_COMMAND_PSTORE_WRITE:
lpc_send_host_response(slot, pstore_command_write(data));
return;
#endif
default:
lpc_send_host_response(slot, EC_LPC_STATUS_INVALID_COMMAND);
}

109
common/pstore_commands.c Normal file
View File

@@ -0,0 +1,109 @@
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Persistent storage commands for Chrome EC */
#include "board.h"
#include "eeprom.h"
#include "lpc_commands.h"
#include "pstore_commands.h"
#include "uart.h"
#include "util.h"
/* TODO: move these to board.h */
#ifdef CONFIG_PSTORE
/* Start block and block count for host persistent storage in EC EEPROM */
#define PSTORE_EEPROM_BLOCK_START 16
#define PSTORE_EEPROM_BLOCK_COUNT 16
#endif
enum lpc_status pstore_command_get_info(uint8_t *data)
{
struct lpc_response_pstore_info *r =
(struct lpc_response_pstore_info *)data;
uart_printf("ee block size=%d, count=%d\n",
eeprom_get_block_size(), eeprom_get_block_count());
ASSERT(PSTORE_EEPROM_BLOCK_START + PSTORE_EEPROM_BLOCK_COUNT <=
eeprom_get_block_count());
r->pstore_size = PSTORE_EEPROM_BLOCK_COUNT * eeprom_get_block_size();
r->access_size = sizeof(uint32_t);
return EC_LPC_STATUS_SUCCESS;
}
enum lpc_status pstore_command_read(uint8_t *data)
{
struct lpc_params_pstore_read *p =
(struct lpc_params_pstore_read *)data;
struct lpc_response_pstore_read *r =
(struct lpc_response_pstore_read *)data;
char *dest = r->data;
int block_size = eeprom_get_block_size();
int block = p->offset / block_size + PSTORE_EEPROM_BLOCK_COUNT;
int offset = p->offset % block_size;
int bytes_left = p->size;
if (p->size > sizeof(r->data))
return EC_LPC_STATUS_ERROR;
while (bytes_left) {
/* Read what we can from the current block */
int bytes_this = MIN(bytes_left, block_size - offset);
if (block >=
PSTORE_EEPROM_BLOCK_START + PSTORE_EEPROM_BLOCK_COUNT)
return EC_LPC_STATUS_ERROR;
if (eeprom_read(block, offset, bytes_this, dest))
return EC_LPC_STATUS_ERROR;
/* Continue to the next block if necessary */
offset = 0;
block++;
bytes_left -= bytes_this;
dest += bytes_this;
}
return EC_LPC_STATUS_SUCCESS;
}
enum lpc_status pstore_command_write(uint8_t *data)
{
struct lpc_params_pstore_write *p =
(struct lpc_params_pstore_write *)data;
const char *src = p->data;
int block_size = eeprom_get_block_size();
int block = p->offset / block_size + PSTORE_EEPROM_BLOCK_COUNT;
int offset = p->offset % block_size;
int bytes_left = p->size;
if (p->size > sizeof(p->data))
return EC_LPC_STATUS_ERROR;
while (bytes_left) {
/* Write what we can to the current block */
int bytes_this = MIN(bytes_left, block_size - offset);
if (block >=
PSTORE_EEPROM_BLOCK_START + PSTORE_EEPROM_BLOCK_COUNT)
return EC_LPC_STATUS_ERROR;
if (eeprom_write(block, offset, bytes_this, src))
return EC_LPC_STATUS_ERROR;
/* Continue to the next block if necessary */
offset = 0;
block++;
bytes_left -= bytes_this;
src += bytes_this;
}
return EC_LPC_STATUS_SUCCESS;
}

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -11,9 +11,6 @@
#include "common.h"
#include "lpc_commands.h"
/* Initializes the module. */
int flash_commands_init(void);
/* Host command handlers. */
enum lpc_status flash_command_get_info(uint8_t *data);
enum lpc_status flash_command_read(uint8_t *data);

View File

@@ -136,7 +136,6 @@ struct lpc_response_flash_info {
uint32_t protect_block_size;
} __attribute__ ((packed));
/* Read flash */
#define EC_LPC_COMMAND_FLASH_READ 0x11
struct lpc_params_flash_read {
@@ -147,16 +146,14 @@ struct lpc_response_flash_read {
uint8_t data[EC_LPC_FLASH_SIZE_MAX];
} __attribute__ ((packed));
/* Write flash */
#define EC_LPC_COMMAND_FLASH_WRITE 0x12
struct lpc_params_flash_write {
uint32_t offset; /* Byte offset to erase */
uint32_t size; /* Size to erase in bytes */
uint32_t offset; /* Byte offset to write */
uint32_t size; /* Size to write in bytes */
uint8_t data[EC_LPC_FLASH_SIZE_MAX];
} __attribute__ ((packed));
/* Erase flash */
#define EC_LPC_COMMAND_FLASH_ERASE 0x13
struct lpc_params_flash_erase {
@@ -249,7 +246,6 @@ struct lpc_params_pwm_set_keyboard_backlight {
uint8_t percent;
} __attribute__ ((packed));
/*****************************************************************************/
/* USB charging control commands */
@@ -260,4 +256,38 @@ struct lpc_params_usb_charge_set_mode {
uint8_t mode;
} __attribute__ ((packed));
/*****************************************************************************/
/* Persistent storage for host */
/* Maximum bytes that can be read/written in a single command */
#define EC_LPC_PSTORE_SIZE_MAX 64
/* Get persistent storage info */
#define EC_LPC_COMMAND_PSTORE_INFO 0x40
struct lpc_response_pstore_info {
/* Persistent storage size, in bytes */
uint32_t pstore_size;
/* Access size. Read/write offset and size must be a multiple
* of this. */
uint32_t access_size;
} __attribute__ ((packed));
/* Read persistent storage */
#define EC_LPC_COMMAND_PSTORE_READ 0x41
struct lpc_params_pstore_read {
uint32_t offset; /* Byte offset to read */
uint32_t size; /* Size to read in bytes */
} __attribute__ ((packed));
struct lpc_response_pstore_read {
uint8_t data[EC_LPC_PSTORE_SIZE_MAX];
} __attribute__ ((packed));
/* Write persistent storage */
#define EC_LPC_COMMAND_PSTORE_WRITE 0x42
struct lpc_params_pstore_write {
uint32_t offset; /* Byte offset to write */
uint32_t size; /* Size to write in bytes */
uint8_t data[EC_LPC_PSTORE_SIZE_MAX];
} __attribute__ ((packed));
#endif /* __CROS_EC_LPC_COMMANDS_H */

18
include/pstore_commands.h Normal file
View File

@@ -0,0 +1,18 @@
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Persistent storage commands for Chrome EC */
#ifndef __CROS_EC_PSTORE_COMMANDS_H
#define __CROS_EC_PSTORE_COMMANDS_H
#include "common.h"
/* Host command handlers. */
enum lpc_status pstore_command_get_info(uint8_t *data);
enum lpc_status pstore_command_read(uint8_t *data);
enum lpc_status pstore_command_write(uint8_t *data);
#endif /* __CROS_EC_PSTORE_COMMANDS_H */

View File

@@ -28,6 +28,12 @@ const char help_str[] =
" Erases EC flash\n"
" hello\n"
" Checks for basic communication with EC\n"
" pstoreinfo\n"
" Prints information on the EC host persistent storage\n"
" pstoreread <offset> <size> <outfile>\n"
" Reads from EC host persistent storage to a file\n"
" pstorewrite <offset> <infile>\n"
" Writes to EC host persistent storage from a file\n"
" readtest <patternoffset> <size>\n"
" Reads a pattern from the EC via LPC\n"
" sertest\n"
@@ -55,6 +61,72 @@ const char help_str[] =
"";
/* Write a buffer to the file. Return non-zero if error. */
static int write_file(const char *filename, const char *buf, int size)
{
FILE *f;
int i;
/* Write to file */
f = fopen(filename, "wb");
if (!f) {
perror("Error opening output file");
return -1;
}
i = fwrite(buf, 1, size, f);
fclose(f);
if (i != size) {
perror("Error writing to file");
return -1;
}
return 0;
}
/* Read a file into a buffer. Sets *size to the size of the buffer. Returns
* the buffer, which must be freed with free() by the caller. Returns NULL if
* error. */
static char *read_file(const char *filename, int *size)
{
FILE *f = fopen(filename, "rb");
char *buf;
int i;
if (!f) {
perror("Error opening input file");
return NULL;
}
fseek(f, 0, SEEK_END);
*size = ftell(f);
rewind(f);
if (*size > 0x100000) {
fprintf(stderr, "File seems unreasonably large\n");
fclose(f);
return NULL;
}
buf = (char *)malloc(*size);
if (!buf) {
fprintf(stderr, "Unable to allocate buffer.\n");
fclose(f);
return NULL;
}
printf("Reading %d bytes from %s...\n", *size, filename);
i = fread(buf, 1, *size, f);
fclose(f);
if (i != *size) {
perror("Error reading file");
free(buf);
return NULL;
}
return buf;
}
/* Waits for the EC to be unbusy. Returns 0 if unbusy, non-zero if
* timeout. */
int wait_for_ec(int status_addr, int timeout_usec)
@@ -283,7 +355,6 @@ int cmd_flash_read(int argc, char *argv[])
int i;
char *e;
char *buf;
FILE *f;
if (argc < 3) {
fprintf(stderr,
@@ -322,20 +393,11 @@ int cmd_flash_read(int argc, char *argv[])
memcpy(buf + i, r.data, p.size);
}
/* Write to file */
f = fopen(argv[2], "wb");
if (!f) {
perror("Error opening output file");
free(buf);
return -1;
}
i = fwrite(buf, 1, size, f);
fclose(f);
rv = write_file(argv[2], buf, size);
free(buf);
if (i != size) {
perror("Error writing to file");
if (rv)
return -1;
}
printf("done.\n");
return 0;
}
@@ -349,7 +411,6 @@ int cmd_flash_write(int argc, char *argv[])
int i;
char *e;
char *buf;
FILE *f;
if (argc < 2) {
fprintf(stderr, "Usage: flashwrite <offset> <filename>\n");
@@ -362,34 +423,9 @@ int cmd_flash_write(int argc, char *argv[])
}
/* Read the input file */
f = fopen(argv[1], "rb");
if (!f) {
perror("Error opening input file");
buf = read_file(argv[1], &size);
if (!buf)
return -1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
rewind(f);
if (size > 0x100000) {
fprintf(stderr, "File seems unreasonably large\n");
fclose(f);
return -1;
}
buf = (char *)malloc(size);
if (!buf) {
fprintf(stderr, "Unable to allocate buffer.\n");
fclose(f);
return -1;
}
printf("Reading %d bytes from %s...\n", size, argv[1]);
i = fread(buf, 1, size, f);
if (i != size) {
perror("Error reading file");
free(buf);
return -1;
}
printf("Writing to offset %d...\n", offset);
@@ -460,6 +496,7 @@ int cmd_serial_test(int argc, char *argv[])
return 0;
}
int cmd_temperature(int argc, char *argv[])
{
int rv;
@@ -493,6 +530,7 @@ int cmd_temperature(int argc, char *argv[])
return rv;
}
int cmd_pwm_get_fan_rpm(void)
{
int rv;
@@ -509,6 +547,7 @@ int cmd_pwm_get_fan_rpm(void)
return 0;
}
int cmd_pwm_set_fan_rpm(int argc, char *argv[])
{
struct lpc_params_pwm_set_fan_target_rpm p;
@@ -535,6 +574,7 @@ int cmd_pwm_set_fan_rpm(int argc, char *argv[])
return 0;
}
int cmd_pwm_get_keyboard_backlight(void)
{
struct lpc_response_pwm_get_keyboard_backlight r;
@@ -550,6 +590,7 @@ int cmd_pwm_get_keyboard_backlight(void)
return 0;
}
int cmd_pwm_set_keyboard_backlight(int argc, char *argv[])
{
struct lpc_params_pwm_set_keyboard_backlight p;
@@ -576,6 +617,7 @@ int cmd_pwm_set_keyboard_backlight(int argc, char *argv[])
return 0;
}
int cmd_usb_charge_set_mode(int argc, char *argv[])
{
struct lpc_params_usb_charge_set_mode p;
@@ -609,6 +651,124 @@ int cmd_usb_charge_set_mode(int argc, char *argv[])
return 0;
}
int cmd_pstore_info(void)
{
struct lpc_response_pstore_info r;
int rv;
rv = ec_command(EC_LPC_COMMAND_PSTORE_INFO, NULL, 0, &r, sizeof(r));
if (rv)
return rv;
printf("PstoreSize %d\nAccessSize %d\n", r.pstore_size, r.access_size);
return 0;
}
int cmd_pstore_read(int argc, char *argv[])
{
struct lpc_params_pstore_read p;
struct lpc_response_pstore_read r;
int offset, size;
int rv;
int i;
char *e;
char *buf;
if (argc < 3) {
fprintf(stderr,
"Usage: pstoreread <offset> <size> <filename>\n");
return -1;
}
offset = strtol(argv[0], &e, 0);
if ((e && *e) || offset < 0 || offset > 0x10000) {
fprintf(stderr, "Bad offset.\n");
return -1;
}
size = strtol(argv[1], &e, 0);
if ((e && *e) || size <= 0 || size > 0x10000) {
fprintf(stderr, "Bad size.\n");
return -1;
}
printf("Reading %d bytes at offset %d...\n", size, offset);
buf = (char *)malloc(size);
if (!buf) {
fprintf(stderr, "Unable to allocate buffer.\n");
return -1;
}
/* Read data in chunks */
for (i = 0; i < size; i += EC_LPC_PSTORE_SIZE_MAX) {
p.offset = offset + i;
p.size = MIN(size - i, EC_LPC_PSTORE_SIZE_MAX);
rv = ec_command(EC_LPC_COMMAND_PSTORE_READ,
&p, sizeof(p), &r, sizeof(r));
if (rv) {
fprintf(stderr, "Read error at offset %d\n", i);
free(buf);
return -1;
}
memcpy(buf + i, r.data, p.size);
}
rv = write_file(argv[2], buf, size);
free(buf);
if (rv)
return -1;
printf("done.\n");
return 0;
}
int cmd_pstore_write(int argc, char *argv[])
{
struct lpc_params_pstore_write p;
int offset, size;
int rv;
int i;
char *e;
char *buf;
if (argc < 2) {
fprintf(stderr, "Usage: pstorewrite <offset> <filename>\n");
return -1;
}
offset = strtol(argv[0], &e, 0);
if ((e && *e) || offset < 0 || offset > 0x10000) {
fprintf(stderr, "Bad offset.\n");
return -1;
}
/* Read the input file */
buf = read_file(argv[1], &size);
if (!buf)
return -1;
printf("Writing to offset %d...\n", offset);
/* Write data in chunks */
for (i = 0; i < size; i += EC_LPC_PSTORE_SIZE_MAX) {
p.offset = offset + i;
p.size = MIN(size - i, EC_LPC_PSTORE_SIZE_MAX);
memcpy(p.data, buf + i, p.size);
rv = ec_command(EC_LPC_COMMAND_PSTORE_WRITE,
&p, sizeof(p), NULL, 0);
if (rv) {
fprintf(stderr, "Write error at offset %d\n", i);
free(buf);
return -1;
}
}
free(buf);
printf("done.\n");
return 0;
}
int main(int argc, char *argv[])
{
if (argc < 2 || !strcasecmp(argv[1], "-?") ||
@@ -652,6 +812,12 @@ int main(int argc, char *argv[])
return cmd_pwm_set_keyboard_backlight(argc - 2, argv + 2);
if (!strcasecmp(argv[1], "usbchargemode"))
return cmd_usb_charge_set_mode(argc - 2, argv + 2);
if (!strcasecmp(argv[1], "pstoreinfo"))
return cmd_pstore_info();
if (!strcasecmp(argv[1], "pstoreread"))
return cmd_pstore_read(argc - 2, argv + 2);
if (!strcasecmp(argv[1], "pstorewrite"))
return cmd_pstore_write(argc - 2, argv + 2);
/* If we're still here, command was unknown */
fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);