blob: 4a3247c071a64aa2b5cedbfb20097b80b3182cfb [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/dif/dif_alert_handler.h"
#include <cstring>
#include <limits>
#include <ostream>
#include "gtest/gtest.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/base/testing/mock_mmio.h"
#include "alert_handler_regs.h" // Generated.
namespace dif_alert_handler_unittest {
namespace {
using ::mock_mmio::LeInt;
using ::mock_mmio::MmioTest;
using ::mock_mmio::MockDevice;
using ::testing::_;
using ::testing::Return;
constexpr uint32_t kAlerts = ALERT_HANDLER_PARAM_N_ALERTS;
constexpr uint32_t kAllZeros = 0;
class AlertHandlerTest : public testing::Test, public MmioTest {
protected:
dif_alert_handler_t alert_handler_ = {.base_addr = dev().region()};
};
class InitTest : public AlertHandlerTest,
public testing::WithParamInterface<uint32_t> {};
TEST_F(InitTest, Success) {
dif_alert_handler_t alert_handler;
EXPECT_EQ(dif_alert_handler_init(dev().region(), &alert_handler), kDifOk);
}
TEST_F(InitTest, NullArgs) {
EXPECT_EQ(dif_alert_handler_init(dev().region(), nullptr), kDifBadArg);
}
class ConfigTest : public AlertHandlerTest {
// We provide our own dev_ member variable in this fixture, in order to
// support IgnoreMmioCalls().
//
// NOTE: This must come before alert_handler_!
private:
std::unique_ptr<MockDevice> dev_ =
std::make_unique<testing::StrictMock<MockDevice>>();
protected:
ConfigTest() { alert_handler_.base_addr = dev().region(); }
// Non-virtual-override dev(), so that EXPECT_*() functions look this one
// up instead of AlertHandlerTest::dev().
MockDevice &dev() { return *dev_; }
// Disables expectations on MMIO operations. This is useful for configuration
// tests that partially configure the device but fail due to a configuration
// error, returning kDifError.
void IgnoreMmioCalls() {
dev_ = std::make_unique<testing::NiceMock<MockDevice>>();
alert_handler_.base_addr = dev().region();
// Make sure that the peripheral looks unlocked.
ON_CALL(*dev_, Read32(_)).WillByDefault(Return(kAllZeros));
}
};
TEST_F(ConfigTest, Locked) {
dif_alert_handler_config_t config = {
.ping_timeout = 0,
};
EXPECT_READ32(
ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT,
true}});
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifLocked);
}
TEST_F(ConfigTest, NoClassInit) {
dif_alert_handler_config_t config = {
.ping_timeout = 50,
};
EXPECT_READ32(
ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT,
false}});
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_OFFSET,
50}});
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifOk);
}
TEST_F(ConfigTest, TimeoutTooBig) {
dif_alert_handler_config_t config = {
.ping_timeout =
ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_MASK +
1,
};
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifBadArg);
}
TEST_F(ConfigTest, BadClassPtr) {
dif_alert_handler_config_t config = {
.ping_timeout = 50,
.classes = nullptr,
.classes_len = 2,
};
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifBadArg);
}
TEST_F(ConfigTest, ClassInit) {
std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5};
std::vector<dif_alert_handler_local_alert_t> locals_a = {
kDifAlertHandlerLocalAlertEscalationPingFail,
};
std::vector<dif_alert_handler_class_phase_signal_t> signals_a = {
{.phase = kDifAlertHandlerClassStatePhase0, .signal = 3},
{.phase = kDifAlertHandlerClassStatePhase2, .signal = 1},
};
std::vector<dif_alert_handler_class_phase_duration_t> durations_a = {
{.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000},
{.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000},
};
std::vector<dif_alert_handler_alert_t> alerts_b = {9, 6, 11};
std::vector<dif_alert_handler_local_alert_t> locals_b = {
kDifAlertHandlerLocalAlertAlertPingFail,
kDifAlertHandlerLocalAlertAlertIntegrityFail,
};
std::vector<dif_alert_handler_class_phase_signal_t> signals_b = {
{.phase = kDifAlertHandlerClassStatePhase1, .signal = 0},
};
std::vector<dif_alert_handler_class_phase_duration_t> durations_b = {
{.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000},
{.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000},
{.phase = kDifAlertHandlerClassStatePhase3, .cycles = 150000},
};
std::vector<dif_alert_handler_class_config_t> classes = {
{
.alert_class = kDifAlertHandlerClassA,
.alerts = alerts_a.data(),
.alerts_len = alerts_a.size(),
.local_alerts = locals_a.data(),
.local_alerts_len = locals_a.size(),
.use_escalation_protocol = kDifToggleDisabled,
.automatic_locking = kDifToggleEnabled,
.accumulator_threshold = 12,
.irq_deadline_cycles = 30000,
.phase_signals = signals_a.data(),
.phase_signals_len = signals_a.size(),
.phase_durations = durations_a.data(),
.phase_durations_len = durations_a.size(),
},
{
.alert_class = kDifAlertHandlerClassB,
.alerts = alerts_b.data(),
.alerts_len = alerts_b.size(),
.local_alerts = locals_b.data(),
.local_alerts_len = locals_b.size(),
.use_escalation_protocol = kDifToggleEnabled,
.automatic_locking = kDifToggleDisabled,
.accumulator_threshold = 8,
.irq_deadline_cycles = 2000,
.phase_signals = signals_b.data(),
.phase_signals_len = signals_b.size(),
.phase_durations = durations_b.data(),
.phase_durations_len = durations_b.size(),
},
};
dif_alert_handler_config_t config = {
.ping_timeout = 50,
.classes = classes.data(),
.classes_len = classes.size(),
};
// The alert handler needs to be unlocked for it to be configured.
EXPECT_READ32(
ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT,
false}});
// Configure class A alerts.
// Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the
// target registers are shadowed.
for (auto alert : alerts_a) {
// The various alerts should be enabled.
ptrdiff_t alert_enable_reg_offset =
ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + alert * sizeof(uint32_t);
EXPECT_READ32(alert_enable_reg_offset, 0);
EXPECT_WRITE32_SHADOWED(
alert_enable_reg_offset,
{{ALERT_HANDLER_ALERT_EN_SHADOWED_0_EN_A_0_BIT, true}});
// The various alerts should be classified.
ptrdiff_t alert_class_reg_offset =
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET +
alert * sizeof(uint32_t);
EXPECT_READ32(alert_class_reg_offset, 0);
EXPECT_WRITE32_SHADOWED(
alert_class_reg_offset,
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSA);
}
// Configure class A local alerts.
// Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the
// target registers are shadowed.
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_REG_RESVAL);
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_1_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_1_REG_RESVAL);
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_1_EN_LA_1_BIT, true}});
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_1_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSA);
// Configure class A control register.
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET,
{
{ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_BIT, false},
{ALERT_HANDLER_CLASSA_CTRL_SHADOWED_LOCK_BIT, true},
{ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT, true},
{ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_OFFSET, 3},
{ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT, true},
{ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_OFFSET, 1},
});
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_ACCUM_THRESH_SHADOWED_REG_OFFSET,
12);
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_TIMEOUT_CYC_SHADOWED_REG_OFFSET,
30000);
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_PHASE1_CYC_SHADOWED_REG_OFFSET,
20000);
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSA_PHASE2_CYC_SHADOWED_REG_OFFSET,
15000);
// Configure class B alerts.
// Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the
// target registers are shadowed.
for (auto alert : alerts_b) {
// The various alerts should be enabled.
ptrdiff_t alert_enable_reg_offset =
ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + alert * sizeof(uint32_t);
EXPECT_READ32(alert_enable_reg_offset, 0);
EXPECT_WRITE32_SHADOWED(
alert_enable_reg_offset,
{{ALERT_HANDLER_ALERT_EN_SHADOWED_0_EN_A_0_BIT, true}});
// The various alerts should be classified.
ptrdiff_t alert_class_reg_offset =
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET +
alert * sizeof(uint32_t);
EXPECT_READ32(alert_class_reg_offset, 0);
EXPECT_WRITE32_SHADOWED(
alert_class_reg_offset,
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSB);
}
// Configure class B local alerts.
// Unfortunately, we can't use EXPECT_MASK for these reads/writes, since the
// target registers are shadowed.
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_RESVAL);
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_RESVAL);
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_EN_LA_0_BIT, true}});
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSB);
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_REG_RESVAL);
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_2_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_2_REG_RESVAL);
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_2_EN_LA_2_BIT, true}});
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_2_REG_OFFSET,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSB);
// Configure class B control register.
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_CLASSB_CTRL_SHADOWED_REG_OFFSET,
{
{ALERT_HANDLER_CLASSB_CTRL_SHADOWED_EN_BIT, true},
{ALERT_HANDLER_CLASSB_CTRL_SHADOWED_LOCK_BIT, false},
{ALERT_HANDLER_CLASSB_CTRL_SHADOWED_EN_E1_BIT, true},
{ALERT_HANDLER_CLASSB_CTRL_SHADOWED_MAP_E1_OFFSET, 0},
});
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_ACCUM_THRESH_SHADOWED_REG_OFFSET,
8);
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_TIMEOUT_CYC_SHADOWED_REG_OFFSET,
2000);
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_PHASE1_CYC_SHADOWED_REG_OFFSET,
20000);
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_PHASE2_CYC_SHADOWED_REG_OFFSET,
15000);
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSB_PHASE3_CYC_SHADOWED_REG_OFFSET,
150000);
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMEOUT_CYC_SHADOWED_PING_TIMEOUT_CYC_SHADOWED_OFFSET,
50}});
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifOk);
}
TEST_F(ConfigTest, BadAlert) {
IgnoreMmioCalls();
std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, kAlerts + 1};
std::vector<dif_alert_handler_local_alert_t> locals_a = {
kDifAlertHandlerLocalAlertEscalationPingFail,
};
std::vector<dif_alert_handler_class_phase_signal_t> signals_a = {
{.phase = kDifAlertHandlerClassStatePhase0, .signal = 3},
{.phase = kDifAlertHandlerClassStatePhase2, .signal = 1},
};
std::vector<dif_alert_handler_class_phase_duration_t> durations_a = {
{.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000},
{.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000},
};
std::vector<dif_alert_handler_class_config_t> classes = {
{
.alert_class = kDifAlertHandlerClassA,
.alerts = alerts_a.data(),
.alerts_len = alerts_a.size(),
.local_alerts = locals_a.data(),
.local_alerts_len = locals_a.size(),
.use_escalation_protocol = kDifToggleDisabled,
.automatic_locking = kDifToggleEnabled,
.accumulator_threshold = 12,
.irq_deadline_cycles = 30000,
.phase_signals = signals_a.data(),
.phase_signals_len = signals_a.size(),
.phase_durations = durations_a.data(),
.phase_durations_len = durations_a.size(),
},
};
dif_alert_handler_config_t config = {
.ping_timeout = 50,
.classes = classes.data(),
.classes_len = classes.size(),
};
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
}
TEST_F(ConfigTest, BadSignalPhase) {
IgnoreMmioCalls();
std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5};
std::vector<dif_alert_handler_local_alert_t> locals_a = {
kDifAlertHandlerLocalAlertEscalationPingFail,
};
std::vector<dif_alert_handler_class_phase_signal_t> signals_a = {
{.phase = kDifAlertHandlerClassStatePhase0, .signal = 3},
{.phase = kDifAlertHandlerClassStateTerminal, .signal = 1},
};
std::vector<dif_alert_handler_class_phase_duration_t> durations_a = {
{.phase = kDifAlertHandlerClassStatePhase1, .cycles = 20000},
{.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000},
};
std::vector<dif_alert_handler_class_config_t> classes = {
{
.alert_class = kDifAlertHandlerClassA,
.alerts = alerts_a.data(),
.alerts_len = alerts_a.size(),
.local_alerts = locals_a.data(),
.local_alerts_len = locals_a.size(),
.use_escalation_protocol = kDifToggleDisabled,
.automatic_locking = kDifToggleEnabled,
.accumulator_threshold = 12,
.irq_deadline_cycles = 30000,
.phase_signals = signals_a.data(),
.phase_signals_len = signals_a.size(),
.phase_durations = durations_a.data(),
.phase_durations_len = durations_a.size(),
},
};
dif_alert_handler_config_t config = {
.ping_timeout = 50,
.classes = classes.data(),
.classes_len = classes.size(),
};
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
}
TEST_F(ConfigTest, BadDurationPhase) {
IgnoreMmioCalls();
std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5};
std::vector<dif_alert_handler_local_alert_t> locals_a = {
kDifAlertHandlerLocalAlertEscalationPingFail,
};
std::vector<dif_alert_handler_class_phase_signal_t> signals_a = {
{.phase = kDifAlertHandlerClassStatePhase0, .signal = 3},
{.phase = kDifAlertHandlerClassStatePhase2, .signal = 1},
};
std::vector<dif_alert_handler_class_phase_duration_t> durations_a = {
{.phase = kDifAlertHandlerClassStateTerminal, .cycles = 20000},
{.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000},
};
std::vector<dif_alert_handler_class_config_t> classes = {
{
.alert_class = kDifAlertHandlerClassA,
.alerts = alerts_a.data(),
.alerts_len = alerts_a.size(),
.local_alerts = locals_a.data(),
.local_alerts_len = locals_a.size(),
.use_escalation_protocol = kDifToggleDisabled,
.automatic_locking = kDifToggleEnabled,
.accumulator_threshold = 12,
.irq_deadline_cycles = 30000,
.phase_signals = signals_a.data(),
.phase_signals_len = signals_a.size(),
.phase_durations = durations_a.data(),
.phase_durations_len = durations_a.size(),
},
};
dif_alert_handler_config_t config = {
.ping_timeout = 50,
.classes = classes.data(),
.classes_len = classes.size(),
};
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
}
TEST_F(ConfigTest, BadPointers) {
IgnoreMmioCalls();
std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5};
std::vector<dif_alert_handler_local_alert_t> locals_a = {
kDifAlertHandlerLocalAlertEscalationPingFail,
};
std::vector<dif_alert_handler_class_phase_signal_t> signals_a = {
{.phase = kDifAlertHandlerClassStatePhase0, .signal = 3},
{.phase = kDifAlertHandlerClassStatePhase2, .signal = 1},
};
std::vector<dif_alert_handler_class_phase_duration_t> durations_a = {
{.phase = kDifAlertHandlerClassStateTerminal, .cycles = 20000},
{.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000},
};
std::vector<dif_alert_handler_class_config_t> classes = {
{
.alert_class = kDifAlertHandlerClassA,
.alerts = alerts_a.data(),
.alerts_len = alerts_a.size(),
.local_alerts = locals_a.data(),
.local_alerts_len = locals_a.size(),
.use_escalation_protocol = kDifToggleDisabled,
.automatic_locking = kDifToggleEnabled,
.accumulator_threshold = 12,
.irq_deadline_cycles = 30000,
.phase_signals = signals_a.data(),
.phase_signals_len = signals_a.size(),
.phase_durations = durations_a.data(),
.phase_durations_len = durations_a.size(),
},
};
dif_alert_handler_config_t config = {
.ping_timeout = 50,
.classes = classes.data(),
.classes_len = classes.size(),
};
classes[0].alerts = nullptr;
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
classes[0].alerts = alerts_a.data();
classes[0].local_alerts = nullptr;
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
classes[0].local_alerts = locals_a.data();
classes[0].phase_signals = nullptr;
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
classes[0].phase_signals = signals_a.data();
classes[0].phase_durations = nullptr;
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
}
TEST_F(ConfigTest, BadClass) {
IgnoreMmioCalls();
std::vector<dif_alert_handler_alert_t> alerts_a = {1, 2, 5};
std::vector<dif_alert_handler_local_alert_t> locals_a = {
kDifAlertHandlerLocalAlertEscalationPingFail,
};
std::vector<dif_alert_handler_class_phase_signal_t> signals_a = {
{.phase = kDifAlertHandlerClassStatePhase0, .signal = 3},
{.phase = kDifAlertHandlerClassStatePhase2, .signal = 1},
};
std::vector<dif_alert_handler_class_phase_duration_t> durations_a = {
{.phase = kDifAlertHandlerClassStatePhase0, .cycles = 20000},
{.phase = kDifAlertHandlerClassStatePhase2, .cycles = 15000},
};
std::vector<dif_alert_handler_class_config_t> classes = {
{
.alert_class = static_cast<dif_alert_handler_class_t>(12),
.alerts = alerts_a.data(),
.alerts_len = alerts_a.size(),
.local_alerts = locals_a.data(),
.local_alerts_len = locals_a.size(),
.use_escalation_protocol = kDifToggleDisabled,
.automatic_locking = kDifToggleEnabled,
.accumulator_threshold = 12,
.irq_deadline_cycles = 30000,
.phase_signals = signals_a.data(),
.phase_signals_len = signals_a.size(),
.phase_durations = durations_a.data(),
.phase_durations_len = durations_a.size(),
},
};
dif_alert_handler_config_t config = {
.ping_timeout = 50,
.classes = classes.data(),
.classes_len = classes.size(),
};
EXPECT_EQ(dif_alert_handler_configure(&alert_handler_, config), kDifError);
}
TEST_F(ConfigTest, NullArgs) {
EXPECT_EQ(dif_alert_handler_configure(nullptr, {}), kDifBadArg);
}
class LockTest : public AlertHandlerTest {};
TEST_F(LockTest, IsLocked) {
bool flag;
EXPECT_READ32(
ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT,
false}});
EXPECT_EQ(dif_alert_handler_is_locked(&alert_handler_, &flag), kDifOk);
EXPECT_FALSE(flag);
EXPECT_READ32(
ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT,
true}});
EXPECT_EQ(dif_alert_handler_is_locked(&alert_handler_, &flag), kDifOk);
EXPECT_TRUE(flag);
}
TEST_F(LockTest, Lock) {
EXPECT_WRITE32_SHADOWED(
ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET,
{{ALERT_HANDLER_PING_TIMER_EN_SHADOWED_PING_TIMER_EN_SHADOWED_BIT,
true}});
EXPECT_EQ(dif_alert_handler_lock(&alert_handler_), kDifOk);
}
TEST_F(LockTest, NullArgs) {
bool flag;
EXPECT_EQ(dif_alert_handler_is_locked(nullptr, &flag), kDifBadArg);
EXPECT_EQ(dif_alert_handler_is_locked(&alert_handler_, nullptr), kDifBadArg);
EXPECT_EQ(dif_alert_handler_lock(nullptr), kDifBadArg);
}
class CauseTest : public AlertHandlerTest {};
TEST_F(CauseTest, IsCause) {
bool flag;
EXPECT_READ32(ALERT_HANDLER_ALERT_CAUSE_5_REG_OFFSET, {{0, true}});
EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, 5, &flag),
kDifOk);
EXPECT_TRUE(flag);
EXPECT_READ32(ALERT_HANDLER_ALERT_CAUSE_6_REG_OFFSET, {{0, false}});
EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, 6, &flag),
kDifOk);
EXPECT_FALSE(flag);
}
TEST_F(CauseTest, Ack) {
EXPECT_WRITE32(ALERT_HANDLER_ALERT_CAUSE_0_REG_OFFSET,
{{ALERT_HANDLER_ALERT_CAUSE_0_A_0_BIT, true}});
EXPECT_EQ(dif_alert_handler_alert_acknowledge(&alert_handler_, 0), kDifOk);
EXPECT_WRITE32(ALERT_HANDLER_ALERT_CAUSE_11_REG_OFFSET,
{{ALERT_HANDLER_ALERT_CAUSE_11_A_11_BIT, true}});
EXPECT_EQ(dif_alert_handler_alert_acknowledge(&alert_handler_, 11), kDifOk);
}
TEST_F(CauseTest, BadAlert) {
bool flag;
EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, kAlerts, &flag),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_alert_acknowledge(&alert_handler_, kAlerts),
kDifBadArg);
}
TEST_F(CauseTest, IsCauseLocal) {
bool flag;
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CAUSE_1_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_CAUSE_1_LA_1_BIT, true}});
EXPECT_EQ(
dif_alert_handler_local_alert_is_cause(
&alert_handler_, kDifAlertHandlerLocalAlertEscalationPingFail, &flag),
kDifOk);
EXPECT_TRUE(flag);
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CAUSE_4_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_CAUSE_4_LA_4_BIT, true}});
EXPECT_EQ(
dif_alert_handler_local_alert_is_cause(
&alert_handler_, kDifAlertHandlerLocalAlertBusIntegrityFail, &flag),
kDifOk);
EXPECT_TRUE(flag);
EXPECT_READ32(ALERT_HANDLER_LOC_ALERT_CAUSE_3_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_CAUSE_3_LA_3_BIT, false}});
EXPECT_EQ(dif_alert_handler_local_alert_is_cause(
&alert_handler_,
kDifAlertHandlerLocalAlertEscalationIntegrityFail, &flag),
kDifOk);
EXPECT_FALSE(flag);
}
TEST_F(CauseTest, AckLocal) {
EXPECT_WRITE32(ALERT_HANDLER_LOC_ALERT_CAUSE_3_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_CAUSE_3_LA_3_BIT, true}});
EXPECT_EQ(
dif_alert_handler_local_alert_acknowledge(
&alert_handler_, kDifAlertHandlerLocalAlertEscalationIntegrityFail),
kDifOk);
EXPECT_WRITE32(ALERT_HANDLER_LOC_ALERT_CAUSE_4_REG_OFFSET,
{{ALERT_HANDLER_LOC_ALERT_CAUSE_4_LA_4_BIT, true}});
EXPECT_EQ(dif_alert_handler_local_alert_acknowledge(
&alert_handler_, kDifAlertHandlerLocalAlertBusIntegrityFail),
kDifOk);
}
TEST_F(CauseTest, NullArgs) {
bool flag;
EXPECT_EQ(dif_alert_handler_alert_is_cause(nullptr, 5, &flag), kDifBadArg);
EXPECT_EQ(dif_alert_handler_alert_is_cause(&alert_handler_, 5, nullptr),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_alert_acknowledge(nullptr, 11), kDifBadArg);
EXPECT_EQ(dif_alert_handler_local_alert_is_cause(
nullptr, kDifAlertHandlerLocalAlertEscalationPingFail, &flag),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_local_alert_is_cause(
&alert_handler_, kDifAlertHandlerLocalAlertEscalationPingFail,
nullptr),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_local_alert_acknowledge(
nullptr, kDifAlertHandlerLocalAlertEscalationIntegrityFail),
kDifBadArg);
}
class EscalationTest : public AlertHandlerTest {};
TEST_F(EscalationTest, CanClear) {
bool flag;
EXPECT_READ32(ALERT_HANDLER_CLASSB_CLR_REGWEN_REG_OFFSET, true);
EXPECT_EQ(dif_alert_handler_escalation_can_clear(
&alert_handler_, kDifAlertHandlerClassB, &flag),
kDifOk);
EXPECT_TRUE(flag);
EXPECT_READ32(ALERT_HANDLER_CLASSA_CLR_REGWEN_REG_OFFSET, false);
EXPECT_EQ(dif_alert_handler_escalation_can_clear(
&alert_handler_, kDifAlertHandlerClassA, &flag),
kDifOk);
EXPECT_FALSE(flag);
}
TEST_F(EscalationTest, Disable) {
EXPECT_WRITE32(ALERT_HANDLER_CLASSC_CLR_REGWEN_REG_OFFSET, true);
EXPECT_EQ(dif_alert_handler_escalation_disable_clearing(
&alert_handler_, kDifAlertHandlerClassC),
kDifOk);
}
TEST_F(EscalationTest, Clear) {
EXPECT_WRITE32_SHADOWED(ALERT_HANDLER_CLASSD_CLR_SHADOWED_REG_OFFSET, true);
EXPECT_EQ(dif_alert_handler_escalation_clear(&alert_handler_,
kDifAlertHandlerClassD),
kDifOk);
}
TEST_F(EscalationTest, NullArgs) {
bool flag;
EXPECT_EQ(dif_alert_handler_escalation_can_clear(
nullptr, kDifAlertHandlerClassB, &flag),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_escalation_can_clear(
&alert_handler_, kDifAlertHandlerClassB, nullptr),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_escalation_disable_clearing(
nullptr, kDifAlertHandlerClassC),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_escalation_clear(nullptr, kDifAlertHandlerClassD),
kDifBadArg);
}
class GetterTest : public AlertHandlerTest {};
TEST_F(GetterTest, GetAcc) {
uint16_t alerts;
EXPECT_READ32(ALERT_HANDLER_CLASSB_ACCUM_CNT_REG_OFFSET, 0xaaaa);
EXPECT_EQ(dif_alert_handler_get_accumulator(&alert_handler_,
kDifAlertHandlerClassB, &alerts),
kDifOk);
EXPECT_EQ(alerts, 0xaaaa);
}
TEST_F(GetterTest, GetCycles) {
uint32_t cycles;
EXPECT_READ32(ALERT_HANDLER_CLASSD_ESC_CNT_REG_OFFSET, 0xaaaaaaaa);
EXPECT_EQ(dif_alert_handler_get_escalation_counter(
&alert_handler_, kDifAlertHandlerClassD, &cycles),
kDifOk);
EXPECT_EQ(cycles, 0xaaaaaaaa);
}
TEST_F(GetterTest, GetState) {
dif_alert_handler_class_state_t state;
EXPECT_READ32(ALERT_HANDLER_CLASSC_STATE_REG_OFFSET,
ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_TIMEOUT);
EXPECT_EQ(dif_alert_handler_get_class_state(&alert_handler_,
kDifAlertHandlerClassC, &state),
kDifOk);
EXPECT_EQ(state, kDifAlertHandlerClassStateTimeout);
EXPECT_READ32(ALERT_HANDLER_CLASSA_STATE_REG_OFFSET,
ALERT_HANDLER_CLASSA_STATE_CLASSA_STATE_VALUE_PHASE2);
EXPECT_EQ(dif_alert_handler_get_class_state(&alert_handler_,
kDifAlertHandlerClassA, &state),
kDifOk);
EXPECT_EQ(state, kDifAlertHandlerClassStatePhase2);
}
TEST_F(GetterTest, NullArgs) {
uint16_t alerts;
EXPECT_EQ(dif_alert_handler_get_accumulator(nullptr, kDifAlertHandlerClassB,
&alerts),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_get_accumulator(&alert_handler_,
kDifAlertHandlerClassB, nullptr),
kDifBadArg);
uint32_t cycles;
EXPECT_EQ(dif_alert_handler_get_escalation_counter(
nullptr, kDifAlertHandlerClassB, &cycles),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_get_escalation_counter(
&alert_handler_, kDifAlertHandlerClassB, nullptr),
kDifBadArg);
dif_alert_handler_class_state_t state;
EXPECT_EQ(dif_alert_handler_get_class_state(nullptr, kDifAlertHandlerClassC,
&state),
kDifBadArg);
EXPECT_EQ(dif_alert_handler_get_class_state(&alert_handler_,
kDifAlertHandlerClassC, nullptr),
kDifBadArg);
}
} // namespace
} // namespace dif_alert_handler_unittest