forked from thesofproject/sof
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathagent.c
More file actions
145 lines (117 loc) · 4.11 KB
/
agent.c
File metadata and controls
145 lines (117 loc) · 4.11 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2017 Intel Corporation. All rights reserved.
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
/*
* System Agent - Simple FW Monitor that can notify host drivers in the event
* of any FW errors. The SA checks if the DSP is still responsive and verifies
* the stability of the system by checking time elapsed between every timer
* tick. If the core exceeds the threshold by over 5% then the SA will emit
* error trace. However if it will be exceeded by over 100% the panic will be
* called.
*/
#include <rtos/timer.h>
#include <sof/lib/agent.h>
#include <rtos/alloc.h>
#include <rtos/clk.h>
#include <sof/lib/memory.h>
#include <sof/lib/uuid.h>
#include <rtos/panic.h>
#include <sof/platform.h>
#include <sof/schedule/ll_schedule.h>
#include <sof/schedule/schedule.h>
#include <rtos/task.h>
#include <rtos/sof.h>
#include <sof/trace/trace.h>
#include <ipc/topology.h>
#include <ipc/trace.h>
#include <user/trace.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <rtos/kernel.h>
LOG_MODULE_REGISTER(sa, CONFIG_SOF_LOG_LEVEL);
/* 5276b491-5b64-464e-8984-dc228ef9e6a1 */
DECLARE_SOF_UUID("sa", sa_uuid, 0x5276b491, 0x5b64, 0x464e,
0x89, 0x84, 0xdc, 0x22, 0x8e, 0xf9, 0xe6, 0xa1);
DECLARE_TR_CTX(sa_tr, SOF_UUID(sa_uuid), LOG_LEVEL_INFO);
/* c63c4e75-8f61-4420-9319-1395932efa9e */
DECLARE_SOF_UUID("agent-work", agent_work_task_uuid, 0xc63c4e75, 0x8f61, 0x4420,
0x93, 0x19, 0x13, 0x95, 0x93, 0x2e, 0xfa, 0x9e);
#if CONFIG_PERFORMANCE_COUNTERS
static void perf_sa_trace(struct perf_cnt_data *pcd, int ignored)
{
tr_info(&sa_tr, "perf sys_load peak plat %u cpu %u",
(uint32_t)((pcd)->plat_delta_peak),
(uint32_t)((pcd)->cpu_delta_peak));
}
static void perf_avg_sa_trace(struct perf_cnt_data *pcd, int ignored)
{
tr_info(&sa_tr, "perf sys_load cpu avg %u (current peak %u)",
(uint32_t)((pcd)->cpu_delta_sum),
(uint32_t)((pcd)->cpu_delta_peak));
}
#endif
static enum task_state validate(void *data)
{
struct sa *sa = data;
uint64_t current;
uint64_t delta;
current = sof_cycle_get_64();
delta = current - sa->last_check;
perf_cnt_stamp(&sa->pcd, perf_sa_trace, 0 /* ignored */);
perf_cnt_average(&sa->pcd, perf_avg_sa_trace, 0 /* ignored */);
#if CONFIG_AGENT_PANIC_ON_DELAY
/* panic timeout */
if (sa->panic_on_delay && delta > sa->panic_timeout)
sof_panic(SOF_IPC_PANIC_IDLE);
#endif
/* warning timeout */
if (delta > sa->warn_timeout) {
if (delta > UINT_MAX)
tr_warn(&sa_tr, "validate(), ll drift detected, delta > %u", UINT_MAX);
else
tr_warn(&sa_tr, "validate(), ll drift detected, delta = %u",
(unsigned int)delta);
}
/* update last_check to current */
sa->last_check = current;
return SOF_TASK_STATE_RESCHEDULE;
}
void sa_init(struct sof *sof, uint64_t timeout)
{
uint64_t ticks;
if (timeout > UINT_MAX)
tr_warn(&sa_tr, "sa_init(), timeout > %u", UINT_MAX);
else
tr_info(&sa_tr, "sa_init(), timeout = %u", (unsigned int)timeout);
sof->sa = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*sof->sa));
/* set default timeouts */
ticks = k_us_to_cyc_ceil64(timeout);
/* TODO: change values after minimal drifts will be assured */
sof->sa->panic_timeout = 2 * ticks; /* 100% delay */
sof->sa->warn_timeout = ticks + ticks / 20; /* 5% delay */
atomic_init(&sof->sa->panic_cnt, 0);
sof->sa->panic_on_delay = true;
if (ticks > UINT_MAX || sof->sa->warn_timeout > UINT_MAX ||
sof->sa->panic_timeout > UINT_MAX)
tr_info(&sa_tr,
"sa_init(), some of the values are > %u", UINT_MAX);
else
tr_info(&sa_tr,
"sa_init(), ticks = %u, sof->sa->warn_timeout = %u, sof->sa->panic_timeout = %u",
(unsigned int)ticks, (unsigned int)sof->sa->warn_timeout,
(unsigned int)sof->sa->panic_timeout);
schedule_task_init_ll(&sof->sa->work, SOF_UUID(agent_work_task_uuid),
SOF_SCHEDULE_LL_TIMER,
SOF_TASK_PRI_HIGH, validate, sof->sa, 0, 0);
schedule_task(&sof->sa->work, 0, timeout);
/* set last check time to now to give time for boot completion */
sof->sa->last_check = sof_cycle_get_64();
}
void sa_exit(struct sof *sof)
{
schedule_task_cancel(&sof->sa->work);
}