130 lines
3.4 KiB
C
130 lines
3.4 KiB
C
/* Copyright 2013 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.
|
|
*/
|
|
|
|
/* Chipset common code for Chrome EC */
|
|
|
|
#include "chipset.h"
|
|
#include "common.h"
|
|
#include "console.h"
|
|
#include "ec_commands.h"
|
|
#include "host_command.h"
|
|
#include "link_defs.h"
|
|
#include "system.h"
|
|
#include "task.h"
|
|
#include "timer.h"
|
|
#include "util.h"
|
|
|
|
/* Console output macros */
|
|
#define CPUTS(outstr) cputs(CC_CHIPSET, outstr)
|
|
#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args)
|
|
|
|
/*****************************************************************************/
|
|
/* Console commands */
|
|
|
|
#ifdef CONFIG_CMD_POWER_AP
|
|
static int command_apreset(int argc, char **argv)
|
|
{
|
|
/* Force the chipset to reset */
|
|
ccprintf("Issuing AP reset...\n");
|
|
chipset_reset(CHIPSET_RESET_CONSOLE_CMD);
|
|
return EC_SUCCESS;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(apreset, command_apreset,
|
|
NULL,
|
|
"Issue AP reset");
|
|
|
|
static int command_apshutdown(int argc, char **argv)
|
|
{
|
|
chipset_force_shutdown(CHIPSET_SHUTDOWN_CONSOLE_CMD);
|
|
return EC_SUCCESS;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(apshutdown, command_apshutdown,
|
|
NULL,
|
|
"Force AP shutdown");
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_HOSTCMD_AP_RESET
|
|
static enum ec_status host_command_apreset(struct host_cmd_handler_args *args)
|
|
{
|
|
/* Force the chipset to reset */
|
|
chipset_reset(CHIPSET_RESET_HOST_CMD);
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_CMD_AP_RESET,
|
|
host_command_apreset,
|
|
EC_VER_MASK(0));
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_CMD_AP_RESET_LOG
|
|
static struct mutex reset_log_mutex;
|
|
static int next_reset_log __preserved_logs(next_reset_log);
|
|
static uint32_t ap_resets_since_ec_boot;
|
|
/* keep reset_logs size a power of 2 */
|
|
static struct ap_reset_log_entry
|
|
reset_logs[4] __preserved_logs(reset_logs);
|
|
static int reset_log_checksum __preserved_logs(reset_log_checksum);
|
|
|
|
/* Calculate reset log checksum */
|
|
static int calc_reset_log_checksum(void)
|
|
{
|
|
return next_reset_log ^ reset_logs[next_reset_log].reset_cause;
|
|
}
|
|
|
|
/* Initialize reset logs and next reset log */
|
|
void init_reset_log(void)
|
|
{
|
|
if (next_reset_log < 0 || next_reset_log >= ARRAY_SIZE(reset_logs) ||
|
|
reset_log_checksum != calc_reset_log_checksum()) {
|
|
reset_log_checksum = 0;
|
|
next_reset_log = 0;
|
|
memset(&reset_logs, 0, sizeof(reset_logs));
|
|
}
|
|
}
|
|
|
|
void report_ap_reset(enum chipset_shutdown_reason reason)
|
|
{
|
|
timestamp_t now = get_time();
|
|
uint32_t now_ms = (uint32_t)(now.val / MSEC);
|
|
|
|
mutex_lock(&reset_log_mutex);
|
|
reset_logs[next_reset_log].reset_cause = reason;
|
|
reset_logs[next_reset_log++].reset_time_ms = now_ms;
|
|
next_reset_log &= ARRAY_SIZE(reset_logs) - 1;
|
|
ap_resets_since_ec_boot++;
|
|
mutex_unlock(&reset_log_mutex);
|
|
|
|
/* Update checksum */
|
|
reset_log_checksum = calc_reset_log_checksum();
|
|
}
|
|
|
|
test_mockable enum ec_error_list
|
|
get_ap_reset_stats(struct ap_reset_log_entry *reset_log_entries,
|
|
size_t num_reset_log_entries, uint32_t *resets_since_ec_boot)
|
|
{
|
|
size_t log_address;
|
|
size_t i;
|
|
|
|
if (reset_log_entries == NULL || resets_since_ec_boot == NULL)
|
|
return EC_ERROR_INVAL;
|
|
|
|
mutex_lock(&reset_log_mutex);
|
|
*resets_since_ec_boot = ap_resets_since_ec_boot;
|
|
for (i = 0;
|
|
i != ARRAY_SIZE(reset_logs) && i != num_reset_log_entries;
|
|
++i) {
|
|
log_address = (next_reset_log + i) &
|
|
(ARRAY_SIZE(reset_logs) - 1);
|
|
reset_log_entries[i] = reset_logs[log_address];
|
|
}
|
|
mutex_unlock(&reset_log_mutex);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
#endif /* !CONFIG_AP_RESET_LOG */
|
|
|