Software APIs
alert_handler_lpg_clkoff_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 
23 #include "sw/device/lib/runtime/irq.h"
25 #include "sw/device/lib/testing/alert_handler_testutils.h"
26 #include "sw/device/lib/testing/rand_testutils.h"
27 #include "sw/device/lib/testing/ret_sram_testutils.h"
28 #include "sw/device/lib/testing/rstmgr_testutils.h"
29 #include "sw/device/lib/testing/rv_plic_testutils.h"
30 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
31 #include "sw/device/lib/testing/test_framework/check.h"
33 
34 #include "aes_regs.h"
35 #include "alert_handler_regs.h"
36 #include "hmac_regs.h"
38 #include "i2c_regs.h"
39 #include "kmac_regs.h"
40 #include "otbn_regs.h"
41 #include "spi_host_regs.h"
42 #include "sw/device/lib/testing/autogen/isr_testutils.h"
43 #include "usbdev_regs.h"
44 
45 OTTF_DEFINE_TEST_CONFIG();
46 
47 static dif_rv_plic_t plic;
48 static dif_alert_handler_t alert_handler;
49 static dif_clkmgr_t clkmgr;
50 static dif_spi_host_t spi_host0;
51 static dif_spi_host_t spi_host1;
52 static dif_usbdev_t usbdev;
53 static dif_aes_t aes;
54 static dif_hmac_t hmac;
55 static dif_kmac_t kmac;
56 static dif_otbn_t otbn;
57 static dif_rstmgr_t rstmgr;
58 
59 static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
60 
61 static plic_isr_ctx_t plic_ctx = {
62  .rv_plic = &plic,
63  .hart_id = kPlicTarget,
64 };
65 
66 /**
67  * Depends on the clock domain, sometimes alert handler will trigger a spurious
68  * alert after the alert timeout. (Issue #2321)
69  * So we allow class A interrupt to fire after the real timeout interrupt is
70  * triggered.
71  */
72 static alert_handler_isr_ctx_t alert_handler_ctx = {
73  .alert_handler = &alert_handler,
74  .plic_alert_handler_start_irq_id = kTopEarlgreyPlicIrqIdAlertHandlerClassa,
75  .expected_irq = kDifAlertHandlerIrqClassb,
76  .is_only_irq = false,
77 };
78 
79 /**
80  * Initialize the peripherals used in this test.
81  */
82 static void init_peripherals(void) {
83  mmio_region_t base_addr =
85  CHECK_DIF_OK(dif_rv_plic_init(base_addr, &plic));
86 
88  CHECK_DIF_OK(dif_alert_handler_init(base_addr, &alert_handler));
89 
90  CHECK_DIF_OK(dif_clkmgr_init(
92 
93  CHECK_DIF_OK(dif_spi_host_init(
95 
96  CHECK_DIF_OK(dif_spi_host_init(
98 
99  CHECK_DIF_OK(dif_usbdev_init(
101 
102  CHECK_DIF_OK(
104 
105  CHECK_DIF_OK(
106  dif_hmac_init(mmio_region_from_addr(TOP_EARLGREY_HMAC_BASE_ADDR), &hmac));
107 
108  CHECK_DIF_OK(
109  dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
110 
111  CHECK_DIF_OK(
112  dif_otbn_init(mmio_region_from_addr(TOP_EARLGREY_OTBN_BASE_ADDR), &otbn));
113 
114  CHECK_DIF_OK(dif_rstmgr_init(
116 }
117 
118 // List of alerts
119 static const uint32_t aes_alerts[] = {kTopEarlgreyAlertIdAesFatalFault,
121 static const uint32_t hmac_alerts[] = {kTopEarlgreyAlertIdHmacFatalFault};
122 static const uint32_t kmac_alerts[] = {
125 static const uint32_t otbn_alerts[] = {kTopEarlgreyAlertIdOtbnFatal,
127 static const uint32_t spihost0_alerts[] = {
129 static const uint32_t spihost1_alerts[] = {
131 static const uint32_t usbdev_alerts[] = {kTopEarlgreyAlertIdUsbdevFatalFault};
132 
133 static const uint32_t num_aes_alerts = ARRAYSIZE(aes_alerts);
134 static const uint32_t num_hmac_alerts = ARRAYSIZE(hmac_alerts);
135 static const uint32_t num_kmac_alerts = ARRAYSIZE(kmac_alerts);
136 static const uint32_t num_otbn_alerts = ARRAYSIZE(otbn_alerts);
137 static const uint32_t num_spihost0_alerts = ARRAYSIZE(spihost0_alerts);
138 static const uint32_t num_spihost1_alerts = ARRAYSIZE(spihost1_alerts);
139 static const uint32_t num_usbdev_alerts = ARRAYSIZE(usbdev_alerts);
140 
141 static const size_t num_alerts =
142  ARRAYSIZE(aes_alerts) + ARRAYSIZE(hmac_alerts) + ARRAYSIZE(kmac_alerts) +
143  ARRAYSIZE(otbn_alerts) + ARRAYSIZE(spihost0_alerts) +
144  ARRAYSIZE(spihost1_alerts) + ARRAYSIZE(usbdev_alerts);
145 
146 /**
147  * A structure to keep the info for peripheral IPs
148  */
149 typedef struct test {
150  /**
151  * Name of the peripheral.
152  */
153  const char *name;
154  /**
155  * Base address for the peripheral.
156  */
157  uintptr_t base;
158  /**
159  * Offset to the peripheral's ALERT_TEST register.
160  */
161  ptrdiff_t offset;
162  /**
163  * Handle to the DIF object for this peripheral.
164  */
165  void *dif;
166  /**
167  * The fatal_alert pin in peripheral's ALERT_TEST reg
168  */
169  uint32_t fatal_alert_bit;
170  /**
171  * List of Alert IDs for the peripheral
172  */
173  const uint32_t *alert_ids;
174  /**
175  * number of alerts for the peripheral
176  */
177  const uint32_t num_alert_peri;
178  /**
179  * The index of this device's clk in the clock manager.
180  */
181  uint32_t clk_index;
182  /**
183  * Is the clock hinteable (==true) or gateable(==false).
184  */
186 } test_t;
187 
188 // The array of the peripherals
189 static const test_t kPeripherals[] = {
190  // Hintable clock IPS
191  {
192  .name = "AES",
194  .offset = AES_ALERT_TEST_REG_OFFSET,
195  .dif = &aes,
196  .fatal_alert_bit = kDifAesAlertFatalFault,
197  .alert_ids = aes_alerts,
198  .num_alert_peri = num_aes_alerts,
200  .is_hintable = true,
201  },
202  {
203  .name = "HMAC",
205  .offset = HMAC_ALERT_TEST_REG_OFFSET,
206  .dif = &hmac,
207  .fatal_alert_bit = kDifHmacAlertFatalFault,
208  .alert_ids = hmac_alerts,
209  .num_alert_peri = num_hmac_alerts,
211  .is_hintable = true,
212  },
213  {
214  .name = "KMAC",
216  .offset = KMAC_ALERT_TEST_REG_OFFSET,
217  .dif = &kmac,
218  .fatal_alert_bit = kDifKmacAlertFatalFault,
219  .alert_ids = kmac_alerts,
220  .num_alert_peri = num_kmac_alerts,
222  .is_hintable = true,
223  },
224  {
225  .name = "OTBN",
227  .offset = OTBN_ALERT_TEST_REG_OFFSET,
228  .dif = &otbn,
229  .fatal_alert_bit = kDifOtbnAlertFatal,
230  .alert_ids = otbn_alerts,
231  .num_alert_peri = num_otbn_alerts,
233  .is_hintable = true,
234  },
235  // Gateable clock IPs
236  {
237  .name = "SPI_HOST0",
239  .offset = SPI_HOST_ALERT_TEST_REG_OFFSET,
240  .dif = &spi_host0,
241  .fatal_alert_bit = 0,
242  .alert_ids = spihost0_alerts,
243  .num_alert_peri = num_spihost0_alerts,
245  .is_hintable = false,
246  },
247  {
248  .name = "SPI_HOST1",
250  .offset = SPI_HOST_ALERT_TEST_REG_OFFSET,
251  .dif = &spi_host1,
252  .fatal_alert_bit = 0,
253  .alert_ids = spihost1_alerts,
254  .num_alert_peri = num_spihost1_alerts,
256  .is_hintable = false,
257  },
258  {
259  .name = "USB",
261  .offset = USBDEV_ALERT_TEST_REG_OFFSET,
262  .dif = &usbdev,
263  .fatal_alert_bit = 0,
264  .alert_ids = usbdev_alerts,
265  .num_alert_peri = num_usbdev_alerts,
267  .is_hintable = false,
268  },
269 };
270 
271 /**
272  * Configure and enable alerts of `num_peripheral` peripherals starting from the
273  * `first_peripheral`.
274  * @param num_peripherals The number of peripherals, of which alerts will be
275  * enabled
276  * @param first_peripheral The address of the first peripheral in the range
277  * @param ping_timeout The timeout value for the ping timer object.
278  */
279 static void alert_handler_config_peripherals(uint32_t num_peripherals,
280  const test_t *first_peripheral,
281  uint32_t ping_timeout) {
282  dif_alert_handler_alert_t alerts[num_alerts];
283  dif_alert_handler_class_t alert_classes[num_alerts];
284 
285  // Enable all alerts coming from the chosen peripherals
286  // Configure them as Class A.
287  size_t array_idx = 0;
288  for (int ii = 0; ii < num_peripherals; ii++) {
289  const test_t *peri_ptr = &first_peripheral[ii];
290  for (int jj = 0; jj < peri_ptr->num_alert_peri; jj++) {
291  alerts[array_idx] = peri_ptr->alert_ids[jj];
292  alert_classes[array_idx] = kDifAlertHandlerClassA;
293  array_idx++;
294  }
295  }
296 
297  // Enable the alert_ping_fail local alert and configure that as Class B.
298  dif_alert_handler_local_alert_t loc_alerts[] = {
299  kDifAlertHandlerLocalAlertAlertPingFail};
300  dif_alert_handler_class_t loc_alert_classes[] = {kDifAlertHandlerClassB};
301 
302  dif_alert_handler_escalation_phase_t esc_phases[] = {
304  .signal = 0,
305  .duration_cycles = 2000}};
306 
307  dif_alert_handler_class_config_t class_config = {
309  .accumulator_threshold = 0,
310  .irq_deadline_cycles = 10000,
311  .escalation_phases = esc_phases,
312  .escalation_phases_len = ARRAYSIZE(esc_phases),
313  .crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1,
314  };
315 
316  dif_alert_handler_class_config_t class_configs[] = {class_config,
317  class_config};
318 
319  dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA,
320  kDifAlertHandlerClassB};
321  dif_alert_handler_config_t config = {
322  .alerts = alerts,
323  .alert_classes = alert_classes,
324  .alerts_len = array_idx,
325  .local_alerts = loc_alerts,
326  .local_alert_classes = loc_alert_classes,
327  .local_alerts_len = ARRAYSIZE(loc_alerts),
328  .classes = classes,
329  .class_configs = class_configs,
330  .classes_len = ARRAYSIZE(class_configs),
331  .ping_timeout = ping_timeout,
332  };
333 
334  CHECK_STATUS_OK(alert_handler_testutils_configure_all(&alert_handler, config,
336  // Enables alert handler irq.
337  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
338  &alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled));
339 
340  CHECK_DIF_OK(dif_alert_handler_irq_set_enabled(
341  &alert_handler, kDifAlertHandlerIrqClassb, kDifToggleEnabled));
342 }
343 
344 /**
345  * A utility function to enable/disable hintable and gateable clocks
346  */
347 void set_peripheral_clock(const test_t *peripheral,
348  dif_toggle_t new_clk_state) {
349  dif_toggle_t clk_state;
350  if (peripheral->is_hintable) {
351  // Set the new clock state
353  &clkmgr, peripheral->clk_index, new_clk_state));
354  // Verify the new clock state
356  &clkmgr, peripheral->clk_index, &clk_state));
357  CHECK(clk_state == new_clk_state,
358  "intended_clk_state = %d, received_clk_state = %d", new_clk_state,
359  clk_state);
360 
361  } else {
363  &clkmgr, peripheral->clk_index, new_clk_state));
364  // Verify the new clock state
366  &clkmgr, peripheral->clk_index, &clk_state));
367  CHECK(clk_state == new_clk_state,
368  "intended_clk_state = %d, received_clk_state = %d", new_clk_state,
369  clk_state);
370  }
371 }
372 /**
373  * A utility function to wait enough until the alert handler pings a peripheral
374  * alert
375  */
376 void wait_enough_for_alert_ping(void) {
377  // wait enough
378  if (kDeviceType == kDeviceFpgaCw310) {
379  // NUM_ALERTS*2*margin_of_safety*(2**DW)*(1/kClockFreqPeripheralHz)
380  // (2**6)*2*4*(2**16)*(400ns) = 12.8s
381  busy_spin_micros(1000 * 12800);
382  } else if (kDeviceType == kDeviceSimDV) {
383  // NUM_ALERTS*2*margin_of_safety*(2**DW)*(1/kClockFreqPeripheralHz)
384  // (2**6)*2*4*(2**3)*(40ns) = 160us
385  busy_spin_micros(160);
386  } else {
387  // Verilator
388  // NUM_ALERTS*2*margin_of_safety*(2**DW)*(1/kClockFreqPeripheralHz)
389  // (2**6)*2*4*(2**16)*(8us) = 256s
390  // This seems to be impractical for the current clock frequency config
391  // of the Verilator tests (kClockFreqPeripheralHz = 125K).
392  LOG_FATAL("SUPPORTED PLATFORMS: DV and FPGA");
393  LOG_FATAL("TO SUPPORT THE PLATFORM %d, COMPUTE THE RIGHT WAIT-TIME",
394  kDeviceType);
395  }
396 }
397 
398 /**
399  * External ISR.
400  *
401  * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt
402  * line to the CPU, which results in a call to this OTTF ISR. This ISR
403  * overrides the default OTTF implementation.
404  */
405 void ottf_external_isr(uint32_t *exc_info) {
406  top_earlgrey_plic_peripheral_t peripheral_serviced;
407  dif_alert_handler_irq_t irq_serviced;
408  isr_testutils_alert_handler_isr(plic_ctx, alert_handler_ctx,
409  &peripheral_serviced, &irq_serviced);
410  CHECK(peripheral_serviced == kTopEarlgreyPlicPeripheralAlertHandler,
411  "Interrupt from unexpected peripheral: %d", peripheral_serviced);
412 }
413 
414 enum {
415  // Non-volatile counter for the test steps on FPGA.
416  kCounterTestSteps = 0,
417 };
418 
419 // This function will run after every device reset
420 bool test_main(void) {
421  init_peripherals();
422 
423  ret_sram_testutils_init();
424 
425  // The test consists of multiple test phases
426  // Each test phase consists of ARRAYSIZE(kPeripherals) steps
427  // At every step, a specific peripheral is tested
428  size_t test_phase;
429  size_t test_step_cnt;
430  size_t peri_idx;
431 
433  rst_info = rstmgr_testutils_reason_get();
434  rstmgr_testutils_reason_clear();
435  if (rst_info & kDifRstmgrResetInfoPor) {
436  // Initialize retention sram counters if running on Cw310.
437  if (kDeviceType == kDeviceFpgaCw310) {
438  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(kCounterTestSteps));
439  CHECK_STATUS_OK(
440  ret_sram_testutils_counter_get(kCounterTestSteps, &test_step_cnt));
441  }
442  }
443  // To keep the test results
444  bool is_cause;
445 
446  // Need a NVM counter to keep the test-step info
447  // between resets on the FPGA.
448  if (kDeviceType == kDeviceFpgaCw310) {
449  CHECK_STATUS_OK(
450  ret_sram_testutils_counter_get(kCounterTestSteps, &test_step_cnt));
451  } else {
452  // Initialize the test_step counter to zero for the simulation
453  test_step_cnt = 0;
454  }
455 
456  /* TEST PHASE #0: NEGATIVE TESTING (FPGA-ONLY)
457 
458  The timeout value is set to 2
459  All of the alerts should trigger ping_timeout_alert
460  if they are not clock_gated
461  TEST: for_each_peripheral
462  1- Disable the clock
463  2- Enable the corresponding alerts
464  3- Wait long enough
465  4- Confirm that ping_timeout has not been triggered
466  5- Reset the device to test the next peripheral
467  */
468  while (test_step_cnt < 1 * ARRAYSIZE(kPeripherals)) {
469  // Run the negative test only on the FPGA
470  // This will save the test time in the simulation
471  LOG_INFO("Phase 0");
472  if (kDeviceType == kDeviceFpgaCw310) {
473  // Read the test_step_cnt and compute the test phase
474  // and the peripheral ID to test
475  CHECK_STATUS_OK(
476  ret_sram_testutils_counter_get(kCounterTestSteps, &test_step_cnt));
477  test_phase = test_step_cnt / ARRAYSIZE(kPeripherals);
478  peri_idx = test_step_cnt - (test_phase)*ARRAYSIZE(kPeripherals);
479  LOG_INFO("Testing peripheral %d", peri_idx);
480 
481  // Wait for a random time <= 1024us
482  busy_spin_micros(rand_testutils_gen32_range(1, 1024));
483 
484  // Disable the clock of the peripheral
485  set_peripheral_clock(&kPeripherals[peri_idx], kDifToggleDisabled);
486 
487  alert_handler_config_peripherals(
488  /*num_peripherals*/ 1, /* *first_peripheral*/ &kPeripherals[peri_idx],
489  /*ping_timeout*/ 2);
490 
491  // wait enough until the alert handler pings the peripheral
492  wait_enough_for_alert_ping();
493 
494  // Check the ping_timeout alert status
496  &alert_handler, kDifAlertHandlerLocalAlertAlertPingFail, &is_cause));
497  CHECK(!is_cause,
498  "Expected response is ping_timeout_fail == 0! But we got "
499  "ping_timeout_fail = 1 for peripheral[%d]",
500  peri_idx);
501 
502  // Enable the clock again
503  set_peripheral_clock(&kPeripherals[peri_idx], kDifToggleEnabled);
504 
505  // Increment the test_step counter
506  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(kCounterTestSteps));
507  // Request system reset to unlock the alert handler config and test the
508  // next peripheral
509  CHECK_DIF_OK(dif_rstmgr_software_device_reset(&rstmgr));
510  } else {
511  // For the simulation, only increment the test_step counter
512  // to proceed to the next phase without resetting the device
513  test_step_cnt++;
514  }
515  }
516 
517  /* TEST PHASE #1: TEST THE REGULAR CONFIG
518 
519  The timeout value is set to 256
520  None of the alerts should trigger ping_timeout_alert
521  TEST:
522  enable_alerts (all_peripherals, timeout=256)
523  for_each_peripheral
524  1- wait for random time
525  2- Disable the peripheral's clock
526  3- Wait long enough
527  4- Confirm that ping_timeout has not been triggered
528  */
529 
530  // Enable and lock the all peripherals' alerts at the beginning of the PHASE
531  // #1
532  LOG_INFO("Phase 1");
533  if (test_step_cnt == 1 * ARRAYSIZE(kPeripherals)) {
534  alert_handler_config_peripherals(
535  /*num_peripherals*/ ARRAYSIZE(kPeripherals),
536  /* *first_peripheral*/ &kPeripherals[0], /*ping_timeout*/ 256);
537  }
538 
539  while (test_step_cnt < 2 * ARRAYSIZE(kPeripherals)) {
540  // Read the test_step_cnt and compute the test phase
541  // amd the peripheral ID to test
542  test_phase = test_step_cnt / ARRAYSIZE(kPeripherals);
543  peri_idx = test_step_cnt - (test_phase)*ARRAYSIZE(kPeripherals);
544 
545  // Wait for a random time <= 1024us
546  busy_spin_micros(rand_testutils_gen32_range(1, 1024));
547 
548  // Disable the clock of the peripheral
549  set_peripheral_clock(&kPeripherals[peri_idx], kDifToggleDisabled);
550 
551  // wait enough until the alert handler pings the peripheral
552  wait_enough_for_alert_ping();
553 
554  // Check the alert status
556  &alert_handler, kDifAlertHandlerLocalAlertAlertPingFail, &is_cause));
557  CHECK(!is_cause, "Expected response: No alert_ping_fail! but we got %d",
558  is_cause);
559 
560  // Enable the clock of the peripheral again
561  set_peripheral_clock(&kPeripherals[peri_idx], kDifToggleEnabled);
562 
563  // Increment the test counter
564  test_step_cnt++;
565  }
566 
567  return true;
568 }