blob: 5e58cd5dd99bbdf77a96b58ef270c8043bfc0e08 [file] [edit]
#include "NvidiaGpuMctpVdm.hpp"
#include <MctpRequester.hpp>
#include <NvidiaEventReporting.hpp>
#include <OcpMctpVdm.hpp>
#include <boost/container_hash/hash.hpp>
#include <phosphor-logging/lg2.hpp>
#include <array>
#include <cstdint>
#include <initializer_list>
#include <span>
#include <system_error>
#include <unordered_map>
std::unordered_map<NvidiaEventHandler::EventKey, EventHandler,
boost::hash<NvidiaEventHandler::EventKey>>
NvidiaEventHandler::eventHandlers;
static std::array<uint64_t, messageTypeCount> buildEventSourceMasks(
std::initializer_list<EventDescriptor> events)
{
std::array<uint64_t, messageTypeCount> masks{};
for (const auto& event : events)
{
const uint8_t idx = static_cast<uint8_t>(event.messageType);
if (idx >= messageTypeCount)
{
lg2::error(
"Invalid message type {MSG} for event code {CODE}, skipping",
"MSG", idx, "CODE", event.eventCode);
continue;
}
if (event.eventCode >= 64)
{
lg2::error(
"Event code {CODE} exceeds 64-bit mask capacity, skipping",
"CODE", event.eventCode);
continue;
}
masks[idx] |= (1ULL << event.eventCode);
}
return masks;
}
NvidiaEventReportingConfig::NvidiaEventReportingConfig(
uint8_t eid, mctp::MctpRequester& req,
std::initializer_list<EventDescriptor> events) :
eid{eid}, requester{req}, eventMasks{buildEventSourceMasks(events)}
{
for (const auto& event : events)
{
NvidiaEventHandler::registerEventHandler(
eid, event.messageType, event.eventCode, event.eventHandler);
}
}
void NvidiaEventReportingConfig::init()
{
int rc = gpu::encodeSetEventSubscriptionRequest(generationSettingEnablePush,
bmc_eid, subscriptionReq);
if (rc != 0)
{
lg2::error("Failed to setup device subscription for eid {EID}", "EID",
eid);
return;
}
requester.sendRecvMsg(
eid, subscriptionReq,
[weak{weak_from_this()}](const std::error_code& ec,
std::span<const uint8_t> buffer) {
auto self = weak.lock();
if (!self)
{
lg2::error("Invalid reference to NvidiaEventReportingConfig");
return;
}
self->handleSetupSubscription(ec, buffer);
});
}
void NvidiaEventReportingConfig::handleSetupSubscription(
const std::error_code& ec, std::span<const uint8_t> buffer)
{
if (ec)
{
lg2::error("failed to setup event subscription on eid {EID}: {EC}",
"EID", eid, "EC", ec.message());
return;
}
ocp::accelerator_management::CompletionCode cc{};
uint16_t reasonCode = 0;
int rc = gpu::decodeSetEventSubscriptionResponse(buffer, cc, reasonCode);
if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
{
lg2::error("failed to setup event subscription on eid {EID}: "
"rc={RC}, cc={CC}, reasonCode={RESC}",
"EID", eid, "RC", rc, "CC", cc, "RESC", reasonCode);
return;
}
// Device is set up for push notifications, now configure event sources
currentMessageTypeIdx = 0;
sendNextEventSource();
}
void NvidiaEventReportingConfig::sendNextEventSource()
{
// Find next message type with events that can be encoded
while (currentMessageTypeIdx < messageTypeCount)
{
// Skip message types with no events
if (eventMasks[currentMessageTypeIdx] == 0)
{
currentMessageTypeIdx++;
continue;
}
uint64_t events = eventMasks[currentMessageTypeIdx];
auto messageType = static_cast<uint8_t>(currentMessageTypeIdx);
const int rc =
gpu::encodeSetEventSourcesRequest(events, messageType, sourcesReq);
if (rc != 0)
{
lg2::error(
"Failed to encode event sources request for EID {EID} messageType {MSG}",
"EID", eid, "MSG", messageType);
currentMessageTypeIdx++;
continue;
}
break;
}
if (currentMessageTypeIdx >= messageTypeCount)
{
lg2::info("Finished setting up event sources for eid {EID}", "EID",
eid);
// All event sources processed
return;
}
requester.sendRecvMsg(
eid, sourcesReq,
[weak{weak_from_this()}](const std::error_code& ec,
std::span<const uint8_t> buffer) {
auto self = weak.lock();
if (!self)
{
lg2::error("Invalid reference to NvidiaEventReportingConfig");
return;
}
self->handleSetupEvents(ec, buffer);
});
}
void NvidiaEventReportingConfig::handleSetupEvents(
const std::error_code& ec, std::span<const uint8_t> buffer)
{
if (ec)
{
lg2::error("failed to set up events for eid {EID}: {MSG}", "EID", eid,
"MSG", ec.message());
currentMessageTypeIdx++;
sendNextEventSource();
return;
}
ocp::accelerator_management::CompletionCode cc{};
uint16_t reasonCode = 0;
const int rc = gpu::decodeSetEventSourcesResponse(buffer, cc, reasonCode);
if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
{
lg2::error("failed to set event sources on eid {EID}: "
"rc={RC}, cc={CC}, reasonCode={RESC}",
"EID", eid, "RC", rc, "CC", cc, "RESC", reasonCode);
currentMessageTypeIdx++;
sendNextEventSource();
return;
}
// Move to next message type and continue
currentMessageTypeIdx++;
sendNextEventSource();
}
void NvidiaEventHandler::handleEvent(uint8_t eid,
std::span<const uint8_t> buffer)
{
EventInfo eventInfo{};
uint8_t messageType = 0;
uint8_t eventId = 0;
uint8_t eventSize = 0;
std::span<const uint8_t> eventData;
const int rc = ocp::accelerator_management::decodeEvent(
buffer, gpu::nvidiaPciVendorId, messageType, eventInfo.ackRequired,
eventInfo.version, eventId, eventInfo.eventClass, eventInfo.eventState,
eventSize, eventData);
if (rc != 0)
{
lg2::error("Failed to decode event log");
return;
}
EventKey key{eid, static_cast<gpu::MessageType>(messageType), eventId};
const auto itr = eventHandlers.find(key);
if (itr == eventHandlers.end())
{
lg2::error(
"No handler registered for event code {CODE} message type {MSG} from eid {EID}",
"CODE", eventId, "MSG", messageType, "EID", eid);
return;
}
itr->second(eventInfo, eventData);
}