oem-ampere: eventManager: Handle `BootProgress` sensor event
Add Ampere OEM code to handle the `sensorEvent` for PLDM `BootProgress`
sensor. In Ampere system, the SOC termini will have the TID 1 or 2. The
Ampere OEM EventManager will check the terminus TID to confirm about the
terminus type. Base on the value of `BootProgress` sensor, the OEM code
will add the Redfish Log to report the boot progress of Ampere SoC.
Tested:
1. Power on the host.
2. Check the Redfish SEL log.
Signed-off-by: Chau Ly <chaul@amperecomputing.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: Icc51537ef17ee8eb4b5b571eafeea7b5d7763cbe
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 6c30c52..9c45ef8 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -219,6 +219,22 @@
oemPlatformHandler = handler;
}
+ /* @brief Method to register event handlers
+ *
+ * @param[in] handler - oem event handlers
+ */
+ inline void registerEventHandlers(EventType eventId, EventHandlers handlers)
+ {
+ // Try to emplace the eventId with an empty vector if it doesn't exist
+ auto [iter,
+ inserted] = eventHandlers.try_emplace(eventId, EventHandlers{});
+
+ for (const auto& handler : handlers)
+ {
+ iter->second.emplace_back(handler);
+ }
+ }
+
/** @brief Handler for GetPDR
*
* @param[in] request - Request message payload
diff --git a/meson.build b/meson.build
index 32684b3..681dd7a 100644
--- a/meson.build
+++ b/meson.build
@@ -138,6 +138,12 @@
)
conf_data.set('SENSOR_POLLING_TIME', get_option('sensor-polling-time'))
+oem_files = []
+if get_option('oem-ampere').enabled()
+ add_project_arguments('-DOEM_AMPERE', language : 'cpp')
+ subdir('oem/ampere')
+endif
+
configure_file(output: 'config.h', configuration: conf_data)
add_project_arguments(
@@ -247,6 +253,7 @@
'platform-mc/sensor_manager.cpp',
'platform-mc/numeric_sensor.cpp',
'platform-mc/event_manager.cpp',
+ oem_files,
'requester/mctp_endpoint_discovery.cpp',
implicit_include_directories: false,
dependencies: deps,
diff --git a/meson.options b/meson.options
index 8a7138a..93ac021 100644
--- a/meson.options
+++ b/meson.options
@@ -175,6 +175,15 @@
description: 'OEM-IBM: max DMA size'
)
+
+## OEM AMPERE Options
+option(
+ 'oem-ampere',
+ type: 'feature',
+ description: 'Enable AMPERE OEM PLDM',
+ value: 'disabled',
+)
+
## Default Sensor Update Interval Options
option(
'default-sensor-update-interval',
diff --git a/oem/ampere/event/meson.build b/oem/ampere/event/meson.build
new file mode 100644
index 0000000..6dc6a9e
--- /dev/null
+++ b/oem/ampere/event/meson.build
@@ -0,0 +1 @@
+oem_files += files('oem_event_manager.cpp',)
\ No newline at end of file
diff --git a/oem/ampere/event/oem_event_manager.cpp b/oem/ampere/event/oem_event_manager.cpp
new file mode 100644
index 0000000..e99288d
--- /dev/null
+++ b/oem/ampere/event/oem_event_manager.cpp
@@ -0,0 +1,427 @@
+#include "oem_event_manager.hpp"
+
+#include "requester/handler.hpp"
+#include "requester/request.hpp"
+
+#include <config.h>
+#include <libpldm/pldm.h>
+#include <libpldm/utils.h>
+#include <systemd/sd-journal.h>
+
+#include <phosphor-logging/lg2.hpp>
+#include <xyz/openbmc_project/Logging/Entry/server.hpp>
+
+#include <algorithm>
+#include <map>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+namespace pldm
+{
+namespace oem_ampere
+{
+namespace boot_stage = boot::stage;
+
+constexpr const char* BIOSFWPanicRegistry =
+ "OpenBMC.0.1.BIOSFirmwarePanicReason.Warning";
+constexpr auto maxDIMMIdxBitNum = 24;
+
+/*
+ An array of possible boot status of a boot stage.
+ The index maps with byte 0 of boot code.
+*/
+std::array<std::string, 3> bootStatMsg = {" booting", " completed", " failed"};
+
+/*
+ An array of possible boot status of DDR training stage.
+ The index maps with byte 0 of boot code.
+*/
+std::array<std::string, 3> ddrTrainingMsg = {
+ " progress started", " in-progress", " progress completed"};
+
+/*
+ In Ampere systems, BMC only directly communicates with MCTP/PLDM SoC
+ EPs through SMBus and PCIe. When host boots up, SMBUS interface
+ comes up first. In this interface, BMC is bus owner.
+
+ mctpd will set the EID 0x14 for S0 and 0x16 for S1 (if available).
+ pldmd will always use TID 1 for S0 and TID 2 for S1 (if available).
+*/
+EventToMsgMap_t tidToSocketNameMap = {{1, "SOCKET 0"}, {2, "SOCKET 1"}};
+
+/*
+ A map between sensor IDs and their names in string.
+ Using pldm::oem::sensor_ids
+*/
+EventToMsgMap_t sensorIdToStrMap = {{BOOT_OVERALL, "BOOT_OVERALL"}};
+
+/*
+ A map between the boot stages and logging strings.
+ Using pldm::oem::boot::stage::boot_stage
+*/
+EventToMsgMap_t bootStageToMsgMap = {
+ {boot_stage::SECPRO, "SECpro"},
+ {boot_stage::MPRO, "Mpro"},
+ {boot_stage::ATF_BL1, "ATF BL1"},
+ {boot_stage::ATF_BL2, "ATF BL2"},
+ {boot_stage::DDR_INITIALIZATION, "DDR initialization"},
+ {boot_stage::DDR_TRAINING, "DDR training"},
+ {boot_stage::S0_DDR_TRAINING_FAILURE, "DDR training failure"},
+ {boot_stage::ATF_BL31, "ATF BL31"},
+ {boot_stage::ATF_BL32, "ATF BL32"},
+ {boot_stage::S1_DDR_TRAINING_FAILURE, "DDR training failure"},
+ {boot_stage::UEFI_STATUS_CLASS_CODE_MIN,
+ "ATF BL33 (UEFI) booting status = "}};
+
+/*
+ A map between log level and the registry used for Redfish SEL log
+ Using pldm::oem::log_level
+*/
+std::unordered_map<log_level, std::string> logLevelToRedfishMsgIdMap = {
+ {log_level::BIOSFWPANIC, BIOSFWPanicRegistry}};
+
+std::string
+ OemEventManager::prefixMsgStrCreation(pldm_tid_t tid, uint16_t sensorId)
+{
+ std::string description;
+ if (!tidToSocketNameMap.contains(tid))
+ {
+ description += "TID " + std::to_string(tid) + ": ";
+ }
+ else
+ {
+ description += tidToSocketNameMap[tid] + ": ";
+ }
+
+ if (!sensorIdToStrMap.contains(sensorId))
+ {
+ description += "Sensor ID " + std::to_string(sensorId) + ": ";
+ }
+ else
+ {
+ description += sensorIdToStrMap[sensorId] + ": ";
+ }
+
+ return description;
+}
+
+void OemEventManager::sendJournalRedfish(const std::string& description,
+ log_level& logLevel)
+{
+ if (description.empty())
+ {
+ return;
+ }
+
+ if (!logLevelToRedfishMsgIdMap.contains(logLevel))
+ {
+ lg2::error("Invalid {LEVEL} Description {DES}", "LEVEL", logLevel,
+ "DES", description);
+ return;
+ }
+ auto redfishMsgId = logLevelToRedfishMsgIdMap[logLevel];
+ lg2::info("MESSAGE={DES}", "DES", description, "REDFISH_MESSAGE_ID",
+ redfishMsgId, "REDFISH_MESSAGE_ARGS", description);
+}
+
+std::string OemEventManager::dimmIdxsToString(uint32_t dimmIdxs)
+{
+ std::string description;
+ for (const auto bitIdx : std::views::iota(0, maxDIMMIdxBitNum))
+ {
+ if (dimmIdxs & (static_cast<uint32_t>(1) << bitIdx))
+ {
+ description += " #" + std::to_string(bitIdx);
+ }
+ }
+ return description;
+}
+
+void OemEventManager::handleBootOverallEvent(
+ pldm_tid_t /*tid*/, uint16_t /*sensorId*/, uint32_t presentReading)
+{
+ log_level logLevel{log_level::OK};
+ std::string description;
+ std::stringstream strStream;
+
+ uint8_t byte0 = (presentReading & 0x000000ff);
+ uint8_t byte1 = (presentReading & 0x0000ff00) >> 8;
+ uint8_t byte2 = (presentReading & 0x00ff0000) >> 16;
+ uint8_t byte3 = (presentReading & 0xff000000) >> 24;
+ /*
+ * Handle SECpro, Mpro, ATF BL1, ATF BL2, ATF BL31,
+ * ATF BL32 and DDR initialization
+ */
+ if (bootStageToMsgMap.contains(byte3))
+ {
+ // Boot stage adding
+ description += bootStageToMsgMap[byte3];
+
+ switch (byte3)
+ {
+ case boot_stage::DDR_TRAINING:
+ if (byte0 >= ddrTrainingMsg.size())
+ {
+ logLevel = log_level::BIOSFWPANIC;
+ description += " unknown status";
+ }
+ else
+ {
+ description += ddrTrainingMsg[byte0];
+ }
+ if (0x01 == byte0)
+ {
+ // Add complete percentage
+ description += " at " + std::to_string(byte1) + "%";
+ }
+ break;
+ case boot_stage::S0_DDR_TRAINING_FAILURE:
+ case boot_stage::S1_DDR_TRAINING_FAILURE:
+ // ddr_training_status_msg()
+ logLevel = log_level::BIOSFWPANIC;
+ description += " at DIMMs:";
+ // dimmIdxs = presentReading & 0x00ffffff;
+ description += dimmIdxsToString(presentReading & 0x00ffffff);
+ description += " of socket ";
+ description +=
+ (boot_stage::S0_DDR_TRAINING_FAILURE == byte3) ? "0" : "1";
+ break;
+ default:
+ if (byte0 >= bootStatMsg.size())
+ {
+ logLevel = log_level::BIOSFWPANIC;
+ description += " unknown status";
+ }
+ else
+ {
+ description += bootStatMsg[byte0];
+ }
+ break;
+ }
+
+ // Sensor report action is fail
+ if (boot::status::BOOT_STATUS_FAILURE == byte2)
+ {
+ logLevel = log_level::BIOSFWPANIC;
+ }
+ }
+ else
+ {
+ if (byte3 <= boot_stage::UEFI_STATUS_CLASS_CODE_MAX)
+ {
+ description +=
+ bootStageToMsgMap[boot_stage::UEFI_STATUS_CLASS_CODE_MIN];
+
+ strStream
+ << "Segment (0x" << std::setfill('0') << std::hex
+ << std::setw(8) << static_cast<uint32_t>(presentReading)
+ << "), Status Class (0x" << std::setw(2)
+ << static_cast<uint32_t>(byte3) << "), Status SubClass (0x"
+ << std::setw(2) << static_cast<uint32_t>(byte2)
+ << "), Operation Code (0x" << std::setw(4)
+ << static_cast<uint32_t>((presentReading & 0xffff0000) >> 16)
+ << ")" << std::dec;
+
+ description += strStream.str();
+ }
+ }
+
+ // Log to Redfish event
+ sendJournalRedfish(description, logLevel);
+}
+
+int OemEventManager::processNumericSensorEvent(
+ pldm_tid_t tid, uint16_t sensorId, const uint8_t* sensorData,
+ size_t sensorDataLength)
+{
+ uint8_t eventState = 0;
+ uint8_t previousEventState = 0;
+ uint8_t sensorDataSize = 0;
+ uint32_t presentReading;
+ auto rc = decode_numeric_sensor_data(
+ sensorData, sensorDataLength, &eventState, &previousEventState,
+ &sensorDataSize, &presentReading);
+ if (rc)
+ {
+ lg2::error(
+ "Failed to decode numericSensorState event for terminus ID {TID}, error {RC} ",
+ "TID", tid, "RC", rc);
+ return rc;
+ }
+
+ switch (sensorId)
+ {
+ case BOOT_OVERALL:
+ handleBootOverallEvent(tid, sensorId, presentReading);
+ break;
+ default:
+ std::string description;
+ std::stringstream strStream;
+ log_level logLevel = log_level::OK;
+
+ description += "SENSOR_EVENT : NUMERIC_SENSOR_STATE: ";
+ description += prefixMsgStrCreation(tid, sensorId);
+ strStream << std::setfill('0') << std::hex << "eventState 0x"
+ << std::setw(2) << static_cast<uint32_t>(eventState)
+ << " previousEventState 0x" << std::setw(2)
+ << static_cast<uint32_t>(previousEventState)
+ << " sensorDataSize 0x" << std::setw(2)
+ << static_cast<uint32_t>(sensorDataSize)
+ << " presentReading 0x" << std::setw(8)
+ << static_cast<uint32_t>(presentReading) << std::dec;
+ description += strStream.str();
+
+ sendJournalRedfish(description, logLevel);
+ break;
+ }
+ return PLDM_SUCCESS;
+}
+
+int OemEventManager::processStateSensorEvent(pldm_tid_t tid, uint16_t sensorId,
+ const uint8_t* sensorData,
+ size_t sensorDataLength)
+{
+ uint8_t sensorOffset = 0;
+ uint8_t eventState = 0;
+ uint8_t previousEventState = 0;
+
+ auto rc =
+ decode_state_sensor_data(sensorData, sensorDataLength, &sensorOffset,
+ &eventState, &previousEventState);
+ if (rc)
+ {
+ lg2::error(
+ "Failed to decode stateSensorState event for terminus ID {TID}, error {RC}",
+ "TID", tid, "RC", rc);
+ return rc;
+ }
+
+ std::string description;
+ std::stringstream strStream;
+ log_level logLevel = log_level::OK;
+
+ description += "SENSOR_EVENT : STATE_SENSOR_STATE: ";
+ description += prefixMsgStrCreation(tid, sensorId);
+ strStream << std::setfill('0') << std::hex << "sensorOffset 0x"
+ << std::setw(2) << static_cast<uint32_t>(sensorOffset)
+ << "eventState 0x" << std::setw(2)
+ << static_cast<uint32_t>(eventState) << " previousEventState 0x"
+ << std::setw(2) << static_cast<uint32_t>(previousEventState)
+ << std::dec;
+ description += strStream.str();
+
+ sendJournalRedfish(description, logLevel);
+
+ return PLDM_SUCCESS;
+}
+
+int OemEventManager::processSensorOpStateEvent(
+ pldm_tid_t tid, uint16_t sensorId, const uint8_t* sensorData,
+ size_t sensorDataLength)
+{
+ uint8_t present_op_state = 0;
+ uint8_t previous_op_state = 0;
+
+ auto rc = decode_sensor_op_data(sensorData, sensorDataLength,
+ &present_op_state, &previous_op_state);
+ if (rc)
+ {
+ lg2::error(
+ "Failed to decode sensorOpState event for terminus ID {TID}, error {RC}",
+ "TID", tid, "RC", rc);
+ return rc;
+ }
+
+ std::string description;
+ std::stringstream strStream;
+ log_level logLevel = log_level::OK;
+
+ description += "SENSOR_EVENT : SENSOR_OP_STATE: ";
+ description += prefixMsgStrCreation(tid, sensorId);
+ strStream << std::setfill('0') << std::hex << "present_op_state 0x"
+ << std::setw(2) << static_cast<uint32_t>(present_op_state)
+ << "previous_op_state 0x" << std::setw(2)
+ << static_cast<uint32_t>(previous_op_state) << std::dec;
+ description += strStream.str();
+
+ sendJournalRedfish(description, logLevel);
+
+ return PLDM_SUCCESS;
+}
+
+int OemEventManager::handleSensorEvent(
+ const pldm_msg* request, size_t payloadLength, uint8_t /* formatVersion */,
+ pldm_tid_t tid, size_t eventDataOffset)
+{
+ /* This OEM event handler is only used for SoC terminus*/
+ if (!tidToSocketNameMap.contains(tid))
+ {
+ return PLDM_SUCCESS;
+ }
+ auto eventData =
+ reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
+ auto eventDataSize = payloadLength - eventDataOffset;
+
+ uint16_t sensorId = 0;
+ uint8_t sensorEventClassType = 0;
+ size_t eventClassDataOffset = 0;
+ auto rc =
+ decode_sensor_event_data(eventData, eventDataSize, &sensorId,
+ &sensorEventClassType, &eventClassDataOffset);
+ if (rc)
+ {
+ lg2::error("Failed to decode sensor event data return code {RC}.", "RC",
+ rc);
+ return rc;
+ }
+ const uint8_t* sensorData = eventData + eventClassDataOffset;
+ size_t sensorDataLength = eventDataSize - eventClassDataOffset;
+
+ switch (sensorEventClassType)
+ {
+ case PLDM_NUMERIC_SENSOR_STATE:
+ {
+ return processNumericSensorEvent(tid, sensorId, sensorData,
+ sensorDataLength);
+ }
+ case PLDM_STATE_SENSOR_STATE:
+ {
+ return processStateSensorEvent(tid, sensorId, sensorData,
+ sensorDataLength);
+ }
+ case PLDM_SENSOR_OP_STATE:
+ {
+ return processSensorOpStateEvent(tid, sensorId, sensorData,
+ sensorDataLength);
+ }
+ default:
+ std::string description;
+ std::stringstream strStream;
+ log_level logLevel = log_level::OK;
+
+ description += "SENSOR_EVENT : Unsupported Sensor Class " +
+ std::to_string(sensorEventClassType) + ": ";
+ description += prefixMsgStrCreation(tid, sensorId);
+ strStream << std::setfill('0') << std::hex
+ << std::setw(sizeof(sensorData) * 2) << "Sensor data: ";
+
+ auto dataPtr = sensorData;
+ for ([[maybe_unused]] const auto& i :
+ std::views::iota(0, (int)sensorDataLength))
+ {
+ strStream << "0x" << static_cast<uint32_t>(*dataPtr);
+ dataPtr += sizeof(sensorData);
+ }
+
+ description += strStream.str();
+
+ sendJournalRedfish(description, logLevel);
+ }
+ lg2::info("Unsupported class type {CLASSTYPE}", "CLASSTYPE",
+ sensorEventClassType);
+ return PLDM_ERROR;
+}
+
+} // namespace oem_ampere
+} // namespace pldm
diff --git a/oem/ampere/event/oem_event_manager.hpp b/oem/ampere/event/oem_event_manager.hpp
new file mode 100644
index 0000000..15b615f
--- /dev/null
+++ b/oem/ampere/event/oem_event_manager.hpp
@@ -0,0 +1,176 @@
+#pragma once
+
+#include "libpldm/pldm.h"
+
+#include "common/instance_id.hpp"
+#include "common/types.hpp"
+#include "oem_event_manager.hpp"
+#include "platform-mc/manager.hpp"
+#include "requester/handler.hpp"
+#include "requester/request.hpp"
+
+namespace pldm
+{
+namespace oem_ampere
+{
+using namespace pldm::pdr;
+
+using EventToMsgMap_t = std::unordered_map<uint8_t, std::string>;
+
+enum sensor_ids
+{
+ BOOT_OVERALL = 175,
+};
+
+namespace boot
+{
+namespace status
+{
+enum boot_status
+{
+ BOOT_STATUS_SUCCESS = 0x80,
+ BOOT_STATUS_FAILURE = 0x81,
+};
+} // namespace status
+namespace stage
+{
+enum boot_stage
+{
+ UEFI_STATUS_CLASS_CODE_MIN = 0x00,
+ UEFI_STATUS_CLASS_CODE_MAX = 0x7f,
+ SECPRO = 0x90,
+ MPRO = 0x91,
+ ATF_BL1 = 0x92,
+ ATF_BL2 = 0x93,
+ DDR_INITIALIZATION = 0x94,
+ DDR_TRAINING = 0x95,
+ S0_DDR_TRAINING_FAILURE = 0x96,
+ ATF_BL31 = 0x97,
+ ATF_BL32 = 0x98,
+ S1_DDR_TRAINING_FAILURE = 0x99,
+};
+} // namespace stage
+} // namespace boot
+
+enum class log_level : int
+{
+ OK,
+ BIOSFWPANIC,
+};
+
+/**
+ * @brief OemEventManager
+ *
+ *
+ */
+class OemEventManager
+{
+ public:
+ OemEventManager() = delete;
+ OemEventManager(const OemEventManager&) = delete;
+ OemEventManager(OemEventManager&&) = delete;
+ OemEventManager& operator=(const OemEventManager&) = delete;
+ OemEventManager& operator=(OemEventManager&&) = delete;
+ virtual ~OemEventManager() = default;
+
+ explicit OemEventManager(
+ sdeventplus::Event& event,
+ requester::Handler<requester::Request>* /* handler */,
+ pldm::InstanceIdDb& /* instanceIdDb */) : event(event) {};
+
+ /** @brief Decode sensor event messages and handle correspondingly.
+ *
+ * @param[in] request - the request message of sensor event
+ * @param[in] payloadLength - the payload length of sensor event
+ * @param[in] formatVersion - the format version of sensor event
+ * @param[in] tid - TID
+ * @param[in] eventDataOffset - the event data offset of sensor event
+ *
+ * @return int - returned error code
+ */
+ int handleSensorEvent(const pldm_msg* request, size_t payloadLength,
+ uint8_t /* formatVersion */, pldm_tid_t tid,
+ size_t eventDataOffset);
+
+ protected:
+ /** @brief Create prefix string for logging message.
+ *
+ * @param[in] tid - TID
+ * @param[in] sensorId - Sensor ID
+ *
+ * @return std::string - the prefeix string
+ */
+ std::string prefixMsgStrCreation(pldm_tid_t tid, uint16_t sensorId);
+
+ /** @brief Log the message into Redfish SEL.
+ *
+ * @param[in] description - the logging message
+ * @param[in] logLevel - the logging level
+ */
+ void sendJournalRedfish(const std::string& description,
+ log_level& logLevel);
+
+ /** @brief Convert the one-hot DIMM index byte into a string of DIMM
+ * indexes.
+ *
+ * @param[in] dimmIdxs - the one-hot DIMM index byte
+ *
+ * @return std::string - the string of DIMM indexes
+ */
+ std::string dimmIdxsToString(uint32_t dimmIdxs);
+
+ /** @brief Handle numeric sensor event message from boot overall sensor.
+ *
+ * @param[in] tid - TID
+ * @param[in] sensorId - Sensor ID
+ * @param[in] presentReading - the present reading of the sensor
+ */
+ void handleBootOverallEvent(pldm_tid_t /*tid*/, uint16_t /*sensorId*/,
+ uint32_t presentReading);
+
+ /** @brief Handle numeric sensor event messages.
+ *
+ * @param[in] tid - TID
+ * @param[in] sensorId - Sensor ID
+ * @param[in] sensorData - the sensor data
+ * @param[in] sensorDataLength - the length of sensor data
+ *
+ * @return int - returned error code
+ */
+ int processNumericSensorEvent(pldm_tid_t tid, uint16_t sensorId,
+ const uint8_t* sensorData,
+ size_t sensorDataLength);
+
+ /** @brief Handle state sensor event messages.
+ *
+ * @param[in] tid - TID
+ * @param[in] sensorId - Sensor ID
+ * @param[in] sensorData - the sensor data
+ * @param[in] sensorDataLength - the length of sensor data
+ *
+ * @return int - returned error code
+ */
+ int processStateSensorEvent(pldm_tid_t tid, uint16_t sensorId,
+ const uint8_t* sensorData,
+ size_t sensorDataLength);
+
+ /** @brief Handle op state sensor event messages.
+ *
+ * @param[in] tid - TID
+ * @param[in] sensorId - Sensor ID
+ * @param[in] sensorData - the sensor data
+ * @param[in] sensorDataLength - the length of sensor data
+ *
+ * @return int - returned error code
+ */
+ int processSensorOpStateEvent(pldm_tid_t tid, uint16_t sensorId,
+ const uint8_t* sensorData,
+ size_t sensorDataLength);
+
+ /** @brief reference of main event loop of pldmd, primarily used to schedule
+ * work
+ */
+ sdeventplus::Event& event;
+};
+} // namespace oem_ampere
+} // namespace pldm
diff --git a/oem/ampere/meson.build b/oem/ampere/meson.build
new file mode 100644
index 0000000..8c37ab1
--- /dev/null
+++ b/oem/ampere/meson.build
@@ -0,0 +1 @@
+subdir('event')
\ No newline at end of file
diff --git a/oem/ampere/oem_ampere.hpp b/oem/ampere/oem_ampere.hpp
new file mode 100644
index 0000000..00d8b90
--- /dev/null
+++ b/oem/ampere/oem_ampere.hpp
@@ -0,0 +1,109 @@
+#pragma once
+#include "../../common/utils.hpp"
+#include "../../libpldmresponder/base.hpp"
+#include "../../libpldmresponder/bios.hpp"
+#include "../../libpldmresponder/fru.hpp"
+#include "../../libpldmresponder/platform.hpp"
+#include "../../oem/ampere/event/oem_event_manager.hpp"
+#include "../../platform-mc/manager.hpp"
+#include "../../pldmd/invoker.hpp"
+#include "../../requester/request.hpp"
+
+namespace pldm
+{
+namespace oem_ampere
+{
+
+/**
+ * @class OemAMPERE
+ *
+ * @brief class for creating all the OEM AMPERE handlers
+ *
+ * Only in case of OEM_AMPERE this class object will be instantiated
+ */
+class OemAMPERE
+{
+ public:
+ OemAMPERE() = delete;
+ OemAMPERE& operator=(const OemAMPERE&) = delete;
+ OemAMPERE(OemAMPERE&&) = delete;
+ OemAMPERE& operator=(OemAMPERE&&) = delete;
+
+ public:
+ /** Constructs OemAMPERE object
+ *
+ * @param[in] dBusIntf - D-Bus handler
+ * @param[in] mctp_fd - fd of MCTP communications socket
+ * @param[in] mctp_eid - MCTP EID of remote host firmware
+ * @param[in] repo - pointer to BMC's primary PDR repo
+ * @param[in] instanceIdDb - pointer to an InstanceIdDb object
+ * @param[in] event - sd_event handler
+ * @param[in] invoker - invoker handler
+ * @param[in] hostPDRHandler - hostPDRHandler handler
+ * @param[in] platformHandler - platformHandler handler
+ * @param[in] fruHandler - fruHandler handler
+ * @param[in] baseHandler - baseHandler handler
+ * @param[in] biosHandler - biosHandler handler
+ * @param[in] reqHandler - reqHandler handler
+ */
+ explicit OemAMPERE(
+ const pldm::utils::DBusHandler* /* dBusIntf */, int /* mctp_fd */,
+ pldm_pdr* /* repo */, pldm::InstanceIdDb& instanceIdDb,
+ sdeventplus::Event& event, responder::Invoker& /* invoker */,
+ HostPDRHandler* /* hostPDRHandler */,
+ responder::platform::Handler* platformHandler,
+ responder::fru::Handler* /* fruHandler */,
+ responder::base::Handler* /* baseHandler */,
+ responder::bios::Handler* /* biosHandler */,
+ platform_mc::Manager* /* platformManager */,
+ pldm::requester::Handler<pldm::requester::Request>* reqHandler) :
+ instanceIdDb(instanceIdDb), event(event),
+ platformHandler(platformHandler), reqHandler(reqHandler)
+ {
+ oemEventManager = std::make_shared<oem_ampere::OemEventManager>(
+ this->event, this->reqHandler, this->instanceIdDb);
+ createOemEventHandler(oemEventManager);
+ }
+
+ private:
+ /** @brief Method for creating OemEventManager
+ *
+ * This method also assigns the OemEventManager to the below
+ * different handlers.
+ */
+ void createOemEventHandler(
+ std::shared_ptr<oem_ampere::OemEventManager> oemEventManager)
+ {
+ platformHandler->registerEventHandlers(
+ PLDM_SENSOR_EVENT,
+ {[&oemEventManager](const pldm_msg* request, size_t payloadLength,
+ uint8_t formatVersion, uint8_t tid,
+ size_t eventDataOffset) {
+ return oemEventManager->handleSensorEvent(
+ request, payloadLength, formatVersion, tid,
+ eventDataOffset);
+ }});
+ }
+
+ private:
+ /** @brief reference to an Instance ID database object, used to obtain PLDM
+ * instance IDs
+ */
+ pldm::InstanceIdDb& instanceIdDb;
+
+ /** @brief reference of main event loop of pldmd, primarily used to schedule
+ * work
+ */
+ sdeventplus::Event& event;
+
+ /** @brief Platform handler*/
+ responder::platform::Handler* platformHandler = nullptr;
+
+ /** @brief pointer to the requester class*/
+ requester::Handler<requester::Request>* reqHandler = nullptr;
+
+ std::shared_ptr<oem_ampere::OemEventManager> oemEventManager{};
+};
+
+} // namespace oem_ampere
+} // namespace pldm
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index e9ff90e..2352b60 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -64,6 +64,10 @@
#include "oem_ibm.hpp"
#endif
+#ifdef OEM_AMPERE
+#include "oem/ampere/oem_ampere.hpp"
+#endif
+
constexpr const char* PLDMService = "xyz.openbmc_project.PLDM";
using namespace pldm;
@@ -309,6 +313,14 @@
auto baseHandler = std::make_unique<base::Handler>(event);
+#ifdef OEM_AMPERE
+ pldm::oem_ampere::OemAMPERE oemAMPERE(
+ &dbusHandler, pldmTransport.getEventSource(), pdrRepo.get(),
+ instanceIdDb, event, invoker, hostPDRHandler.get(),
+ platformHandler.get(), fruHandler.get(), baseHandler.get(),
+ biosHandler.get(), platformManager.get(), &reqHandler);
+#endif
+
#ifdef OEM_IBM
pldm::oem_ibm::OemIBM oemIBM(
&dbusHandler, pldmTransport.getEventSource(), hostEID, pdrRepo.get(),