From 96536de3f4c2b942b5c40ac18a2a42d282f98dbf Mon Sep 17 00:00:00 2001 From: Shawn Nematbakhsh Date: Wed, 11 Feb 2015 19:32:15 -0800 Subject: pd_log: Add command to request PD MCU to write a log When we find that charging is in a wedged state, we may wish to write a PD log entry, but the PD MCU cannot detect such a state on its own. Therefore, add a new command to ask the PD MCU to write a log of a given type, and add a new board-specific custom log event. BUG=chrome-os-partner:36668 TEST=Manual on samus: ./ectool --dev=1 pdwritelog charge 0 ./ectool --dev=1 pdwritelog charge 1 ./ectool --dev=1 pdwritelog 1 0 ./ectool --dev=1 pdwritelog 2 0 ./ectool --dev=1 pdlog Verify log output matches expectation: 2015-02-12 11:12:49.290 P0 SRC 2015-02-12 11:12:49.296 P1 SNK Charger PD 20286mV max 20000mV / 3000mA 2015-02-12 11:12:49.303 P0 New connection 2015-02-12 11:12:49.310 P0 Board-custom event --- END OF LOG -- Also, verify kernel logging of wedged event: [ 181.378420] PDLOG 2015/02/12 19:13:44.019 P0 Event 02 (0000) [] Also, trigger wedged state on Samus and verify log entry is written. BRANCH=Samus Change-Id: I55c7c839cf8300fcd3931dccdaaf16c1065e31a8 Signed-off-by: Shawn Nematbakhsh Reviewed-on: https://chromium-review.googlesource.com/248981 Reviewed-by: Alec Berg --- board/samus/extpower.c | 17 +++++++++++++++++ common/charge_manager.c | 3 +++ common/pd_log.c | 32 ++++++++++++++++++++++++++++++++ include/charge_manager.h | 2 ++ include/ec_commands.h | 14 ++++++++++++-- util/ectool.c | 37 +++++++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 2 deletions(-) diff --git a/board/samus/extpower.c b/board/samus/extpower.c index 79eb941d18..19f4a5d5ff 100644 --- a/board/samus/extpower.c +++ b/board/samus/extpower.c @@ -245,6 +245,22 @@ static int get_boostin_voltage(void) return ret; } +/* + * Send command to PD to write a custom persistent log entry indicating that + * charging was wedged. Returns pd_host_command success status. + */ +static int log_charge_wedged(void) +{ + static struct ec_params_pd_write_log_entry log_args; + + log_args.type = PD_EVENT_MCU_BOARD_CUSTOM; + log_args.port = 0; + + return pd_host_command(EC_CMD_PD_WRITE_LOG_ENTRY, 0, + &log_args, + sizeof(struct ec_params_pd_write_log_entry), + NULL, 0); +} /* Time interval between checking if charge circuit is wedged */ #define CHARGE_WEDGE_CHECK_INTERVAL (2*SECOND) @@ -320,6 +336,7 @@ static void check_charge_wedged(void) host_command_pd_send_status(PD_CHARGE_NONE); charger_disable(1); charge_circuit_state = CHARGE_CIRCUIT_WEDGED; + log_charge_wedged(); CPRINTS("Charge wedged! PROCHOT %02x, Stalled: %d", prochot_status, charge_stalled_count); diff --git a/common/charge_manager.c b/common/charge_manager.c index 35a570d2e6..bf93724cbd 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -199,6 +199,9 @@ void charge_manager_save_log(int port) uint16_t flags = 0; struct ec_response_usb_pd_power_info pinfo; + if (port < 0 || port >= PD_PORT_COUNT) + return; + save_log[port] = 0; charge_manager_fill_power_info(port, &pinfo); diff --git a/common/pd_log.c b/common/pd_log.c index fa9b8c3bf5..96d55f9330 100644 --- a/common/pd_log.c +++ b/common/pd_log.c @@ -3,6 +3,7 @@ * found in the LICENSE file. */ +#include "charge_manager.h" #include "console.h" #include "hooks.h" #include "host_command.h" @@ -194,6 +195,37 @@ dequeue_retry: DECLARE_HOST_COMMAND(EC_CMD_PD_GET_LOG_ENTRY, hc_pd_get_log_entry, EC_VER_MASK(0)); + +static int hc_pd_write_log_entry(struct host_cmd_handler_args *args) +{ + const struct ec_params_pd_write_log_entry *p = args->params; + uint8_t type = p->type; + uint8_t port = p->port; + + if (type < PD_EVENT_MCU_BASE || type >= PD_EVENT_ACC_BASE) + return EC_RES_INVALID_PARAM; + if (port > 0 && port >= PD_PORT_COUNT) + return EC_RES_INVALID_PARAM; + + switch (type) { + /* Charge event: Log data for all ports */ + case PD_EVENT_MCU_CHARGE: + charge_manager_save_log(port); + break; + + /* Other events: no extra data, just log event type + port */ + case PD_EVENT_MCU_CONNECT: + case PD_EVENT_MCU_BOARD_CUSTOM: + default: + pd_log_event(type, PD_LOG_PORT_SIZE(port, 0), 0, NULL); + break; + } + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_PD_WRITE_LOG_ENTRY, + hc_pd_write_log_entry, + EC_VER_MASK(0)); #else /* !HAS_TASK_HOSTCMD */ /* we are a PD accessory, send back the events as a VDM (VDO_CMD_GET_LOG) */ int pd_vdm_get_log_entry(uint32_t *payload) diff --git a/include/charge_manager.h b/include/charge_manager.h index d761f131fc..6654542667 100644 --- a/include/charge_manager.h +++ b/include/charge_manager.h @@ -6,6 +6,8 @@ #ifndef __CHARGE_MANAGER_H #define __CHARGE_MANAGER_H +#include "common.h" + /* Charge port that indicates no active port */ #define CHARGE_SUPPLIER_NONE -1 #define CHARGE_PORT_NONE -1 diff --git a/include/ec_commands.h b/include/ec_commands.h index 304cb9acda..edf9f4fa6b 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -2888,8 +2888,10 @@ struct ec_response_pd_log { /* PD event log : entry types */ /* PD MCU events */ #define PD_EVENT_MCU_BASE 0x00 -#define PD_EVENT_MCU_CHARGE (PD_EVENT_MCU_BASE+0) -#define PD_EVENT_MCU_CONNECT (PD_EVENT_MCU_BASE+1) +#define PD_EVENT_MCU_CHARGE (PD_EVENT_MCU_BASE+0) +#define PD_EVENT_MCU_CONNECT (PD_EVENT_MCU_BASE+1) +/* Reserved for custom board event */ +#define PD_EVENT_MCU_BOARD_CUSTOM (PD_EVENT_MCU_BASE+2) /* PD generic accessory events */ #define PD_EVENT_ACC_BASE 0x20 #define PD_EVENT_ACC_RW_FAIL (PD_EVENT_ACC_BASE+0) @@ -2978,6 +2980,14 @@ struct ec_params_usb_pd_set_mode_request { uint8_t port; /* port */ } __packed; +/* Ask the PD MCU to record a log of a requested type */ +#define EC_CMD_PD_WRITE_LOG_ENTRY 0x117 + +struct ec_params_pd_write_log_entry { + uint8_t type; /* event type : see PD_EVENT_xx above */ + uint8_t port; /* port#, or 0 for events unrelated to a given port */ +} __packed; + #endif /* !__ACPI__ */ /*****************************************************************************/ diff --git a/util/ectool.c b/util/ectool.c index 251e604b84..ed4787706f 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -141,6 +141,8 @@ const char help_str[] = " Whether or not the AP should pause in S5 on shutdown\n" " pdlog\n" " Prints the PD event log entries\n" + " pdwritelog \n" + " Writes a PD event log of the given \n" " pdgetmode \n" " Get All USB-PD alternate SVIDs and modes on \n" " pdsetmode \n" @@ -5469,6 +5471,10 @@ int cmd_pd_log(int argc, char *argv[]) >> CHARGE_FLAGS_TYPE_SHIFT; pinfo.max_power = 0; print_pd_power_info(&pinfo); + } else if (u.r.type == PD_EVENT_MCU_CONNECT) { + printf("New connection\n"); + } else if (u.r.type == PD_EVENT_MCU_BOARD_CUSTOM) { + printf("Board-custom event\n"); } else if (u.r.type == PD_EVENT_ACC_RW_FAIL) { printf("RW signature check failed\n"); } else if (u.r.type == PD_EVENT_PS_FAULT) { @@ -5503,6 +5509,36 @@ int cmd_pd_log(int argc, char *argv[]) return 0; } +int cmd_pd_write_log(int argc, char *argv[]) +{ + struct ec_params_pd_write_log_entry p; + char *e; + + if (argc < 3) { + fprintf(stderr, "Usage: %s \n", + argv[0]); + return -1; + } + + if (!strcasecmp(argv[1], "charge")) + p.type = PD_EVENT_MCU_CHARGE; + else { + p.type = strtol(argv[1], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad log_type parameter.\n"); + return -1; + } + } + + p.port = strtol(argv[2], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad port parameter.\n"); + return -1; + } + + return ec_command(EC_CMD_PD_WRITE_LOG_ENTRY, 0, &p, sizeof(p), NULL, 0); +} + /* NULL-terminated list of commands */ const struct command commands[] = { {"extpwrcurrentlimit", cmd_ext_power_current_limit}, @@ -5559,6 +5595,7 @@ const struct command commands[] = { {"pdsetmode", cmd_pd_set_amode}, {"port80read", cmd_port80_read}, {"pdlog", cmd_pd_log}, + {"pdwritelog", cmd_pd_write_log}, {"powerinfo", cmd_power_info}, {"protoinfo", cmd_proto_info}, {"pstoreinfo", cmd_pstore_info}, -- cgit v1.2.1