Software APIs
dif_alert_handler.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 
6 
7 #include <assert.h>
8 #include <limits.h>
9 
11 
12 #include "alert_handler_regs.h" // Generated.
13 
14 static_assert(ALERT_HANDLER_PARAM_N_CLASSES == 4,
15  "Expected four alert classes!");
16 static_assert(ALERT_HANDLER_PARAM_N_ESC_SEV == 4,
17  "Expected four escalation signals!");
18 static_assert(ALERT_HANDLER_PARAM_N_PHASES == 4,
19  "Expected four escalation phases!");
20 static_assert(ALERT_HANDLER_PARAM_N_LOC_ALERT == 7,
21  "Expected seven local alerts!");
22 
23 // Enable, class, lock, and cause multiregs for alerts.
24 static_assert(ALERT_HANDLER_ALERT_EN_SHADOWED_MULTIREG_COUNT &&
25  ALERT_HANDLER_ALERT_EN_SHADOWED_EN_A_FIELD_WIDTH == 1 &&
26  ALERT_HANDLER_ALERT_EN_SHADOWED_0_EN_A_0_BIT == 0,
27  "Expected alert enables to be multiregs with LSB at index 0!");
28 static_assert(ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT &&
29  ALERT_HANDLER_ALERT_CLASS_SHADOWED_CLASS_A_FIELD_WIDTH == 2 &&
30  ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_OFFSET == 0,
31  "Expected alert class CSRs to be multiregs with LSB at index 0!");
32 static_assert(ALERT_HANDLER_ALERT_REGWEN_MULTIREG_COUNT &&
33  ALERT_HANDLER_ALERT_REGWEN_EN_FIELD_WIDTH == 1 &&
34  ALERT_HANDLER_ALERT_REGWEN_0_EN_0_BIT == 0,
35  "Expected alert locks to be multiregs with LSB at index 0!");
36 static_assert(ALERT_HANDLER_ALERT_CAUSE_MULTIREG_COUNT &&
37  ALERT_HANDLER_ALERT_CAUSE_A_FIELD_WIDTH == 1 &&
38  ALERT_HANDLER_ALERT_CAUSE_0_A_0_BIT == 0,
39  "Expected alert causes to be multiregs with LSB at index 0!");
40 
41 // Enable, class, lock, and cause multiregs for local alerts.
42 static_assert(
43  ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_MULTIREG_COUNT &&
44  ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_EN_LA_FIELD_WIDTH == 1 &&
45  ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_EN_LA_0_BIT == 0,
46  "Expected local alert enables to be multiregs with LSB at index 0!");
47 static_assert(
48  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT &&
49  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_CLASS_LA_FIELD_WIDTH == 2 &&
50  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_OFFSET == 0,
51  "Expected local alert class CSRs to be multiregs with LSB at index 0!");
52 static_assert(
53  ALERT_HANDLER_LOC_ALERT_REGWEN_MULTIREG_COUNT &&
54  ALERT_HANDLER_LOC_ALERT_REGWEN_EN_FIELD_WIDTH == 1 &&
55  ALERT_HANDLER_LOC_ALERT_REGWEN_0_EN_0_BIT == 0,
56  "Expected local alert locks to be multiregs with LSB at index 0!");
57 static_assert(
58  ALERT_HANDLER_LOC_ALERT_CAUSE_MULTIREG_COUNT &&
59  ALERT_HANDLER_LOC_ALERT_CAUSE_LA_FIELD_WIDTH == 1 &&
60  ALERT_HANDLER_LOC_ALERT_CAUSE_0_LA_0_BIT == 0,
61  "Expected local alert causes to be multiregs with LSB at index 0!");
62 
63 // Accumulator threshold field sizes.
64 static_assert(
65  ALERT_HANDLER_CLASSA_ACCUM_THRESH_SHADOWED_CLASSA_ACCUM_THRESH_SHADOWED_MASK <=
66  USHRT_MAX,
67  "Expected class A accumulator threshold field to be 16 bits.");
68 static_assert(
69  ALERT_HANDLER_CLASSB_ACCUM_THRESH_SHADOWED_CLASSB_ACCUM_THRESH_SHADOWED_MASK <=
70  USHRT_MAX,
71  "Expected class B accumulator threshold field to be 16 bits.");
72 static_assert(
73  ALERT_HANDLER_CLASSC_ACCUM_THRESH_SHADOWED_CLASSC_ACCUM_THRESH_SHADOWED_MASK <=
74  USHRT_MAX,
75  "Expected class C accumulator threshold field to be 16 bits.");
76 static_assert(
77  ALERT_HANDLER_CLASSD_ACCUM_THRESH_SHADOWED_CLASSD_ACCUM_THRESH_SHADOWED_MASK <=
78  USHRT_MAX,
79  "Expected class D accumulator threshold field to be 16 bits.");
80 
81 /**
82  * Macro for generating the case statements for local alert cause CSRs.
83  */
84 #define LOC_ALERT_CAUSE_REGS_CASE_(loc_alert_, value_) \
85  case loc_alert_: \
86  cause_reg_offset = ALERT_HANDLER_LOC_ALERT_CAUSE_##value_##_REG_OFFSET; \
87  break;
88 
89 /**
90  * Macro for generating the case statements for local alert lock CSRs.
91  */
92 #define LOC_ALERT_REGWENS_CASE_(loc_alert_, value_) \
93  case loc_alert_: \
94  regwen_offset = ALERT_HANDLER_LOC_ALERT_REGWEN_##value_##_REG_OFFSET; \
95  break;
96 
97 /**
98  * Macro for generating the case statements for class lock CSRs.
99  */
100 #define ALERT_CLASS_REGWENS_CASE_(class_, value_) \
101  case kDifAlertHandlerClass##class_: \
102  regwen_offset = ALERT_HANDLER_CLASS##class_##_REGWEN_REG_OFFSET; \
103  break;
104 
105 /**
106  * Macro for generating the case statements for class clear lock CSRs.
107  */
108 #define ALERT_CLASS_CLEAR_REGWENS_CASE_(class_, value_) \
109  case kDifAlertHandlerClass##class_: \
110  regwen_offset = ALERT_HANDLER_CLASS##class_##_CLR_REGWEN_REG_OFFSET; \
111  break;
112 
113 /**
114  * We use this to convert the class enum to the integer value that is
115  * assigned to each class in auto-generated register header file. We do this
116  * to make this code robust against changes to the class values in the
117  * auto-generated register header file.
118  */
120 static bool class_to_uint32(dif_alert_handler_class_t alert_class,
121  uint32_t *classification) {
122 #define ALERT_CLASS_REGS_CASE_(class_, value_) \
123  case kDifAlertHandlerClass##class_: \
124  *classification = \
125  ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASS##class_; \
126  break;
127  switch (alert_class) {
128  LIST_OF_CLASSES(ALERT_CLASS_REGS_CASE_)
129  default:
130  return false;
131  }
132 
133 #undef ALERT_CLASS_REGS_CASE_
134 
135  return true;
136 }
137 
139 static bool is_valid_escalation_phase(dif_alert_handler_class_state_t phase) {
140  if (phase < kDifAlertHandlerClassStatePhase0 ||
142  return false;
143  }
144  return true;
145 }
146 
147 /**
148  * NOTE: the alert ID corresponds directly to the multireg index for each CSR.
149  * (I.e., alert N has enable multireg N).
150  */
152  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
153  dif_alert_handler_class_t alert_class, dif_toggle_t enabled,
154  dif_toggle_t locked) {
155  if (alert_handler == NULL || alert >= ALERT_HANDLER_PARAM_N_ALERTS ||
156  !dif_is_valid_toggle(enabled) || !dif_is_valid_toggle(locked)) {
157  return kDifBadArg;
158  }
159  uint32_t classification;
160  if (!class_to_uint32(alert_class, &classification)) {
161  return kDifBadArg;
162  }
163 
164  // Check if configuration is locked.
165  ptrdiff_t regwen_offset = ALERT_HANDLER_ALERT_REGWEN_0_REG_OFFSET +
166  (ptrdiff_t)alert * (ptrdiff_t)sizeof(uint32_t);
167  if (!mmio_region_read32(alert_handler->base_addr, regwen_offset)) {
168  return kDifLocked;
169  }
170 
171  // Classify the alert.
172  ptrdiff_t class_reg_offset = ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET +
173  (ptrdiff_t)alert * (ptrdiff_t)sizeof(uint32_t);
174  mmio_region_write32_shadowed(alert_handler->base_addr, class_reg_offset,
175  classification);
176 
177  // Enable the alert.
178  ptrdiff_t enable_reg_offset = ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET +
179  (ptrdiff_t)alert * (ptrdiff_t)sizeof(uint32_t);
180  mmio_region_write32_shadowed(alert_handler->base_addr, enable_reg_offset,
181  0x1);
182 
183  // Lock the configuration.
184  if (locked == kDifToggleEnabled) {
185  mmio_region_write32(alert_handler->base_addr, regwen_offset, 0);
186  }
187 
188  return kDifOk;
189 }
190 
192  const dif_alert_handler_t *alert_handler,
194  dif_alert_handler_class_t alert_class, dif_toggle_t enabled,
195  dif_toggle_t locked) {
196  if (alert_handler == NULL || !dif_is_valid_toggle(enabled) ||
197  !dif_is_valid_toggle(locked)) {
198  return kDifBadArg;
199  }
200  uint32_t classification;
201  if (!class_to_uint32(alert_class, &classification)) {
202  return kDifBadArg;
203  }
204 
205 #define LOC_ALERT_REGS_CASE_(loc_alert_, value_) \
206  case loc_alert_: \
207  enable_reg_offset = \
208  ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_##value_##_REG_OFFSET; \
209  class_reg_offset = \
210  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_##value_##_REG_OFFSET; \
211  regwen_offset = ALERT_HANDLER_LOC_ALERT_REGWEN_##value_##_REG_OFFSET; \
212  break;
213 
214  // Get register/field offsets for local alert type.
215  ptrdiff_t enable_reg_offset;
216  ptrdiff_t class_reg_offset;
217  ptrdiff_t regwen_offset;
218  switch (local_alert) {
219  LIST_OF_LOC_ALERTS(LOC_ALERT_REGS_CASE_)
220  default:
221  return kDifBadArg;
222  }
223 
224 #undef LOC_ALERT_REGS_CASE_
225 
226  // Check if configuration is locked.
227  if (!mmio_region_read32(alert_handler->base_addr, regwen_offset)) {
228  return kDifLocked;
229  }
230 
231  // Classify the alert.
232  mmio_region_write32_shadowed(alert_handler->base_addr, class_reg_offset,
233  classification);
234 
235  // Enable the alert.
236  // NOTE: the alert ID corresponds directly to the multireg index.
237  // (I.e., alert N has enable multireg N).
238  mmio_region_write32_shadowed(alert_handler->base_addr, enable_reg_offset,
239  0x1);
240 
241  // Lock the configuration.
242  if (locked == kDifToggleEnabled) {
243  mmio_region_write32(alert_handler->base_addr, regwen_offset, 0);
244  }
245 
246  return kDifOk;
247 }
248 
250  const dif_alert_handler_t *alert_handler,
251  dif_alert_handler_class_t alert_class,
253  dif_toggle_t locked) {
254  if (alert_handler == NULL ||
256  (config.escalation_phases == NULL && config.escalation_phases_len != 0) ||
257  (config.escalation_phases != NULL && config.escalation_phases_len == 0) ||
258  !is_valid_escalation_phase(config.crashdump_escalation_phase) ||
259  !dif_is_valid_toggle(enabled) || !dif_is_valid_toggle(locked)) {
260  return kDifBadArg;
261  }
262  for (int i = 0; i < config.escalation_phases_len; ++i) {
263  switch (config.escalation_phases[i].phase) {
268  continue;
269  break;
270  default:
271  return kDifBadArg;
272  }
273  }
274 
275 #define ALERT_CLASS_CONFIG_REGS_CASE_(class_, value_) \
276  case kDifAlertHandlerClass##class_: \
277  class_regwen_offset = ALERT_HANDLER_CLASS##class_##_REGWEN_REG_OFFSET; \
278  ctrl_reg_offset = ALERT_HANDLER_CLASS##class_##_CTRL_SHADOWED_REG_OFFSET; \
279  accum_thresh_reg_offset = \
280  ALERT_HANDLER_CLASS##class_##_ACCUM_THRESH_SHADOWED_REG_OFFSET; \
281  irq_deadline_reg_offset = \
282  ALERT_HANDLER_CLASS##class_##_TIMEOUT_CYC_SHADOWED_REG_OFFSET; \
283  phase0_cycles_reg_offset = \
284  ALERT_HANDLER_CLASS##class_##_PHASE0_CYC_SHADOWED_REG_OFFSET; \
285  phase1_cycles_reg_offset = \
286  ALERT_HANDLER_CLASS##class_##_PHASE1_CYC_SHADOWED_REG_OFFSET; \
287  phase2_cycles_reg_offset = \
288  ALERT_HANDLER_CLASS##class_##_PHASE2_CYC_SHADOWED_REG_OFFSET; \
289  phase3_cycles_reg_offset = \
290  ALERT_HANDLER_CLASS##class_##_PHASE3_CYC_SHADOWED_REG_OFFSET; \
291  crashdump_phase_reg_offset = \
292  ALERT_HANDLER_CLASS##class_##_CRASHDUMP_TRIGGER_SHADOWED_REG_OFFSET; \
293  break;
294 
295  ptrdiff_t class_regwen_offset;
296  ptrdiff_t ctrl_reg_offset;
297  ptrdiff_t accum_thresh_reg_offset;
298  ptrdiff_t irq_deadline_reg_offset;
299  ptrdiff_t phase0_cycles_reg_offset;
300  ptrdiff_t phase1_cycles_reg_offset;
301  ptrdiff_t phase2_cycles_reg_offset;
302  ptrdiff_t phase3_cycles_reg_offset;
303  ptrdiff_t crashdump_phase_reg_offset;
304  switch (alert_class) {
305  LIST_OF_CLASSES(ALERT_CLASS_CONFIG_REGS_CASE_)
306  default:
307  return kDifBadArg;
308  }
309 
310 #undef ALERT_CLASS_CONFIG_REGS_CASE_
311 
312  // Check if class configuration is locked.
313  if (!mmio_region_read32(alert_handler->base_addr, class_regwen_offset)) {
314  return kDifLocked;
315  }
316 
317  // NOTE: from this point on, we assume that Class A's constants are
318  // representative of all alert class control register layouts.
319 
320  // Configure the class control register and escalation phases / cycle times.
321  // Note, if an escalation phase is configured, it is also enabled.
322  uint32_t ctrl_reg = 0;
323  ctrl_reg =
324  bitfield_bit32_write(ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_BIT,
325  dif_toggle_to_bool(enabled));
326  ctrl_reg = bitfield_bit32_write(
327  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_LOCK_BIT,
329 
330  for (int i = 0; i < config.escalation_phases_len; ++i) {
333  config.escalation_phases[i].signal;
334 
335  // Check the escalation phase is valid. The signal is checked in the case
336  // statement below, which will return kDifBadArg if it does not
337  // correspond to any of the specified cases.
338  if (!is_valid_escalation_phase(phase)) {
339  return kDifBadArg;
340  }
341 
342  bitfield_bit32_index_t signal_enable_bit;
343  bitfield_field32_t signal_map_field;
344  switch (signal) {
345  // TODO: this should be rewritten to allow combinations of all signals.
346  // The alert handler supports the full phase -> signal mapping matrix.
347  // I.e., it is possible to enable signal 0 and 3 in phase 1 for
348  // instance. For Top Earl Grey it is for instance also recommended to
349  // trigger signals 1 and 2 at the same time since both trigger the same
350  // action in the life cycle controller and serve as redundant
351  // channels.
352  case 0:
353  signal_enable_bit = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT;
354  signal_map_field = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_FIELD;
355  break;
356  case 1:
357  signal_enable_bit = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E1_BIT;
358  signal_map_field = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E1_FIELD;
359  break;
360  case 2:
361  signal_enable_bit = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT;
362  signal_map_field = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_FIELD;
363  break;
364  case 3:
365  signal_enable_bit = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E3_BIT;
366  signal_map_field = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E3_FIELD;
367  break;
368  // Does not trigger any of the signals. Can be useful in cases where an
369  // escalation phase is just used to wait a specific amount of time.
370  case 0xFFFFFFFF:
371  break;
372  default:
373  return kDifBadArg;
374  }
375 
376  // Clear all settings.
377  if (signal == 0xFFFFFFFF) {
378  ctrl_reg = bitfield_bit32_write(
379  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT, false);
380  ctrl_reg = bitfield_field32_write(
381  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_FIELD,
382  (uint32_t)(phase - kDifAlertHandlerClassStatePhase0));
383  ctrl_reg = bitfield_bit32_write(
384  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E1_BIT, false);
385  ctrl_reg = bitfield_field32_write(
386  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E1_FIELD,
387  (uint32_t)(phase - kDifAlertHandlerClassStatePhase0));
388  ctrl_reg = bitfield_bit32_write(
389  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT, false);
390  ctrl_reg = bitfield_field32_write(
391  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_FIELD,
392  (uint32_t)(phase - kDifAlertHandlerClassStatePhase0));
393  ctrl_reg = bitfield_bit32_write(
394  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E3_BIT, false);
395  ctrl_reg = bitfield_field32_write(
396  ctrl_reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E3_FIELD,
397  (uint32_t)(phase - kDifAlertHandlerClassStatePhase0));
398  } else {
399  ctrl_reg = bitfield_bit32_write(ctrl_reg, signal_enable_bit, true);
400  ctrl_reg = bitfield_field32_write(
401  ctrl_reg, signal_map_field,
402  (uint32_t)(phase - kDifAlertHandlerClassStatePhase0));
403  }
404 
405  switch (phase) {
407  mmio_region_write32_shadowed(
408  alert_handler->base_addr, phase0_cycles_reg_offset,
410  break;
412  mmio_region_write32_shadowed(
413  alert_handler->base_addr, phase1_cycles_reg_offset,
415  break;
417  mmio_region_write32_shadowed(
418  alert_handler->base_addr, phase2_cycles_reg_offset,
420  break;
422  mmio_region_write32_shadowed(
423  alert_handler->base_addr, phase3_cycles_reg_offset,
425  break;
426  default:
427  return kDifBadArg;
428  }
429  }
430 
431  // Configure the class accumulator threshold.
432  mmio_region_write32_shadowed(alert_handler->base_addr,
433  accum_thresh_reg_offset,
434  config.accumulator_threshold);
435 
436  // Configure the class IRQ deadline.
437  mmio_region_write32_shadowed(alert_handler->base_addr,
438  irq_deadline_reg_offset,
439  config.irq_deadline_cycles);
440 
441  // Configure the crashdump phase.
442  mmio_region_write32_shadowed(alert_handler->base_addr,
443  crashdump_phase_reg_offset,
444  (uint32_t)(config.crashdump_escalation_phase -
446 
447  // Configure the class control register last, since this holds the enable bit.
448  mmio_region_write32_shadowed(alert_handler->base_addr, ctrl_reg_offset,
449  ctrl_reg);
450 
451  // Lock the configuration.
452  if (locked == kDifToggleEnabled) {
453  mmio_region_write32(alert_handler->base_addr, class_regwen_offset, 0);
454  }
455 
456  return kDifOk;
457 }
458 
460  const dif_alert_handler_t *alert_handler, uint32_t ping_timeout,
461  dif_toggle_t enabled, dif_toggle_t locked) {
462  if (alert_handler == NULL ||
463  ping_timeout >
464  ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_MASK ||
465  !dif_is_valid_toggle(enabled) || !dif_is_valid_toggle(locked)) {
466  return kDifBadArg;
467  }
468 
469  // Check if the ping timer is locked.
470  if (!mmio_region_read32(alert_handler->base_addr,
471  ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET)) {
472  return kDifLocked;
473  }
474 
475  // Set the ping timeout.
476  mmio_region_write32_shadowed(
477  alert_handler->base_addr,
478  ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_REG_OFFSET, ping_timeout);
479 
480  // Enable the ping timer.
481  // Note, this must be done after the timeout has been configured above, since
482  // pinging will start immediately.
483  if (enabled == kDifToggleEnabled) {
484  mmio_region_write32_shadowed(
485  alert_handler->base_addr,
486  ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, 1);
487  }
488 
489  // Lock the configuration.
490  if (locked == kDifToggleEnabled) {
491  mmio_region_write32(alert_handler->base_addr,
492  ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET, 0);
493  }
494 
495  return kDifOk;
496 }
497 
499  const dif_alert_handler_t *alert_handler, dif_toggle_t locked) {
500  if (alert_handler == NULL || !dif_is_valid_toggle(locked)) {
501  return kDifBadArg;
502  }
503 
504  // Check if the ping timer is locked.
505  if (!mmio_region_read32(alert_handler->base_addr,
506  ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET)) {
507  return kDifLocked;
508  }
509 
510  // Enable the ping timer.
511  mmio_region_write32_shadowed(alert_handler->base_addr,
512  ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET,
513  1);
514 
515  // Lock the configuration.
516  if (locked == kDifToggleEnabled) {
517  mmio_region_write32(alert_handler->base_addr,
518  ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET, 0);
519  }
520 
521  return kDifOk;
522 }
523 
525  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert) {
526  if (alert_handler == NULL || alert >= ALERT_HANDLER_PARAM_N_ALERTS) {
527  return kDifBadArg;
528  }
529 
530  ptrdiff_t regwen_offset = ALERT_HANDLER_ALERT_REGWEN_0_REG_OFFSET +
531  (ptrdiff_t)alert * (ptrdiff_t)sizeof(uint32_t);
532  mmio_region_write32(alert_handler->base_addr, regwen_offset, 0);
533 
534  return kDifOk;
535 }
536 
538  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
539  bool *is_locked) {
540  if (alert_handler == NULL || alert >= ALERT_HANDLER_PARAM_N_ALERTS ||
541  is_locked == NULL) {
542  return kDifBadArg;
543  }
544 
545  ptrdiff_t regwen_offset = ALERT_HANDLER_ALERT_REGWEN_0_REG_OFFSET +
546  (ptrdiff_t)alert * (ptrdiff_t)sizeof(uint32_t);
547  *is_locked = !mmio_region_read32(alert_handler->base_addr, regwen_offset);
548 
549  return kDifOk;
550 }
551 
553  const dif_alert_handler_t *alert_handler,
554  dif_alert_handler_local_alert_t local_alert) {
555  if (alert_handler == NULL) {
556  return kDifBadArg;
557  }
558 
559  ptrdiff_t regwen_offset;
560  switch (local_alert) {
561  LIST_OF_LOC_ALERTS(LOC_ALERT_REGWENS_CASE_)
562  default:
563  return kDifBadArg;
564  }
565 
566  mmio_region_write32(alert_handler->base_addr, regwen_offset, 0);
567 
568  return kDifOk;
569 }
570 
572  const dif_alert_handler_t *alert_handler,
573  dif_alert_handler_local_alert_t local_alert, bool *is_locked) {
574  if (alert_handler == NULL || is_locked == NULL) {
575  return kDifBadArg;
576  }
577 
578  ptrdiff_t regwen_offset;
579  switch (local_alert) {
580  LIST_OF_LOC_ALERTS(LOC_ALERT_REGWENS_CASE_)
581  default:
582  return kDifBadArg;
583  }
584 
585  *is_locked = !mmio_region_read32(alert_handler->base_addr, regwen_offset);
586 
587  return kDifOk;
588 }
589 
591  const dif_alert_handler_t *alert_handler,
592  dif_alert_handler_class_t alert_class) {
593  if (alert_handler == NULL) {
594  return kDifBadArg;
595  }
596 
597  ptrdiff_t regwen_offset;
598  switch (alert_class) {
599  LIST_OF_CLASSES(ALERT_CLASS_REGWENS_CASE_)
600  default:
601  return kDifBadArg;
602  }
603 
604  mmio_region_write32(alert_handler->base_addr, regwen_offset, 0);
605 
606  return kDifOk;
607 }
608 
610  const dif_alert_handler_t *alert_handler,
611  dif_alert_handler_class_t alert_class, bool *is_locked) {
612  if (alert_handler == NULL || is_locked == NULL) {
613  return kDifBadArg;
614  }
615 
616  ptrdiff_t regwen_offset;
617  switch (alert_class) {
618  LIST_OF_CLASSES(ALERT_CLASS_REGWENS_CASE_)
619  default:
620  return kDifBadArg;
621  }
622 
623  *is_locked = !mmio_region_read32(alert_handler->base_addr, regwen_offset);
624 
625  return kDifOk;
626 }
627 
629  const dif_alert_handler_t *alert_handler) {
630  if (alert_handler == NULL) {
631  return kDifBadArg;
632  }
633 
634  mmio_region_write32(alert_handler->base_addr,
635  ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET, 0);
636 
637  return kDifOk;
638 }
639 
641  const dif_alert_handler_t *alert_handler, bool *is_locked) {
642  if (alert_handler == NULL || is_locked == NULL) {
643  return kDifBadArg;
644  }
645 
646  *is_locked = !mmio_region_read32(alert_handler->base_addr,
647  ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET);
648 
649  return kDifOk;
650 }
651 
653  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert,
654  bool *is_cause) {
655  if (alert_handler == NULL || is_cause == NULL ||
656  alert >= ALERT_HANDLER_PARAM_N_ALERTS) {
657  return kDifBadArg;
658  }
659 
660  ptrdiff_t cause_reg_offset = ALERT_HANDLER_ALERT_CAUSE_0_REG_OFFSET +
661  (ptrdiff_t)alert * (ptrdiff_t)sizeof(uint32_t);
662  *is_cause = mmio_region_read32(alert_handler->base_addr, cause_reg_offset);
663 
664  return kDifOk;
665 }
666 
668  const dif_alert_handler_t *alert_handler, dif_alert_handler_alert_t alert) {
669  if (alert_handler == NULL || alert >= ALERT_HANDLER_PARAM_N_ALERTS) {
670  return kDifBadArg;
671  }
672 
673  ptrdiff_t cause_reg_offset = ALERT_HANDLER_ALERT_CAUSE_0_REG_OFFSET +
674  (ptrdiff_t)alert * (ptrdiff_t)sizeof(uint32_t);
675  mmio_region_write32(alert_handler->base_addr, cause_reg_offset, 0x1);
676 
677  return kDifOk;
678 }
679 
681  const dif_alert_handler_t *alert_handler,
682  dif_alert_handler_local_alert_t local_alert, bool *is_cause) {
683  if (alert_handler == NULL || is_cause == NULL) {
684  return kDifBadArg;
685  }
686 
687  ptrdiff_t cause_reg_offset;
688  switch (local_alert) {
689  LIST_OF_LOC_ALERTS(LOC_ALERT_CAUSE_REGS_CASE_)
690  default:
691  return kDifBadArg;
692  }
693 
694  *is_cause = mmio_region_read32(alert_handler->base_addr, cause_reg_offset);
695 
696  return kDifOk;
697 }
698 
700  const dif_alert_handler_t *alert_handler,
701  dif_alert_handler_local_alert_t local_alert) {
702  if (alert_handler == NULL) {
703  return kDifBadArg;
704  }
705 
706  ptrdiff_t cause_reg_offset;
707  switch (local_alert) {
708  LIST_OF_LOC_ALERTS(LOC_ALERT_CAUSE_REGS_CASE_)
709  default:
710  return kDifBadArg;
711  }
712 
713  mmio_region_write32(alert_handler->base_addr, cause_reg_offset, 0x1);
714 
715  return kDifOk;
716 }
717 
719  const dif_alert_handler_t *alert_handler,
720  dif_alert_handler_class_t alert_class, bool *can_clear) {
721  if (alert_handler == NULL || can_clear == NULL) {
722  return kDifBadArg;
723  }
724 
725  ptrdiff_t regwen_offset;
726  switch (alert_class) {
727  LIST_OF_CLASSES(ALERT_CLASS_CLEAR_REGWENS_CASE_)
728  default:
729  return kDifBadArg;
730  }
731 
732  *can_clear = mmio_region_read32(alert_handler->base_addr, regwen_offset);
733 
734  return kDifOk;
735 }
736 
738  const dif_alert_handler_t *alert_handler,
739  dif_alert_handler_class_t alert_class) {
740  if (alert_handler == NULL) {
741  return kDifBadArg;
742  }
743 
744  ptrdiff_t regwen_offset;
745  switch (alert_class) {
746  LIST_OF_CLASSES(ALERT_CLASS_CLEAR_REGWENS_CASE_)
747  default:
748  return kDifBadArg;
749  }
750 
751  mmio_region_write32(alert_handler->base_addr, regwen_offset, 0);
752 
753  return kDifOk;
754 }
755 
757  const dif_alert_handler_t *alert_handler,
758  dif_alert_handler_class_t alert_class) {
759  if (alert_handler == NULL) {
760  return kDifBadArg;
761  }
762 
763 #define ALERT_CLASS_CLEAR_CASE_(class_, value_) \
764  case kDifAlertHandlerClass##class_: \
765  reg_offset = ALERT_HANDLER_CLASS##class_##_CLR_SHADOWED_REG_OFFSET; \
766  break;
767 
768  ptrdiff_t reg_offset;
769  switch (alert_class) {
770  LIST_OF_CLASSES(ALERT_CLASS_CLEAR_CASE_)
771  default:
772  return kDifBadArg;
773  }
774 
775 #undef ALERT_CLASS_CLEAR_CASE_
776 
777  mmio_region_write32_shadowed(alert_handler->base_addr, reg_offset, 0x1);
778 
779  return kDifOk;
780 }
781 
783  const dif_alert_handler_t *alert_handler,
784  dif_alert_handler_class_t alert_class, uint16_t *num_alerts) {
785  if (alert_handler == NULL || num_alerts == NULL) {
786  return kDifBadArg;
787  }
788 
789 #define ALERT_CLASS_ACCUM_CASE_(class_, value_) \
790  case kDifAlertHandlerClass##class_: \
791  reg_offset = ALERT_HANDLER_CLASS##class_##_ACCUM_CNT_REG_OFFSET; \
792  field = \
793  ALERT_HANDLER_CLASS##class_##_ACCUM_CNT_CLASS##class_##_ACCUM_CNT_FIELD; \
794  break;
795 
796  ptrdiff_t reg_offset;
797  bitfield_field32_t field;
798  switch (alert_class) {
799  LIST_OF_CLASSES(ALERT_CLASS_ACCUM_CASE_)
800  default:
801  return kDifBadArg;
802  }
803 
804 #undef ALERT_CLASS_ACCUM_CASE_
805 
806  uint32_t reg = mmio_region_read32(alert_handler->base_addr, reg_offset);
807  *num_alerts = (uint16_t)bitfield_field32_read(reg, field);
808 
809  return kDifOk;
810 }
811 
813  const dif_alert_handler_t *alert_handler,
814  dif_alert_handler_class_t alert_class, uint32_t *cycles) {
815  if (alert_handler == NULL || cycles == NULL) {
816  return kDifBadArg;
817  }
818 
819 #define ALERT_CLASS_ESC_CNT_CASE_(class_, value_) \
820  case kDifAlertHandlerClass##class_: \
821  reg_offset = ALERT_HANDLER_CLASS##class_##_ESC_CNT_REG_OFFSET; \
822  break;
823 
824  ptrdiff_t reg_offset;
825  switch (alert_class) {
826  LIST_OF_CLASSES(ALERT_CLASS_ESC_CNT_CASE_)
827  default:
828  return kDifBadArg;
829  }
830 
831 #undef ALERT_CLASS_ESC_CNT_CASE_
832 
833  *cycles = mmio_region_read32(alert_handler->base_addr, reg_offset);
834 
835  return kDifOk;
836 }
837 
839  const dif_alert_handler_t *alert_handler,
840  dif_alert_handler_class_t alert_class,
842  if (alert_handler == NULL || state == NULL) {
843  return kDifBadArg;
844  }
845 
846 #define ALERT_CLASS_STATE_CASE_(class_, value_) \
847  case kDifAlertHandlerClass##class_: \
848  reg_offset = ALERT_HANDLER_CLASS##class_##_STATE_REG_OFFSET; \
849  field = ALERT_HANDLER_CLASS##class_##_STATE_CLASS##class_##_STATE_FIELD; \
850  break;
851 
852  ptrdiff_t reg_offset;
853  bitfield_field32_t field;
854  switch (alert_class) {
855  LIST_OF_CLASSES(ALERT_CLASS_STATE_CASE_)
856  default:
857  return kDifBadArg;
858  }
859 
860 #undef ALERT_CLASS_STATE_CASE_
861 
862  uint32_t reg = mmio_region_read32(alert_handler->base_addr, reg_offset);
863  switch (bitfield_field32_read(reg, field)) {
864  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_IDLE:
866  break;
867  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_TIMEOUT:
869  break;
870  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_FSMERROR:
872  break;
873  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_TERMINAL:
875  break;
876  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_PHASE0:
878  break;
879  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_PHASE1:
881  break;
882  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_PHASE2:
884  break;
885  case ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_PHASE3:
887  break;
888  default:
889  return kDifError;
890  }
891 
892  return kDifOk;
893 }