Software APIs
alert_handler_reverse_ping_in_deep_sleep_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 
5 #include <assert.h>
6 #include <limits.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 
19 #include "sw/device/lib/runtime/irq.h"
21 #include "sw/device/lib/testing/alert_handler_testutils.h"
22 #include "sw/device/lib/testing/aon_timer_testutils.h"
23 #include "sw/device/lib/testing/keymgr_testutils.h"
24 #include "sw/device/lib/testing/pwrmgr_testutils.h"
25 #include "sw/device/lib/testing/rstmgr_testutils.h"
26 #include "sw/device/lib/testing/rv_plic_testutils.h"
27 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
28 #include "sw/device/lib/testing/test_framework/check.h"
30 
31 #include "alert_handler_regs.h" // Generated.
32 
33 OTTF_DEFINE_TEST_CONFIG();
34 
35 enum {
36  // This time needs to be greater than 0.175s. See test plan for more details.
37  kTestParamWakeupThresholdUsec = 200000,
38 
39  // This time is needed to cycle through all the alert pings. See test plan
40  // for more details.
41  kTestParamCycleThroughAllPingsUsec = kTestParamWakeupThresholdUsec >> 2,
42  kTestParamAlertHandlerIrqDeadlineUsec = 100,
43  kTestParamAlertHandlerPhase0EscalationDurationUsec = 100,
44  kTestParamAlertHandlerPingTimeoutUsec = 20,
45 };
46 
47 static_assert(
48  kTestParamWakeupThresholdUsec > 175000,
49  "Invalid kTestParamWakeupThresholdUsec. See test plan for more details.");
50 
51 static const dt_pwrmgr_t kPwrmgrDt = 0;
52 static_assert(kDtPwrmgrCount == 1, "this test expects a pwrmgr");
53 static const dt_aon_timer_t kAonTimerDt = 0;
54 static_assert(kDtAonTimerCount >= 1,
55  "this test expects at least one aon_timer");
56 static const dt_rstmgr_t kRstmgrDt = 0;
57 static_assert(kDtPwrmgrCount == 1, "this test expects a rstmgr");
58 static const dt_alert_handler_t kAlertHandlerDt = 0;
59 static_assert(kDtAlertHandlerCount == 1, "this test expects an alert_handler");
60 static const dt_flash_ctrl_t kFlashCtrlDt = 0;
61 static_assert(kDtFlashCtrlCount == 1, "this test expects a flash_ctrl");
62 static const dt_rv_plic_t kRvPlicDt = 0;
63 static_assert(kDtRvPlicCount == 1, "this test expects exactly one rv_plic");
64 
65 static dif_flash_ctrl_state_t flash_ctrl;
66 static dif_rv_plic_t plic;
67 static dif_pwrmgr_t pwrmgr;
68 static dif_rstmgr_t rstmgr;
69 static dif_aon_timer_t aon_timer;
70 static dif_alert_handler_t alert_handler;
71 static const uint32_t kPlicTarget = 0;
72 
73 static volatile bool interrupt_serviced = false;
74 
75 /**
76  * Initialize the peripherals used in this test.
77  */
78 static void init_peripherals(void) {
79  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &plic));
80  CHECK_DIF_OK(dif_alert_handler_init_from_dt(kAlertHandlerDt, &alert_handler));
81  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
82  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr));
83  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
84 
85  CHECK_DIF_OK(dif_flash_ctrl_init_state_from_dt(&flash_ctrl, kFlashCtrlDt));
86 
87  // Enable all the alert_handler interrupts used in this test.
88  rv_plic_testutils_irq_range_enable(
89  &plic, kPlicTarget,
90  dt_alert_handler_irq_to_plic_id(kAlertHandlerDt,
91  kDtAlertHandlerIrqClassa),
92  dt_alert_handler_irq_to_plic_id(kAlertHandlerDt,
93  kDtAlertHandlerIrqClassd));
94 }
95 
96 /**
97  * Program the alert handler to escalate on alerts upto phase 1 (i.e. wipe
98  * secret) but not trigger reset. Then CPU can check if the correct interrupt
99  * fires and check the local alert cause register.
100  */
101 static void alert_handler_config(void) {
102  dif_alert_handler_alert_t alerts[ALERT_HANDLER_PARAM_N_ALERTS];
103  dif_alert_handler_class_t alert_classes[ALERT_HANDLER_PARAM_N_ALERTS];
104 
105  // Enable all incoming alerts and configure them to classa.
106  // This alert should never fire because we do not expect any incoming alerts.
107  for (dif_alert_handler_alert_t i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) {
108  alerts[i] = i;
109  alert_classes[i] = kDifAlertHandlerClassA;
110  }
111 
112  // Enable alert ping fail local alert and configure that to classb.
113  dif_alert_handler_local_alert_t loc_alerts[ALERT_HANDLER_PARAM_N_LOC_ALERT];
114  dif_alert_handler_class_t loc_alert_classes[ALERT_HANDLER_PARAM_N_LOC_ALERT];
116  i < ALERT_HANDLER_PARAM_N_LOC_ALERT; ++i) {
117  loc_alerts[i] = i;
118  loc_alert_classes[i] = kDifAlertHandlerClassB;
119  }
120  uint32_t cycles = 0;
121  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
122  kTestParamAlertHandlerPhase0EscalationDurationUsec, &cycles));
123  dif_alert_handler_escalation_phase_t esc_phases[] = {
124  {
126  .signal = 0,
127  .duration_cycles = cycles,
128  },
129  };
130 
131  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
132  kTestParamAlertHandlerIrqDeadlineUsec, &cycles));
133  dif_alert_handler_class_config_t class_config = {
135  .accumulator_threshold = 0,
136  .irq_deadline_cycles = cycles,
137  .escalation_phases = esc_phases,
138  .escalation_phases_len = ARRAYSIZE(esc_phases),
139  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1,
140  };
141 
142  dif_alert_handler_class_config_t class_configs[] = {class_config,
143  class_config};
144 
145  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA,
146  kDifAlertHandlerClassB};
147  CHECK_STATUS_OK(alert_handler_testutils_get_cycles_from_us(
148  kTestParamAlertHandlerPingTimeoutUsec, &cycles));
149  dif_alert_handler_config_t config = {
150  .alerts = alerts,
151  .alert_classes = alert_classes,
152  .alerts_len = ARRAYSIZE(alerts),
153  .local_alerts = loc_alerts,
154  .local_alert_classes = loc_alert_classes,
155  .local_alerts_len = ARRAYSIZE(loc_alerts),
156  .classes = classes,
157  .class_configs = class_configs,
158  .classes_len = ARRAYSIZE(class_configs),
159  .ping_timeout = cycles,
160  };
161 
162  CHECK_STATUS_OK(alert_handler_testutils_configure_all(&alert_handler, config,
164  // Enables alert handler irq.
165  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
166  &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled));
167 
168  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
169  &alert_handler, kDifAlertHandlerIrqClassb, kDifToggleEnabled));
170 }
171 
172 /**
173  * Ensure there were no local alerts fired.
174  */
175 static void check_local_alerts(void) {
177  i < ALERT_HANDLER_PARAM_N_LOC_ALERT; ++i) {
178  bool is_cause;
179  CHECK_DIF_OK(
180  dif_alert_handler_local_alert_is_cause(&alert_handler, i, &is_cause));
181  CHECK(!is_cause, "Unexpected local alert cause: %d", i);
182  }
183 }
184 
185 /**
186  * Resets the chip.
187  */
188 static void chip_sw_reset(void) {
189  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
190  busy_spin_micros(100);
191  CHECK(false, "Should have reset before this line");
192 }
193 
194 /**
195  * External ISR.
196  *
197  * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt
198  * line to the CPU, which results in a call to this OTTF ISR. This ISR
199  * overrides the default OTTF implementation.
200  */
201 void ottf_external_isr(uint32_t *exc_info) { interrupt_serviced = true; }
202 
203 bool test_main(void) {
204  init_peripherals();
205  dif_pwrmgr_request_sources_t wakeup_sources;
206  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
207  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_aon_timer_instance_id(kAonTimerDt),
208  kDtAonTimerWakeupWkupReq, &wakeup_sources));
209 
210  // We need to initialize the info FLASH partitions storing the Creator and
211  // Owner secrets to avoid getting the flash controller into a fatal error
212  // state.
213  if (kDeviceType == kDeviceFpgaCw310) {
214  dif_rstmgr_reset_info_bitfield_t rst_info = rstmgr_testutils_reason_get();
215  if (rst_info & kDifRstmgrResetInfoPor) {
216  CHECK_STATUS_OK(keymgr_testutils_flash_init(&flash_ctrl, &kCreatorSecret,
217  &kOwnerSecret));
218  chip_sw_reset();
219  }
220  }
221 
222  if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) == true) {
223  LOG_INFO("POR reset");
224 
226 
227  // Update the expected `reset_info` value for the FPGA target, as we have
228  // a soft reset required to apply the info flash page configuration.
229  if (kDeviceType == kDeviceFpgaCw310) {
230  reset_info = kDifRstmgrResetInfoSw;
231  }
232 
233  CHECK(UNWRAP(rstmgr_testutils_reset_info_any(&rstmgr, reset_info)));
234  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
235 
236  alert_handler_config();
237 
238  irq_global_ctrl(true);
239  irq_external_ctrl(true);
240 
241  uint64_t wakeup_threshold = 0;
242  CHECK_STATUS_OK(aon_timer_testutils_get_aon_cycles_64_from_us(
243  kTestParamWakeupThresholdUsec, &wakeup_threshold));
244 
245  // Sleep longer in FPGA and silicon targets.
247  uint64_t wakeup_threshold_new = wakeup_threshold * 50;
248  CHECK(wakeup_threshold_new > wakeup_threshold,
249  "Detected wakeup_threshold overflow.");
250  wakeup_threshold = wakeup_threshold_new;
251  }
252 
253  // Wait for the alert handler to cycle through all pings and make sure
254  // there were no interrupts fired during that time.
255  busy_spin_micros(kTestParamCycleThroughAllPingsUsec);
256  check_local_alerts();
257  CHECK(interrupt_serviced == false, "Unexpected interrupt triggered.");
258 
259  // Enable and enter deep sleep.
260  CHECK_STATUS_OK(
261  aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold));
262  CHECK_STATUS_OK(
263  pwrmgr_testutils_enable_low_power(&pwrmgr, wakeup_sources, 0));
265  CHECK(false, "Fail to enter in low power mode!");
266  OT_UNREACHABLE();
267  } else if (UNWRAP(pwrmgr_testutils_is_wakeup_reason(
268  &pwrmgr, wakeup_sources)) == true) {
269  LOG_INFO("Wakeup reset");
270  CHECK(UNWRAP(rstmgr_testutils_is_reset_info(
272  CHECK_STATUS_OK(aon_timer_testutils_shutdown(&aon_timer));
273 
274  // At this point the test has verified that the reset reason is low power
275  // exit, which discounts any resets triggered by local alert escalations.
276  // We check local alerts and interrupt flag one more time to ensure the
277  // alert handler resumes with the expected state.
278  check_local_alerts();
279  CHECK(interrupt_serviced == false, "Unexpected interrupt triggered.");
280  return true;
281  }
282  dif_pwrmgr_wakeup_reason_t wakeup_reason;
283  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
284  LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
285  wakeup_reason.types, wakeup_reason.request_sources);
286  return false;
287 }