-
Notifications
You must be signed in to change notification settings - Fork 781
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[test] alert_handler_reverse_ping_in_deep_sleep
Check that escalation receivers located inside always-on blocks do not auto-escalate due to the reverse ping feature while the system is in deep sleep. Signed-off-by: Miguel Osorio <[email protected]>
- Loading branch information
Showing
4 changed files
with
278 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
220 changes: 220 additions & 0 deletions
220
sw/device/tests/alert_handler_reverse_ping_in_deep_sleep_test.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
// Copyright lowRISC contributors. | ||
// Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#include <assert.h> | ||
#include <limits.h> | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
#include "sw/device/lib/base/math.h" | ||
#include "sw/device/lib/base/mmio.h" | ||
#include "sw/device/lib/dif/dif_alert_handler.h" | ||
#include "sw/device/lib/dif/dif_aon_timer.h" | ||
#include "sw/device/lib/dif/dif_pwrmgr.h" | ||
#include "sw/device/lib/dif/dif_rstmgr.h" | ||
#include "sw/device/lib/dif/dif_rv_plic.h" | ||
#include "sw/device/lib/runtime/irq.h" | ||
#include "sw/device/lib/runtime/log.h" | ||
#include "sw/device/lib/testing/alert_handler_testutils.h" | ||
#include "sw/device/lib/testing/aon_timer_testutils.h" | ||
#include "sw/device/lib/testing/pwrmgr_testutils.h" | ||
#include "sw/device/lib/testing/rstmgr_testutils.h" | ||
#include "sw/device/lib/testing/rv_plic_testutils.h" | ||
#include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h" | ||
#include "sw/device/lib/testing/test_framework/check.h" | ||
#include "sw/device/lib/testing/test_framework/ottf_main.h" | ||
|
||
#include "alert_handler_regs.h" // Generated. | ||
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" | ||
#include "sw/device/lib/testing/autogen/isr_testutils.h" | ||
|
||
OTTF_DEFINE_TEST_CONFIG(); | ||
|
||
enum { | ||
// TODO: Randomize the following test parameters. Need to define timing | ||
// parameters for entry/exit to/from deep sleep. | ||
kTestParamWakeupThresholdUsec = 200, | ||
kTestParamAlertHandlerIrqDeadlineUsec = 100, | ||
kTestParamAlertHandlerPhase0EscalationDurationUsec = 100, | ||
kTestParamAlertHandlerPingTimeoutUsec = 20, | ||
}; | ||
|
||
static dif_rv_plic_t plic; | ||
static dif_pwrmgr_t pwrmgr; | ||
static dif_rstmgr_t rstmgr; | ||
static dif_aon_timer_t aon_timer; | ||
static dif_alert_handler_t alert_handler; | ||
static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0; | ||
|
||
static plic_isr_ctx_t plic_ctx = { | ||
.rv_plic = &plic, | ||
.hart_id = kPlicTarget, | ||
}; | ||
|
||
// Depends on the clock domain, sometimes alert handler will trigger a spurious | ||
// alert after the alert timeout. (Issue #2321) | ||
// So we allow class A interrupt to fire after the real timeout interrupt is | ||
// triggered. | ||
static alert_handler_isr_ctx_t alert_handler_ctx = { | ||
.alert_handler = &alert_handler, | ||
.plic_alert_handler_start_irq_id = kTopEarlgreyPlicIrqIdAlertHandlerClassa, | ||
.expected_irq = kDifAlertHandlerIrqClassb, | ||
.is_only_irq = false, | ||
}; | ||
|
||
/** | ||
* Initialize the peripherals used in this test. | ||
*/ | ||
static void init_peripherals(void) { | ||
CHECK_DIF_OK(dif_rv_plic_init( | ||
mmio_region_from_addr(TOP_EARLGREY_RV_PLIC_BASE_ADDR), &plic)); | ||
CHECK_DIF_OK(dif_alert_handler_init( | ||
mmio_region_from_addr(TOP_EARLGREY_ALERT_HANDLER_BASE_ADDR), | ||
&alert_handler)); | ||
CHECK_DIF_OK(dif_pwrmgr_init( | ||
mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR), &pwrmgr)); | ||
CHECK_DIF_OK(dif_rstmgr_init( | ||
mmio_region_from_addr(TOP_EARLGREY_RSTMGR_AON_BASE_ADDR), &rstmgr)); | ||
CHECK_DIF_OK(dif_aon_timer_init( | ||
mmio_region_from_addr(TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR), &aon_timer)); | ||
|
||
// Enable all the alert_handler interrupts used in this test. | ||
rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, | ||
kTopEarlgreyPlicIrqIdAlertHandlerClassa, | ||
kTopEarlgreyPlicIrqIdAlertHandlerClassd); | ||
} | ||
|
||
/** | ||
* Program the alert handler to escalate on alerts upto phase 1 (i.e. wipe | ||
* secret) but not trigger reset. Then CPU can check if the correct interrupt | ||
* fires and check the local alert cause register. | ||
*/ | ||
static void alert_handler_config(void) { | ||
dif_alert_handler_alert_t alerts[ALERT_HANDLER_PARAM_N_ALERTS]; | ||
dif_alert_handler_class_t alert_classes[ALERT_HANDLER_PARAM_N_ALERTS]; | ||
|
||
// Enable all incoming alerts and configure them to classa. | ||
// This alert should never fire because we do not expect any incoming alerts. | ||
for (int i = 0; i < ALERT_HANDLER_PARAM_N_ALERTS; ++i) { | ||
alerts[i] = i; | ||
alert_classes[i] = kDifAlertHandlerClassA; | ||
} | ||
|
||
// Enable alert ping fail local alert and configure that to classb. | ||
dif_alert_handler_local_alert_t loc_alerts[] = { | ||
kDifAlertHandlerLocalAlertAlertPingFail}; | ||
dif_alert_handler_class_t loc_alert_classes[] = {kDifAlertHandlerClassB}; | ||
|
||
dif_alert_handler_escalation_phase_t esc_phases[] = { | ||
{ | ||
.phase = kDifAlertHandlerClassStatePhase0, | ||
.signal = 0, | ||
.duration_cycles = | ||
udiv64_slow(kTestParamAlertHandlerPhase0EscalationDurationUsec * | ||
kClockFreqPeripheralHz, | ||
1000000, /*rem_out=*/NULL), | ||
}, | ||
}; | ||
|
||
dif_alert_handler_class_config_t class_config = { | ||
.auto_lock_accumulation_counter = kDifToggleDisabled, | ||
.accumulator_threshold = 0, | ||
.irq_deadline_cycles = udiv64_slow( | ||
kTestParamAlertHandlerIrqDeadlineUsec * kClockFreqPeripheralHz, | ||
1000000, /*rem_out=*/NULL), | ||
.escalation_phases = esc_phases, | ||
.escalation_phases_len = ARRAYSIZE(esc_phases), | ||
.crashdump_escalation_phase = kDifAlertHandlerClassStatePhase1, | ||
}; | ||
|
||
dif_alert_handler_class_config_t class_configs[] = {class_config, | ||
class_config}; | ||
|
||
dif_alert_handler_class_t classes[] = {kDifAlertHandlerClassA, | ||
kDifAlertHandlerClassB}; | ||
dif_alert_handler_config_t config = { | ||
.alerts = alerts, | ||
.alert_classes = alert_classes, | ||
.alerts_len = ARRAYSIZE(alerts), | ||
.local_alerts = loc_alerts, | ||
.local_alert_classes = loc_alert_classes, | ||
.local_alerts_len = ARRAYSIZE(loc_alerts), | ||
.classes = classes, | ||
.class_configs = class_configs, | ||
.classes_len = ARRAYSIZE(class_configs), | ||
.ping_timeout = udiv64_slow( | ||
kTestParamAlertHandlerPingTimeoutUsec * kClockFreqPeripheralHz, | ||
1000000, /*rem_out=*/NULL), | ||
}; | ||
|
||
alert_handler_testutils_configure_all(&alert_handler, config, | ||
kDifToggleEnabled); | ||
// Enables alert handler irq. | ||
CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( | ||
&alert_handler, kDifAlertHandlerIrqClassa, kDifToggleEnabled)); | ||
|
||
CHECK_DIF_OK(dif_alert_handler_irq_set_enabled( | ||
&alert_handler, kDifAlertHandlerIrqClassb, kDifToggleEnabled)); | ||
} | ||
|
||
/** | ||
* External ISR. | ||
* | ||
* Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt | ||
* line to the CPU, which results in a call to this OTTF ISR. This ISR | ||
* overrides the default OTTF implementation. | ||
*/ | ||
void ottf_external_isr(void) { | ||
top_earlgrey_plic_peripheral_t peripheral_serviced; | ||
dif_alert_handler_irq_t irq_serviced; | ||
isr_testutils_alert_handler_isr(plic_ctx, alert_handler_ctx, | ||
&peripheral_serviced, &irq_serviced); | ||
CHECK(peripheral_serviced == kTopEarlgreyPlicPeripheralAlertHandler, | ||
"Interurpt from unexpected peripheral: %d", peripheral_serviced); | ||
} | ||
|
||
bool test_main(void) { | ||
init_peripherals(); | ||
|
||
if (pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) { | ||
LOG_INFO("POR reset"); | ||
CHECK(rstmgr_testutils_reset_info_any(&rstmgr, kDifRstmgrResetInfoPor)); | ||
rstmgr_testutils_pre_reset(&rstmgr); | ||
|
||
alert_handler_config(); | ||
|
||
irq_global_ctrl(true); | ||
irq_external_ctrl(true); | ||
|
||
uint32_t wakeup_threshold = | ||
udiv64_slow(kTestParamWakeupThresholdUsec * kClockFreqAonHz, 1000000, | ||
/*rem_out=*/NULL); | ||
|
||
// Enable and enter deep sleep. | ||
aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold); | ||
pwrmgr_testutils_enable_low_power(&pwrmgr, | ||
kDifPwrmgrWakeupRequestSourceFive, 0); | ||
wait_for_interrupt(); | ||
CHECK(false, "Fail to enter in low power mode!"); | ||
} else if (pwrmgr_testutils_is_wakeup_reason( | ||
&pwrmgr, kDifPwrmgrWakeupRequestSourceFive)) { | ||
LOG_INFO("Wakeup reset"); | ||
CHECK(rstmgr_testutils_is_reset_info(&rstmgr, | ||
kDifRstmgrResetInfoLowPowerExit)); | ||
aon_timer_testutils_shutdown(&aon_timer); | ||
|
||
bool is_cause; | ||
CHECK_DIF_OK(dif_alert_handler_local_alert_is_cause( | ||
&alert_handler, kDifAlertHandlerLocalAlertAlertPingFail, &is_cause)); | ||
CHECK(!is_cause, "Unexpected local alert cause: alert_ping_fail"); | ||
return true; | ||
} else { | ||
dif_pwrmgr_wakeup_reason_t wakeup_reason; | ||
CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason)); | ||
LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d", | ||
wakeup_reason.types, wakeup_reason.request_sources); | ||
return false; | ||
} | ||
return false; | ||
} |