Pavona Software APIs
alert_handler_testutils.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/lib/testing/alert_handler_testutils.h"
6
7#include "hw/top/dt/alert_handler.h" // Generated
8#include "hw/top/dt/api.h" // Generated
13#include "sw/device/lib/testing/test_framework/check.h"
14
15#include "hw/top/alert_handler_regs.h" // Generated
16
17#define MODULE_ID MAKE_MODULE_ID('a', 'h', 't')
18
19const char kAlertClassName[] = {'A', 'B', 'C', 'D'};
20static_assert(ARRAYSIZE(kAlertClassName) == ALERT_HANDLER_PARAM_N_CLASSES,
21 "Expected four alert classes!");
22
23/**
24 * This is used to traverse the dump treating it as an array of bits, and
25 * extract a number of bits placing them in a uint32_t. The word and bit index
26 * are updated by num_bits before returning.
27 */
28static uint32_t get_next_n_bits(
29 int num_bits, const dif_rstmgr_alert_info_dump_segment_t *dump,
30 int *word_index, int *bit_index) {
31 CHECK(num_bits <= 32);
32 CHECK(*bit_index < 32);
33 uint32_t word = dump[*word_index] >> *bit_index;
34 // If the needed bits straddle into the next word, extract the missing bits
35 // from the next word.
36 if (*bit_index + num_bits > 32) {
37 word |= dump[(*word_index) + 1] << (32 - *bit_index);
38 }
39 if (*bit_index + num_bits >= 32) {
40 (*word_index) += 1;
41 *bit_index = *bit_index + num_bits - 32;
42 } else {
43 *bit_index += num_bits;
44 }
45 uint32_t mask = (uint32_t)(((uint64_t)1 << num_bits) - 1);
46 word &= mask;
47 return word;
48}
49
50status_t alert_handler_testutils_info_parse(
51 const dif_rstmgr_alert_info_dump_segment_t *dump, int dump_size,
52 alert_handler_testutils_info_t *info) {
53 int word_index = 0;
54 int bit_index = 0;
55 for (int i = 0; i < ALERT_HANDLER_PARAM_N_CLASSES; ++i) {
56 info->class_esc_state[i] =
57 get_next_n_bits(3, dump, &word_index, &bit_index);
58 }
59 for (int i = 0; i < ALERT_HANDLER_PARAM_N_CLASSES; ++i) {
60 info->class_esc_cnt[i] = get_next_n_bits(32, dump, &word_index, &bit_index);
61 }
62 for (int i = 0; i < ALERT_HANDLER_PARAM_N_CLASSES; ++i) {
63 info->class_accum_cnt[i] =
64 (uint16_t)get_next_n_bits(16, dump, &word_index, &bit_index);
65 }
66 info->loc_alert_cause =
67 (uint8_t)get_next_n_bits(7, dump, &word_index, &bit_index);
68 TRY_CHECK(word_index < dump_size);
69 for (int i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
70 info->alert_cause[i] = get_next_n_bits(1, dump, &word_index, &bit_index);
71 }
72 TRY_CHECK(word_index < dump_size ||
73 (word_index == dump_size && bit_index == 0));
74 return OK_STATUS();
75}
76
77void alert_handler_testutils_info_dump(
78 const alert_handler_testutils_info_t *info) {
79 LOG_INFO("alert_info:");
80 LOG_INFO("esc_state [0]=%x, [1]=%x, [2]=%x, [3]=%x", info->class_esc_state[0],
81 info->class_esc_state[1], info->class_esc_state[2],
82 info->class_esc_state[3]);
83 LOG_INFO("esc_cnt [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x",
84 info->class_esc_cnt[0], info->class_esc_cnt[1],
85 info->class_esc_cnt[2], info->class_esc_cnt[3]);
86 LOG_INFO("accum_cnt [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x",
87 info->class_accum_cnt[0], info->class_accum_cnt[1],
88 info->class_accum_cnt[2], info->class_accum_cnt[3]);
89 LOG_INFO("loc_alert_cause=0x%x", info->loc_alert_cause);
90 int set_count = 0;
91 LOG_INFO("alert_cause bits set:");
92 // Typically very few bits are set, so it is more clear to only show the
93 // on bits.
94 for (int i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
95 if (info->alert_cause[i]) {
96 LOG_INFO("alert_cause[%d] = 1", i);
97 ++set_count;
98 }
99 }
100 if (set_count == 0) {
101 LOG_INFO("No bits set");
102 }
103}
104
105status_t alert_handler_testutils_configure_all(
106 const dif_alert_handler_t *alert_handler, dif_alert_handler_config_t config,
107 dif_toggle_t locked) {
108 TRY_CHECK(alert_handler != NULL);
109 TRY_CHECK(dif_is_valid_toggle(locked));
110
111 // Check lengths of alert, local alert, and class arrays.
112 TRY_CHECK((config.alerts_len > 0 && config.alerts != NULL &&
113 config.alert_classes != NULL) ||
114 (config.alerts_len == 0 && config.alerts == NULL &&
115 config.alert_classes == NULL));
116 TRY_CHECK((config.local_alerts_len > 0 && config.local_alerts != NULL &&
117 config.local_alert_classes != NULL) ||
118 (config.local_alerts_len == 0 && config.local_alerts == NULL &&
119 config.local_alert_classes == NULL));
120 TRY_CHECK((config.classes_len > 0 && config.classes != NULL &&
121 config.class_configs != NULL) ||
122 (config.classes_len == 0 && config.classes == NULL &&
123 config.class_configs == NULL));
124
125 // Check that the provided ping timeout actually fits in the timeout
126 // register, which is smaller than a native word length.
127 TRY_CHECK(
128 config.ping_timeout <=
129 ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_MASK);
130
131 // Configure and enable the requested alerts.
132 for (int i = 0; i < config.alerts_len; ++i) {
133 TRY(dif_alert_handler_configure_alert(alert_handler, config.alerts[i],
134 config.alert_classes[i],
135 kDifToggleEnabled, locked));
136 }
137
138 // Configure and enable the requested local alerts.
139 for (int i = 0; i < config.local_alerts_len; ++i) {
140 TRY(dif_alert_handler_configure_local_alert(
141 alert_handler, config.local_alerts[i], config.local_alert_classes[i],
142 kDifToggleEnabled, locked));
143 }
144
145 // Configure and enable the requested classes.
146 for (int i = 0; i < config.classes_len; ++i) {
147 TRY(dif_alert_handler_configure_class(alert_handler, config.classes[i],
148 config.class_configs[i],
149 kDifToggleEnabled, locked));
150 }
151
152 // Configure the ping timer.
153 TRY(dif_alert_handler_configure_ping_timer(alert_handler, config.ping_timeout,
154 kDifToggleEnabled, locked));
155
156 return OK_STATUS();
157}
158
159status_t alert_handler_testutils_get_cycles_from_us(uint64_t microseconds,
160 uint32_t *cycles) {
161 uint64_t cycles_ = udiv64_slow(
164 1000000,
165 /*rem_out=*/NULL);
166 TRY_CHECK(cycles_ < UINT32_MAX,
167 "The value 0x%08x%08x can't fit into the 32 bits timer counter.",
168 (uint32_t)(cycles_ >> 32), (uint32_t)cycles_);
169 *cycles = (uint32_t)cycles_;
170 return OK_STATUS();
171}
172
173uint32_t alert_handler_testutils_cycle_rescaling_factor(void) {
174 return kDeviceType == kDeviceSimDV ? 1 : 10;
175}
176
177static status_t alert_handler_class_info_log(
178 const dif_alert_handler_t *alert_handler,
179 dif_alert_handler_class_t alert_class) {
181 TRY(dif_alert_handler_get_class_state(alert_handler, alert_class, &state));
182
183 uint16_t num_alerts;
184 TRY(dif_alert_handler_get_accumulator(alert_handler, alert_class,
185 &num_alerts));
186
187 if (num_alerts > 0) {
188 LOG_INFO("Alert class %c state: %d, acc_cnt: %d",
189 kAlertClassName[alert_class], state, num_alerts);
190
191 for (dif_alert_handler_alert_t alert = 0;
192 alert < ALERT_HANDLER_PARAM_N_ALERTS; ++alert) {
193 bool is_cause;
194 TRY(dif_alert_handler_alert_is_cause(alert_handler, alert, &is_cause));
195 if (is_cause) {
196 LOG_INFO("Alert %d is set", alert);
197 }
198 }
199
200 bool can_clear;
201 TRY(dif_alert_handler_escalation_can_clear(alert_handler, alert_class,
202 &can_clear));
203 if (can_clear) {
204 TRY(dif_alert_handler_escalation_clear(alert_handler, alert_class));
205 } else {
206 LOG_INFO("Alert class %c can't be cleared", kAlertClassName[alert_class]);
207 }
208 }
209
210 return OK_STATUS();
211}
212
213static status_t alert_handler_class_log(
214 const dif_alert_handler_t *alert_handler,
215 dif_alert_handler_class_t alert_class) {
217 TRY(dif_alert_handler_get_class_state(alert_handler, alert_class, &state));
218
219 uint16_t num_alerts;
220 TRY(dif_alert_handler_get_accumulator(alert_handler, alert_class,
221 &num_alerts));
222
223 if (num_alerts > 0) {
224 LOG_INFO("Alert class %c state: %d, acc_cnt: %d",
225 kAlertClassName[alert_class], state, num_alerts);
226 for (dif_alert_handler_alert_t alert = 0;
227 alert < ALERT_HANDLER_PARAM_N_ALERTS; ++alert) {
228 bool is_cause;
229 TRY(dif_alert_handler_alert_is_cause(alert_handler, alert, &is_cause));
230 if (is_cause) {
231 LOG_INFO("Alert %d is set", alert);
232 }
233 }
234 }
235
236 return OK_STATUS();
237}
238
239status_t alert_handler_testutils_status_log(
240 const dif_alert_handler_t *alert_handler) {
241 TRY_CHECK(alert_handler != NULL);
242
243 for (dif_alert_handler_class_t alert_class = 0;
244 alert_class < ALERT_HANDLER_PARAM_N_CLASSES; ++alert_class) {
245 TRY(alert_handler_class_log(alert_handler, alert_class));
246 }
247
248 return OK_STATUS();
249}
250
251status_t alert_handler_testutils_dump_log(const dif_rstmgr_t *rstmgr) {
252 TRY_CHECK(rstmgr != NULL);
253
255 size_t seg_size;
256 alert_handler_testutils_info_t actual_info;
257
258 uint32_t log_count = 0;
259
260 CHECK_DIF_OK(dif_rstmgr_alert_info_dump_read(
261 rstmgr, dump, DIF_RSTMGR_ALERT_INFO_MAX_SIZE, &seg_size));
262 CHECK(seg_size <= INT_MAX, "seg_size must fit in int");
263 CHECK_STATUS_OK(
264 alert_handler_testutils_info_parse(dump, (int)seg_size, &actual_info));
265
266 for (dif_alert_handler_class_t alert_class = 0;
267 alert_class < ALERT_HANDLER_PARAM_N_CLASSES; ++alert_class) {
268 if (actual_info.class_esc_state[alert_class] != kCstateIdle) {
269 LOG_INFO("crashdump - Alert class %c state: %d, acc_cnt: %d, esc_cnt: %d",
270 kAlertClassName[alert_class],
271 actual_info.class_esc_state[alert_class],
272 actual_info.class_accum_cnt[alert_class],
273 actual_info.class_esc_cnt[alert_class]);
274 log_count++;
275 }
276 }
277 for (dif_alert_handler_alert_t alert = 0;
278 alert < ALERT_HANDLER_PARAM_N_ALERTS; ++alert) {
279 if (actual_info.alert_cause[alert]) {
280 LOG_INFO("crashdump - Alert %d is set", alert);
281 log_count++;
282 }
283 }
284
285 if (log_count == 0) {
286 LOG_INFO("crashdump - No alerts reported");
287 }
288
289 return OK_STATUS();
290}
291
292status_t alert_handler_testutils_dump_enable(
293 const dif_alert_handler_t *alert_handler, const dif_rstmgr_t *rstmgr) {
294 TRY_CHECK(alert_handler != NULL);
295 TRY_CHECK(rstmgr != NULL);
296
297 uint32_t enable_count = 0;
298 for (dif_alert_handler_class_t alert_class = 0;
299 alert_class < ALERT_HANDLER_PARAM_N_CLASSES; ++alert_class) {
300 bool is_enabled;
301 TRY(dif_alert_handler_is_class_enabled(alert_handler, alert_class,
302 &is_enabled));
303 if (is_enabled) {
304 TRY(dif_alert_handler_crash_dump_trigger_set(
305 alert_handler, alert_class, kDifAlertHandlerClassStatePhase3));
306 enable_count++;
307 }
308 }
309
310 if (enable_count) {
311 CHECK_DIF_OK(dif_rstmgr_alert_info_set_enabled(rstmgr, kDifToggleEnabled));
312 }
313
314 return OK_STATUS();
315}