Software APIs
watchdog_functest.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 <stdbool.h>
6 #include <stdint.h>
7 
14 #include "sw/device/lib/testing/rstmgr_testutils.h"
15 #include "sw/device/lib/testing/test_framework/check.h"
18 #include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
19 #include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
20 #include "sw/device/silicon_creator/lib/drivers/watchdog.h"
21 #include "sw/device/silicon_creator/lib/error.h"
22 
24 #include "rstmgr_regs.h"
25 
26 static uint32_t compute_ticks_per_ms(uint64_t hz) {
27  const uint64_t kTicksPerMs = udiv64_slow(hz, 1000, NULL);
28  CHECK(kTicksPerMs <= UINT32_MAX, "kTicksPerMs exceeds UINT32_MAX");
29  return (uint32_t)kTicksPerMs;
30 }
31 
32 // Tests that we can pet the watchdog and avoid a reset.
33 static rom_error_t watchdog_pet_test(void) {
34  // Set watchdog bite threshold to 5ms.
35  uint32_t bite_threshold = 5 * compute_ticks_per_ms(kClockFreqAonHz);
36  uint32_t bark_threshold = 9 * bite_threshold / 8;
37  LOG_INFO("bite threshold = %d", bite_threshold);
38  LOG_INFO("bark threshold = %d", bark_threshold);
39  watchdog_configure((watchdog_config_t){
40  .bite_threshold = bite_threshold,
41  .bark_threshold = bark_threshold,
42  .enable = kHardenedBoolTrue,
43  });
44 
45  for (size_t i = 0; i < 10; ++i) {
46  watchdog_pet();
47 
48  // Sleep for 1ms.
49  busy_spin_micros(1 * 1000);
50  }
51  watchdog_disable();
52  return kErrorOk;
53 }
54 
55 // Tests that we can configure the watchdog in a disabled state.
56 static rom_error_t watchdog_configure_disabled_test(void) {
57  // Set watchdog bite threshold to 1ms.
58  uint32_t threshold = 1 * compute_ticks_per_ms(kClockFreqAonHz);
59  LOG_INFO("threshold = %d", threshold);
60  watchdog_configure((watchdog_config_t){
61  .bite_threshold = threshold,
62  .bark_threshold = threshold,
63  .enable = kHardenedBoolFalse,
64  });
65 
66  // Sleep for 5ms.
67  busy_spin_micros(5 * 1000);
68  return kErrorOk;
69 }
70 
71 // Tests that if we neglect the dog, it will bite and reset the chip.
72 static rom_error_t watchdog_bite_test(void) {
73  // Set watchdog bite threshold to 5ms.
74  uint32_t bite_threshold = 5 * compute_ticks_per_ms(kClockFreqAonHz);
75  uint32_t bark_threshold = 9 * bite_threshold / 8;
76  LOG_INFO("bite threshold = %d", bite_threshold);
77  LOG_INFO("bark threshold = %d", bark_threshold);
78  watchdog_configure((watchdog_config_t){
79  .bite_threshold = bite_threshold,
80  .bark_threshold = bark_threshold,
81  .enable = kHardenedBoolTrue,
82  });
83 
84  // Sleep for 6ms.
85  busy_spin_micros(6 * 1000);
86 
87  watchdog_disable();
88  return kErrorUnknown;
89 }
90 
91 OTTF_DEFINE_TEST_CONFIG();
92 
93 // The test phases are tracked in retention RAM so that we ensure the reset
94 // happened in the correct phase of the test.
95 typedef enum TestPhase {
96  kTestPhaseInit = 0,
97  kTestPhasePet,
98  kTestPhaseDisable,
99  kTestPhaseBite,
100  kTestPhaseDone,
101 } test_phase_t;
102 
103 bool test_main(void) {
104  status_t result = OK_STATUS();
105  uint32_t reason = rstmgr_testutils_reason_get();
106  rstmgr_alert_info_enable();
107  LOG_INFO("reset_info = %08x", reason);
108 
109  // Clear the existing reset reason(s) so that they do not appear after the
110  // next reset.
111  rstmgr_testutils_reason_clear();
112 
113  // Use the part of the retention SRAM reserved for the silicon owner to
114  // store the test phase.
115  uint32_t *phase = &retention_sram_get()->owner.reserved[0];
116 
117  if (bitfield_bit32_read(reason, kRstmgrReasonPowerOn)) {
118  sec_mmio_init();
119 
120  // Power-on: zero out the retention RAM.
121  retention_sram_clear();
122 
123  *phase = kTestPhasePet;
124  EXECUTE_TEST(result, watchdog_pet_test);
125 
126  *phase = kTestPhaseDisable;
127  EXECUTE_TEST(result, watchdog_configure_disabled_test);
128 
129  *phase = kTestPhaseBite;
130  EXECUTE_TEST(result, watchdog_bite_test);
131 
132  *phase = kTestPhaseDone;
133  LOG_ERROR("Test failure: should have reset before this line.");
134  } else if (bitfield_bit32_read(reason, kRstmgrReasonWatchdog)) {
135  LOG_INFO("Detected reset after escalation test");
136  if (*phase != kTestPhaseBite) {
137  LOG_ERROR("Test failure: expected phase %d but got phase %d",
138  kTestPhaseBite, *phase);
139  result = UNKNOWN();
140  } else {
141  result = OK_STATUS();
142  }
143  } else {
144  LOG_ERROR("Unknown reset reason");
145  result = UNKNOWN();
146  }
147  return status_ok(result);
148 }