Software APIs
sensor_ctrl_alerts_test.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 
12 #include "sw/device/lib/runtime/irq.h"
14 #include "sw/device/lib/testing/pwrmgr_testutils.h"
15 #include "sw/device/lib/testing/rand_testutils.h"
16 #include "sw/device/lib/testing/ret_sram_testutils.h"
17 #include "sw/device/lib/testing/rstmgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
20 
22 #include "sensor_ctrl_regs.h" // Generated.
23 
24 OTTF_DEFINE_TEST_CONFIG();
25 
26 /**
27  * This test checks that incoming ast events can be
28  * configured as both recoverable and fatal.
29  * Further, this test checks that recoverable and fatal
30  * events are able to reach their proper alert_handler
31  * destination.
32  *
33  * Since fatal events do not stop firing once asserted,
34  * this test performs a self reset after every fatal
35  * event. In order to keep track of how far the test
36  * has advanced, a non-volatile counter in retention
37  * sram is used to track current progress.
38  */
39 static dif_rstmgr_t rstmgr;
40 static dif_sensor_ctrl_t sensor_ctrl;
41 static dif_alert_handler_t alert_handler;
42 
43 /**
44  * Clear event trigger and recoverable status.
45  */
46 static void clear_event(uint32_t idx, dif_toggle_t fatal) {
47  CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, idx,
49 
50  if (!dif_toggle_to_bool(fatal)) {
51  CHECK_DIF_OK(dif_sensor_ctrl_clear_recov_event(&sensor_ctrl, idx));
52  }
53 }
54 
55 static uint32_t get_events(dif_toggle_t fatal) {
56  dif_sensor_ctrl_events_t events = 0;
57  if (dif_toggle_to_bool(fatal)) {
58  CHECK_DIF_OK(dif_sensor_ctrl_get_fatal_events(&sensor_ctrl, &events));
59  } else {
60  CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
61  }
62  return events;
63 }
64 
65 /**
66  * Check alert cause registers are correctly set
67  */
68 static void check_alert_state(dif_toggle_t fatal) {
69  bool fatal_cause = false;
70  bool recov_cause = false;
71 
74  &fatal_cause));
75 
78  &recov_cause));
79 
80  if (dif_toggle_to_bool(fatal)) {
81  CHECK(fatal_cause & !recov_cause,
82  "Fatal alert not correctly observed in alert handler");
83  } else {
84  CHECK(recov_cause & !fatal_cause,
85  "Recov alert not correctly observed in alert handler");
86  }
87 
92 };
93 
94 /**
95  * First configure fatality of the desired event.
96  * Then trigger the event from sensor_ctrl to ast.
97  * Do this with the alert disabled and make sure there is no fault, and
98  * then enable it and expect a fault.
99  * Next poll for setting of correct events inside sensor_ctrl status.
100  * When a recoverable event is triggered, make sure only recoverable
101  * status is seen, likewise for fatal events.
102  * Finally, check for correct capture of cause in alert handler.
103  */
104 static void test_event(uint32_t idx, dif_toggle_t fatal) {
105  // Configure event fatality
106  CHECK_DIF_OK(dif_sensor_ctrl_set_alert_fatal(&sensor_ctrl, idx, fatal));
107 
108  LOG_INFO("Testing alert %d masked off", idx);
109  // Disable the alert on the sensor_ctrl side
110  CHECK_DIF_OK(
112 
113  // Trigger event
114  CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, idx,
116 
117  // There should be no fault so we cannot wait for CSR updates.
118  busy_spin_micros(20);
119 
120  dif_sensor_ctrl_events_t events = 0;
121  CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
122  CHECK(events == 0, "Event is disabled, so we expect no recoverable faults");
123  CHECK_DIF_OK(dif_sensor_ctrl_get_fatal_events(&sensor_ctrl, &events));
124  CHECK(events == 0, "Event is disabled, so we expect no fatal faults");
125 
126  LOG_INFO("Testing alert %d %s masked on", idx, fatal ? "fatal" : "recov");
127  // Enable the alert on the sensor_ctrl side
128  CHECK_DIF_OK(
129  dif_sensor_ctrl_set_alert_en(&sensor_ctrl, idx, kDifToggleEnabled));
130 
131  // wait for events to set
132  IBEX_SPIN_FOR(get_events(fatal) > 0, 1);
133 
134  // Check for the event in ast sensor_ctrl
135  // if the event is not set, error
136  CHECK(((get_events(fatal) >> idx) & 0x1) == 1, "Event %d not observed in AST",
137  idx);
138 
139  // check the opposite fatality setting, should not be set
140  CHECK(((get_events(!fatal) >> idx) & 0x1) == 0,
141  "Event %d observed in AST when it should not be", idx);
142 
143  // clear event trigger
144  clear_event(idx, fatal);
145 
146  // check whether alert handler captured the event
147  check_alert_state(fatal);
148 
149  // Disable the alert on the sensor_ctrl side
150  CHECK_DIF_OK(
152 };
153 
154 enum {
155  // Counter for event index.
156  kCounterEventIdx = 0,
157  // Counter for number of events tested.
158  kCounterNumTests = 0,
159  // Max number of events to test per run.
160  kNumTestsMax = SENSOR_CTRL_PARAM_NUM_ALERT_EVENTS >> 1,
161 };
162 
163 static uint32_t get_next_event_to_test(void) {
164  uint32_t event_idx;
165  // Reseed so that we don't see the same sequence after each reset.
166  rand_testutils_reseed();
167  do {
168  CHECK_STATUS_OK(
169  ret_sram_testutils_counter_get(kCounterEventIdx, &event_idx));
170  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterEventIdx));
171  // Drop each event randomly to reduce run time.
172  } while (rand_testutils_gen32() <= UINT32_MAX >> 1 &&
173  event_idx < SENSOR_CTRL_PARAM_NUM_ALERT_EVENTS);
174  return event_idx;
175 }
176 
177 bool test_main(void) {
178  // Initialize sensor_ctrl
179  CHECK_DIF_OK(dif_sensor_ctrl_init(
181  &sensor_ctrl));
182 
183  // Initialize alert_handler
184  CHECK_DIF_OK(dif_alert_handler_init(
186  &alert_handler));
187 
188  CHECK_DIF_OK(dif_rstmgr_init(
190 
191  // Enable both recoverable and fatal alerts
194  kDifAlertHandlerClassA, kDifToggleEnabled, kDifToggleEnabled));
197  kDifAlertHandlerClassA, kDifToggleEnabled, kDifToggleEnabled));
198 
199  // Check if there was a HW reset caused by expected cases.
201  rst_info = rstmgr_testutils_reason_get();
202  rstmgr_testutils_reason_clear();
203 
204  ret_sram_testutils_init();
205 
206  if (rst_info == kDifRstmgrResetInfoPor) {
207  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterEventIdx));
208  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterNumTests));
209  }
210 
211  // Make sure we do not try to test more than half of all available events
212  // in a single test. Testing too many would just make the run time too
213  // long.
214  uint32_t value = 0;
215  CHECK_STATUS_OK(ret_sram_testutils_counter_get(kCounterNumTests, &value));
216  uint32_t event_idx = get_next_event_to_test();
217  if (event_idx == SENSOR_CTRL_PARAM_NUM_ALERT_EVENTS ||
218  value >= kNumTestsMax) {
219  LOG_INFO("Tested all events");
220  return true;
221  } else {
222  LOG_INFO("Testing event %d", event_idx);
223  }
224 
225  // test recoverable event
226  test_event(event_idx, /*fatal*/ kDifToggleDisabled);
227 
228  // test fatal event
229  test_event(event_idx, /*fatal*/ kDifToggleEnabled);
230 
231  // increment non-volatile counter to know where we are
232  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterNumTests));
233 
234  // Now request system to reset and test again
235  LOG_INFO("Rebooting system");
236  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
238 
239  return false;
240 }