[dif/alert_handler] Add class locking DIFs. This commit adds two DIFs to lock the configuration CSRs of a specific alert class, and check if a specific alert class' CSRs are locked. This gives users fine grained control over the locking of a specific alert class' configuration. This addresses a task in #9899. Signed-off-by: Timothy Trippel <ttrippel@google.com>
diff --git a/sw/device/lib/dif/dif_alert_handler.c b/sw/device/lib/dif/dif_alert_handler.c index 62433c1..2266287 100644 --- a/sw/device/lib/dif/dif_alert_handler.c +++ b/sw/device/lib/dif/dif_alert_handler.c
@@ -20,13 +20,21 @@ "Expected seven local alerts!"); /** - * Macro for generating the case statements for local alert lock CSRS. + * Macro for generating the case statements for local alert lock CSRs. */ #define LOC_ALERT_REGWENS_CASE_(loc_alert_, value_) \ case loc_alert_: \ regwen_offset = ALERT_HANDLER_LOC_ALERT_REGWEN_##value_##_REG_OFFSET; \ break; +/** + * Macro for generating the case statements for class lock CSRs. + */ +#define ALERT_CLASS_REGWENS_CASE_(class_, value_) \ + case kDifAlertHandlerClass##class_: \ + regwen_offset = ALERT_HANDLER_CLASS##class_##_REGWEN_REG_OFFSET; \ + break; + // TODO(#9899): add static assert for accumulator_threshold field size /** @@ -552,6 +560,44 @@ return kDifOk; } +dif_result_t dif_alert_handler_lock_class( + const dif_alert_handler_t *alert_handler, + dif_alert_handler_class_t alert_class) { + if (alert_handler == NULL) { + return kDifBadArg; + } + + ptrdiff_t regwen_offset; + switch (alert_class) { + LIST_OF_CLASSES(ALERT_CLASS_REGWENS_CASE_) + default: + return kDifBadArg; + } + + mmio_region_write32(alert_handler->base_addr, regwen_offset, 0); + + return kDifOk; +} + +dif_result_t dif_alert_handler_is_class_locked( + const dif_alert_handler_t *alert_handler, + dif_alert_handler_class_t alert_class, bool *is_locked) { + if (alert_handler == NULL || is_locked == NULL) { + return kDifBadArg; + } + + ptrdiff_t regwen_offset; + switch (alert_class) { + LIST_OF_CLASSES(ALERT_CLASS_REGWENS_CASE_) + default: + return kDifBadArg; + } + + *is_locked = !mmio_region_read32(alert_handler->base_addr, regwen_offset); + + return kDifOk; +} + dif_result_t dif_alert_handler_lock_ping_timer( const dif_alert_handler_t *alert_handler) { if (alert_handler == NULL) { @@ -947,3 +993,4 @@ } #undef LOC_ALERT_REGWENS_CASE_ +#undef ALERT_CLASS_REGWENS_CASE_
diff --git a/sw/device/lib/dif/dif_alert_handler.h b/sw/device/lib/dif/dif_alert_handler.h index 4ad1656..8116c5f 100644 --- a/sw/device/lib/dif/dif_alert_handler.h +++ b/sw/device/lib/dif/dif_alert_handler.h
@@ -493,6 +493,37 @@ dif_alert_handler_local_alert_t local_alert, bool *is_locked); /** + * Locks out an alert handler class configuration. + * + * This operation cannot be undone, and should be performed at the end of + * configuring the alert handler in early boot. + * + * This function is reentrant: calling it while functionality is locked will + * have no effect and return `kDifOk`. + * + * @param alert_handler An alert handler handle. + * @param alert_class The alert class to lock. + * @return The result of the operation. + */ +OT_WARN_UNUSED_RESULT +dif_result_t dif_alert_handler_lock_class( + const dif_alert_handler_t *alert_handler, + dif_alert_handler_class_t alert_class); + +/** + * Checks whether an alert handler's class is locked. + * + * @param alert_handler An alert handler handle. + * @param alert_class The alert class to check is locked. + * @param is_locked Out-param for the locked state. + * @return The result of the operation. + */ +OT_WARN_UNUSED_RESULT +dif_result_t dif_alert_handler_is_class_locked( + const dif_alert_handler_t *alert_handler, + dif_alert_handler_class_t alert_class, bool *is_locked); + +/** * Locks out alert handler ping timer configuration. * * This operation cannot be undone, and should be performed at the end of
diff --git a/sw/device/lib/dif/dif_alert_handler_unittest.cc b/sw/device/lib/dif/dif_alert_handler_unittest.cc index 371934f..6a08682 100644 --- a/sw/device/lib/dif/dif_alert_handler_unittest.cc +++ b/sw/device/lib/dif/dif_alert_handler_unittest.cc
@@ -7,6 +7,8 @@ #include <cstring> #include <limits> #include <ostream> +#include <tuple> +#include <vector> #include "gtest/gtest.h" #include "sw/device/lib/base/mmio.h" @@ -731,6 +733,75 @@ kDifBadArg); } +class ClassLockTest : public AlertHandlerTest, + public testing::WithParamInterface< + std::tuple<dif_alert_handler_class_t, uint32_t>> {}; + +static std::vector<std::tuple<dif_alert_handler_class_t, uint32_t>> + class_regwen_pairs{ + std::tuple<dif_alert_handler_class_t, uint32_t>{ + kDifAlertHandlerClassA, ALERT_HANDLER_CLASSA_REGWEN_REG_OFFSET}, + std::tuple<dif_alert_handler_class_t, uint32_t>{ + kDifAlertHandlerClassB, ALERT_HANDLER_CLASSB_REGWEN_REG_OFFSET}, + std::tuple<dif_alert_handler_class_t, uint32_t>{ + kDifAlertHandlerClassC, ALERT_HANDLER_CLASSC_REGWEN_REG_OFFSET}, + std::tuple<dif_alert_handler_class_t, uint32_t>{ + kDifAlertHandlerClassD, ALERT_HANDLER_CLASSD_REGWEN_REG_OFFSET}}; + +TEST_P(ClassLockTest, IsClassLocked) { + dif_alert_handler_class_t alert_class = std::get<0>(GetParam()); + uint32_t regwen_offset = std::get<1>(GetParam()); + bool is_locked = true; + + EXPECT_READ32(regwen_offset, ALERT_HANDLER_CLASSA_REGWEN_REG_RESVAL); + EXPECT_EQ(dif_alert_handler_is_class_locked(&alert_handler_, alert_class, + &is_locked), + kDifOk); + EXPECT_FALSE(is_locked); + + is_locked = false; + EXPECT_READ32(regwen_offset, 0); + EXPECT_EQ(dif_alert_handler_is_class_locked(&alert_handler_, alert_class, + &is_locked), + kDifOk); + EXPECT_TRUE(is_locked); +} + +INSTANTIATE_TEST_SUITE_P(AllClassesLockedAndUnlocked, ClassLockTest, + testing::ValuesIn(class_regwen_pairs)); + +TEST_P(ClassLockTest, LockClass) { + dif_alert_handler_class_t alert_class = std::get<0>(GetParam()); + uint32_t regwen_offset = std::get<1>(GetParam()); + + EXPECT_WRITE32(regwen_offset, 0); + EXPECT_EQ(dif_alert_handler_lock_class(&alert_handler_, alert_class), kDifOk); +} + +INSTANTIATE_TEST_SUITE_P(LockAllClasses, ClassLockTest, + testing::ValuesIn(class_regwen_pairs)); + +TEST_F(ClassLockTest, BadArgs) { + bool is_locked; + EXPECT_EQ(dif_alert_handler_is_class_locked(nullptr, kDifAlertHandlerClassA, + &is_locked), + kDifBadArg); + EXPECT_EQ(dif_alert_handler_is_class_locked( + &alert_handler_, + static_cast<dif_alert_handler_class_t>(kClasses), &is_locked), + kDifBadArg); + EXPECT_EQ(dif_alert_handler_is_class_locked(&alert_handler_, + kDifAlertHandlerClassD, nullptr), + kDifBadArg); + + EXPECT_EQ(dif_alert_handler_lock_class(nullptr, kDifAlertHandlerClassA), + kDifBadArg); + EXPECT_EQ( + dif_alert_handler_lock_class( + &alert_handler_, static_cast<dif_alert_handler_class_t>(kClasses)), + kDifBadArg); +} + class PingTimerLockTest : public AlertHandlerTest {}; TEST_F(PingTimerLockTest, IsPingTimerLocked) {