summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Hesling <hesling@chromium.org>2019-07-02 11:14:48 -0700
committerCommit Bot <commit-bot@chromium.org>2019-07-25 22:55:07 +0000
commitddefefa0e49462514d3b804e19622ef97d1266a5 (patch)
tree8a9b9424e9766115f9969a4b803f5a257aef7b37
parentdb09365fbf9662e30997439ee32566d3c9d58f4c (diff)
downloadchrome-ec-ddefefa0e49462514d3b804e19622ef97d1266a5.tar.gz
ectool: Add stress command to ectool
This command stress tests the channel between the user-side ec command interface and the target MCU. This can be used to expose rare communication errors, such as exceeding communication timeouts. BRANCH=none BUG=b:131724307,b:116065496 TEST=make buildall -j TEST=cros_workon --board=nocturne start chromeos-base/ec-utils emerge-nocturne chromeos-base/ec-utils cros deploy dut1 chromeos-base/ec-utils # On dut1 ectool stress ectool --name=cros_fp stress ectool --name=cros_fp stress reboot Change-Id: I485e915d0bc027ccee8d2d78b90fe0d066a3ff4d Signed-off-by: Craig Hesling <hesling@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1686712 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--util/ectool.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/util/ectool.c b/util/ectool.c
index f1e7758dc6..f3a7cf09b2 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -13,6 +13,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <signal.h>
#include <stdbool.h>
#include "anx74xx.h"
@@ -36,6 +37,11 @@
/* Maximum flash size (16 MB, conservative) */
#define MAX_FLASH_SIZE 0x1000000
+/*
+ * Calculate the expected response for a hello ec command.
+ */
+#define HELLO_RESP(in_data) ((in_data) + 0x01020304)
+
/* Command line options */
enum {
OPT_DEV = 1000,
@@ -259,6 +265,8 @@ const char help_str[] =
" Run RW signature verification and get status.\n"
" sertest\n"
" Serial output test for COM2\n"
+ " stress [reboot] [help]\n"
+ " Stress test the ec host command interface.\n"
" switches\n"
" Prints current EC switch positions\n"
" temps <sensorid>\n"
@@ -2174,6 +2182,163 @@ int cmd_port_80_flood(int argc, char *argv[])
}
#endif
+/*
+ * This boolean variable and handler are used for
+ * catching signals that translate into a quit/shutdown
+ * of a runtime loop.
+ * This is used in cmd_stress_test.
+ */
+static bool sig_quit;
+static void sig_quit_handler(int sig)
+{
+ sig_quit = true;
+}
+
+int cmd_stress_test(int argc, char *argv[])
+{
+ int i;
+ bool reboot = false;
+ time_t now;
+ time_t start_time, last_update_time;
+ unsigned int rand_seed = 0;
+ uint64_t round = 1, attempt = 1;
+ uint64_t failures = 0;
+
+ const int max_sleep_usec = 1000; /* 1ms */
+ const int loop_update_interval = 10000;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "help") == 0) {
+ printf("Usage: %s [reboot] [help]\n", argv[0]);
+ printf("Stress tests the host command interface by"
+ " repeatedly issuing common host commands.\n");
+ printf("The intent is to expose errors in kernel<->mcu"
+ " communication, such as exceeding timeouts.\n");
+ printf("\n");
+ printf("reboot - Reboots the target before"
+ " starting the stress test.\n");
+ printf(" This may force restart the host,"
+ " if the main ec is the target.\n");
+ return 0;
+ } else if (strcmp(argv[i], "reboot") == 0) {
+ reboot = true;
+ } else {
+ fprintf(stderr, "Error - Unknown argument '%s'\n",
+ argv[i]);
+ return 1;
+ }
+ }
+
+ printf("Stress test tool version: %s %s %s\n",
+ CROS_ECTOOL_VERSION, DATE, BUILDER);
+
+ start_time = time(NULL);
+ last_update_time = start_time;
+ printf("Start time: %s\n", ctime(&start_time));
+
+ if (reboot) {
+ printf("Issuing ec reboot. Expect a few early failed"
+ " ioctl messages.\n");
+ ec_command(EC_CMD_REBOOT, 0, NULL, 0, NULL, 0);
+ sleep(2);
+ }
+
+ sig_quit = false;
+ signal(SIGINT, sig_quit_handler);
+ while (!sig_quit) {
+ int rv;
+ struct ec_response_get_version ver_r;
+ char *build_string = (char *)ec_inbuf;
+ struct ec_params_flash_protect flash_p;
+ struct ec_response_flash_protect flash_r;
+ struct ec_params_hello hello_p;
+ struct ec_response_hello hello_r;
+
+ /* Request EC Version Strings */
+ rv = ec_command(EC_CMD_GET_VERSION, 0,
+ NULL, 0, &ver_r, sizeof(ver_r));
+ if (rv < 0) {
+ failures++;
+ perror("ERROR: EC_CMD_GET_VERSION failed");
+ }
+ ver_r.version_string_ro[sizeof(ver_r.version_string_ro) - 1]
+ = '\0';
+ ver_r.version_string_rw[sizeof(ver_r.version_string_rw) - 1]
+ = '\0';
+ if (strlen(ver_r.version_string_ro) == 0) {
+ failures++;
+ fprintf(stderr, "RO version string is empty\n");
+ }
+ if (strlen(ver_r.version_string_rw) == 0) {
+ failures++;
+ fprintf(stderr, "RW version string is empty\n");
+ }
+
+ usleep(rand_r(&rand_seed) % max_sleep_usec);
+
+ /* Request EC Build String */
+ rv = ec_command(EC_CMD_GET_BUILD_INFO, 0,
+ NULL, 0, ec_inbuf, ec_max_insize);
+ if (rv < 0) {
+ failures++;
+ perror("ERROR: EC_CMD_GET_BUILD_INFO failed");
+ }
+ build_string[ec_max_insize - 1] = '\0';
+ if (strlen(build_string) == 0) {
+ failures++;
+ fprintf(stderr, "Build string is empty\n");
+ }
+
+ usleep(rand_r(&rand_seed) % max_sleep_usec);
+
+ /* Request Flash Protect Status */
+ rv = ec_command(EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT,
+ &flash_p, sizeof(flash_p), &flash_r,
+ sizeof(flash_r));
+ if (rv < 0) {
+ failures++;
+ perror("ERROR: EC_CMD_FLASH_PROTECT failed");
+ }
+
+ usleep(rand_r(&rand_seed) % max_sleep_usec);
+
+ /* Request Hello */
+ hello_p.in_data = 0xa0b0c0d0;
+ rv = ec_command(EC_CMD_HELLO, 0, &hello_p, sizeof(hello_p),
+ &hello_r, sizeof(hello_r));
+ if (rv < 0) {
+ failures++;
+ perror("ERROR: EC_CMD_HELLO failed");
+ }
+ if (hello_r.out_data != HELLO_RESP(hello_p.in_data)) {
+ failures++;
+ fprintf(stderr, "Hello response was invalid.\n");
+ }
+
+ usleep(rand_r(&rand_seed) % max_sleep_usec);
+
+ if ((attempt % loop_update_interval) == 0) {
+ now = time(NULL);
+ printf("Update: attempt %" PRIu64 " round %" PRIu64
+ " | took %.f seconds\n",
+ attempt, round,
+ difftime(now, last_update_time));
+ last_update_time = now;
+ }
+
+ if (attempt++ == UINT64_MAX)
+ round++;
+ }
+ printf("\n");
+
+ now = time(NULL);
+ printf("End time: %s\n", ctime(&now));
+ printf("Total runtime: %.f seconds\n",
+ difftime(time(NULL), start_time));
+ printf("Total failures: %" PRIu64 "\n", failures);
+ return 0;
+}
+
int read_mapped_temperature(int id)
{
int rv;
@@ -8842,6 +9007,7 @@ const struct command commands[] = {
{"rwsigaction", cmd_rwsig_action},
{"rwsigstatus", cmd_rwsig_status},
{"sertest", cmd_serial_test},
+ {"stress", cmd_stress_test},
{"port80flood", cmd_port_80_flood},
{"switches", cmd_switches},
{"temps", cmd_temperature},