platform-mc: Support pollForPlatFormEventMessage
Supports polling all events synchronously when the terminus sends
`pldmMessagePollEvent` with the event id. BMC will use the received
event id as input for `pollForPlatformEventMessage` command to retrieve
the event data.
Change-Id: If01f63f30d3f57f8423c863ec776e83dda8e3042
Signed-off-by: Dung Cao <dung@os.amperecomputing.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
diff --git a/platform-mc/event_manager.cpp b/platform-mc/event_manager.cpp
index 8212598..a784cdd 100644
--- a/platform-mc/event_manager.cpp
+++ b/platform-mc/event_manager.cpp
@@ -1,5 +1,6 @@
#include "event_manager.hpp"
+#include "libpldm/platform.h"
#include "libpldm/utils.h"
#include "terminus_manager.hpp"
@@ -72,6 +73,34 @@
return processCperEvent(tid, eventId, eventData, eventDataSize);
}
+ /* EventClass pldmMessagePollEvent `Table 11 - PLDM Event Types` DSP0248 */
+ if (eventClass == PLDM_MESSAGE_POLL_EVENT)
+ {
+ lg2::info("Received pldmMessagePollEvent for terminus {TID}", "TID",
+ tid);
+ pldm_message_poll_event poll_event{};
+ auto rc = decode_pldm_message_poll_event_data(eventData, eventDataSize,
+ &poll_event);
+ if (rc)
+ {
+ lg2::error(
+ "Failed to decode PldmMessagePollEvent event, error {RC} ",
+ "RC", rc);
+ return rc;
+ }
+
+ auto it = termini.find(tid);
+ if (it != termini.end())
+ {
+ auto& terminus = it->second; // Reference for clarity
+ terminus->pollEvent = true;
+ terminus->pollEventId = poll_event.event_id;
+ terminus->pollDataTransferHandle = poll_event.data_transfer_handle;
+ }
+
+ return PLDM_SUCCESS;
+ }
+
lg2::info("Unsupported class type {CLASSTYPE}", "CLASSTYPE", eventClass);
return PLDM_ERROR;
@@ -456,5 +485,208 @@
return PLDM_SUCCESS;
}
+int EventManager::getNextPartParameters(
+ uint16_t eventId, std::vector<uint8_t> eventMessage, uint8_t transferFlag,
+ uint32_t eventDataIntegrityChecksum, uint32_t nextDataTransferHandle,
+ uint8_t* transferOperationFlag, uint32_t* dataTransferHandle,
+ uint32_t* eventIdToAcknowledge)
+{
+ if (transferFlag != PLDM_PLATFORM_TRANSFER_START_AND_END &&
+ transferFlag != PLDM_PLATFORM_TRANSFER_END)
+ {
+ *transferOperationFlag = PLDM_GET_NEXTPART;
+ *dataTransferHandle = nextDataTransferHandle;
+ *eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_FRAGMENT;
+ return PLDM_SUCCESS;
+ }
+
+ if (transferFlag == PLDM_PLATFORM_TRANSFER_END)
+ {
+ if (eventDataIntegrityChecksum !=
+ crc32(eventMessage.data(), eventMessage.size()))
+ {
+ lg2::error("pollForPlatformEventMessage invalid checksum.");
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ }
+
+ /* End of one event. Set request transfer flag to ACK */
+ *transferOperationFlag = PLDM_ACKNOWLEDGEMENT_ONLY;
+ *dataTransferHandle = 0;
+ *eventIdToAcknowledge = eventId;
+
+ return PLDM_SUCCESS;
+}
+
+exec::task<int> EventManager::pollForPlatformEventTask(
+ pldm_tid_t tid, uint32_t pollDataTransferHandle)
+{
+ uint8_t rc = 0;
+ // Set once, doesn't need resetting
+ uint8_t transferOperationFlag = PLDM_GET_FIRSTPART;
+ uint32_t dataTransferHandle = pollDataTransferHandle;
+ uint32_t eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_NULL;
+ uint8_t formatVersion = 0x1; // Constant, no need to reset
+ uint16_t eventId = PLDM_PLATFORM_EVENT_ID_ACK;
+ uint16_t polledEventId = PLDM_PLATFORM_EVENT_ID_NONE;
+ pldm_tid_t polledEventTid = 0;
+ uint8_t polledEventClass = 0;
+
+ std::vector<uint8_t> eventMessage{};
+
+ // Reset and mark terminus as available
+ updateAvailableState(tid, true);
+
+ while (eventId != PLDM_PLATFORM_EVENT_ID_NONE)
+ {
+ uint8_t completionCode = 0;
+ pldm_tid_t eventTid = PLDM_PLATFORM_EVENT_ID_NONE;
+ eventId = PLDM_PLATFORM_EVENT_ID_NONE;
+ uint32_t nextDataTransferHandle = 0;
+ uint8_t transferFlag = 0;
+ uint8_t eventClass = 0;
+ uint32_t eventDataSize = 0;
+ uint8_t* eventData = nullptr;
+ uint32_t eventDataIntegrityChecksum = 0;
+
+ /* Stop event polling */
+ if (!getAvailableState(tid))
+ {
+ lg2::info(
+ "Terminus ID {TID} is not available for PLDM request from {NOW}.",
+ "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
+ co_await stdexec::just_stopped();
+ }
+
+ rc = co_await pollForPlatformEventMessage(
+ tid, formatVersion, transferOperationFlag, dataTransferHandle,
+ eventIdToAcknowledge, completionCode, eventTid, eventId,
+ nextDataTransferHandle, transferFlag, eventClass, eventDataSize,
+ eventData, eventDataIntegrityChecksum);
+ if (rc || completionCode != PLDM_SUCCESS)
+ {
+ lg2::error(
+ "Failed to pollForPlatformEventMessage for terminus {TID}, event {EVENTID}, error {RC}, complete code {CC}",
+ "TID", tid, "EVENTID", eventId, "RC", rc, "CC", completionCode);
+ co_return rc;
+ }
+
+ if (eventDataSize > 0)
+ {
+ eventMessage.insert(eventMessage.end(), eventData,
+ eventData + eventDataSize);
+ }
+
+ if (transferOperationFlag == PLDM_ACKNOWLEDGEMENT_ONLY)
+ {
+ /* Handle the polled event after finish ACK it */
+ if (eventHandlers.contains(polledEventClass))
+ {
+ eventHandlers.at(
+ polledEventClass)(polledEventTid, polledEventId,
+ eventMessage.data(), eventMessage.size());
+ }
+ eventMessage.clear();
+
+ if (eventId == PLDM_PLATFORM_EVENT_ID_ACK)
+ {
+ transferOperationFlag = PLDM_GET_FIRSTPART;
+ dataTransferHandle = 0;
+ eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_NULL;
+ }
+ }
+ else
+ {
+ auto ret = getNextPartParameters(
+ eventId, eventMessage, transferFlag, eventDataIntegrityChecksum,
+ nextDataTransferHandle, &transferOperationFlag,
+ &dataTransferHandle, &eventIdToAcknowledge);
+ if (ret)
+ {
+ lg2::error(
+ "Failed to process data of pollForPlatformEventMessage for terminus {TID}, event {EVENTID} return {RET}",
+ "TID", tid, "EVENTID", eventId, "RET", ret);
+ co_return PLDM_ERROR_INVALID_DATA;
+ }
+
+ /* Store the polled event INFO to handle after ACK */
+ if ((transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END) ||
+ (transferFlag == PLDM_PLATFORM_TRANSFER_END))
+ {
+ polledEventTid = eventTid;
+ polledEventId = eventId;
+ polledEventClass = eventClass;
+ }
+ }
+ }
+
+ co_return PLDM_SUCCESS;
+}
+
+exec::task<int> EventManager::pollForPlatformEventMessage(
+ pldm_tid_t tid, uint8_t formatVersion, uint8_t transferOperationFlag,
+ uint32_t dataTransferHandle, uint16_t eventIdToAcknowledge,
+ uint8_t& completionCode, uint8_t& eventTid, uint16_t& eventId,
+ uint32_t& nextDataTransferHandle, uint8_t& transferFlag,
+ uint8_t& eventClass, uint32_t& eventDataSize, uint8_t*& eventData,
+ uint32_t& eventDataIntegrityChecksum)
+{
+ Request request(
+ sizeof(pldm_msg_hdr) + PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
+ auto requestMsg = new (request.data()) pldm_msg;
+ auto rc = encode_poll_for_platform_event_message_req(
+ 0, formatVersion, transferOperationFlag, dataTransferHandle,
+ eventIdToAcknowledge, requestMsg, request.size());
+ if (rc)
+ {
+ lg2::error(
+ "Failed to encode request PollForPlatformEventMessage for terminus ID {TID}, error {RC} ",
+ "TID", tid, "RC", rc);
+ co_return rc;
+ }
+
+ /* Stop event polling */
+ if (!getAvailableState(tid))
+ {
+ lg2::info(
+ "Terminus ID {TID} is not available for PLDM request from {NOW}.",
+ "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
+ co_await stdexec::just_stopped();
+ }
+
+ const pldm_msg* responseMsg = nullptr;
+ size_t responseLen = 0;
+ rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
+ &responseLen);
+ if (rc)
+ {
+ lg2::error(
+ "Failed to send PollForPlatformEventMessage message for terminus {TID}, error {RC}",
+ "TID", tid, "RC", rc);
+ co_return rc;
+ }
+
+ rc = decode_poll_for_platform_event_message_resp(
+ responseMsg, responseLen, &completionCode, &eventTid, &eventId,
+ &nextDataTransferHandle, &transferFlag, &eventClass, &eventDataSize,
+ (void**)&eventData, &eventDataIntegrityChecksum);
+ if (rc)
+ {
+ lg2::error(
+ "Failed to decode response PollForPlatformEventMessage for terminus ID {TID}, error {RC} ",
+ "TID", tid, "RC", rc);
+ co_return rc;
+ }
+ if (completionCode != PLDM_SUCCESS)
+ {
+ lg2::error(
+ "Error : PollForPlatformEventMessage for terminus ID {TID}, complete code {CC}.",
+ "TID", tid, "CC", completionCode);
+ co_return rc;
+ }
+
+ co_return completionCode;
+}
+
} // namespace platform_mc
} // namespace pldm