summaryrefslogtreecommitdiff
path: root/common/chipset.c
blob: 3a30c96112e569b0b12309c208aeffa3898522a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* Copyright 2013 The ChromiumOS Authors
 * 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 "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;
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];

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);
}

static int host_command_get_uptime_info(struct host_cmd_handler_args *args)
{
	/*
	 * In the current implementation, not all terms are preserved across a
	 * sysjump.  Future implementations may preserve additional information.
	 *
	 * time_since_ec_boot_ms:   preserved, but wraps at ~50 days
	 * ec_reset_flags:          preserved, with 'sysjump' added
	 * ap_resets_since_ec_boot: Not preserved
	 * recent_ap_reset[*]:      Not preserved
	 */
	struct ec_response_uptime_info *r = args->response;
	timestamp_t now = get_time();
	uint32_t now_ms = (uint32_t)(now.val / MSEC);
	size_t log_address = 0;
	size_t i = 0;

	r->time_since_ec_boot_ms = now_ms;
	r->ec_reset_flags = system_get_reset_flags();

	memset(r->recent_ap_reset, 0, sizeof(r->recent_ap_reset));

	mutex_lock(&reset_log_mutex);
	r->ap_resets_since_ec_boot = ap_resets_since_ec_boot;
	for (i = 0;
	     i != ARRAY_SIZE(reset_logs) && i != ARRAY_SIZE(r->recent_ap_reset);
	     ++i) {
		log_address = (next_reset_log + i) &
			(ARRAY_SIZE(reset_logs) - 1);
		r->recent_ap_reset[i] = reset_logs[log_address];
	}
	mutex_unlock(&reset_log_mutex);

	args->response_size = sizeof(*r);
	return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_GET_UPTIME_INFO,
		     host_command_get_uptime_info,
		     EC_VER_MASK(0));

#endif  /* !CONFIG_AP_RESET_LOG */