blob: 6920fb96a8d44c6daa319eb87b65c5367f504aec [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright OpenBMC Authors
* SPDX-License-Identifier: Apache-2.0
*/
#include "NvidiaLongRunningHandler.hpp"
#include <NvidiaEventReporting.hpp>
#include <NvidiaGpuMctpVdm.hpp>
#include <OcpMctpVdm.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/system/error_code.hpp>
#include <phosphor-logging/lg2.hpp>
#include <cerrno>
#include <cstdint>
#include <span>
#include <system_error>
#include <utility>
NvidiaLongRunningResponseHandler::NvidiaLongRunningResponseHandler(
boost::asio::io_context& io) : io(io)
{}
int NvidiaLongRunningResponseHandler::registerResponseHandler(
gpu::MessageType messageType, uint8_t commandCode, uint8_t instanceId,
ResponseHandler handler)
{
const ResponseKey key{messageType, commandCode, instanceId};
auto [it, inserted] = entries.try_emplace(key, std::move(handler), io);
if (!inserted)
{
return EEXIST;
}
it->second.timer.expires_after(longRunningResponseTimeout);
it->second.timer.async_wait(
[weak = weak_from_this(),
key](const boost::system::error_code& ec) mutable {
if (ec == boost::asio::error::operation_aborted)
{
return;
}
if (auto self = weak.lock())
{
self->onTimeout(key);
}
});
return 0;
}
void NvidiaLongRunningResponseHandler::onTimeout(ResponseKey key)
{
auto entryIt = entries.find(key);
if (entryIt == entries.end())
{
return;
}
ResponseHandler localHandler = std::move(entryIt->second.handler);
entries.erase(entryIt);
lg2::error(
"Long running response timed out: MessageType={MT}, CommandCode={CC}, InstanceId={IID}",
"MT", static_cast<uint8_t>(std::get<0>(key)), "CC", std::get<1>(key),
"IID", std::get<2>(key));
localHandler(make_error_code(std::errc::timed_out),
ocp::accelerator_management::CompletionCode::ERROR, 0,
std::span<const uint8_t>{});
}
void NvidiaLongRunningResponseHandler::handler(
const EventInfo& eventInfo, std::span<const uint8_t> eventData)
{
if (eventInfo.eventClass != longRunningResponseEventClass)
{
lg2::error(
"Received long running response event with unsupported event class: {EVENT_CLASS}",
"EVENT_CLASS", eventInfo.eventClass);
return;
}
const gpu::MessageType messageType =
static_cast<gpu::MessageType>(eventInfo.eventState & 0xFF);
const uint8_t commandCode =
static_cast<uint8_t>((eventInfo.eventState >> 8) & 0xFF);
ocp::accelerator_management::CompletionCode cc{};
uint16_t reasonCode = 0;
uint8_t instanceId = 0;
std::span<const uint8_t> responseData;
const int rc = gpu::decodeLongRunningResponseEvent(
eventData, cc, reasonCode, instanceId, responseData);
if (rc != 0)
{
lg2::error("Failed to decode long running response event, rc={RC}, "
"MessageType={MT}, CommandCode={CC}",
"RC", rc, "MT", static_cast<uint8_t>(messageType), "CC",
commandCode);
return;
}
const ResponseKey key{messageType, commandCode, instanceId};
auto entryIt = entries.find(key);
if (entryIt == entries.end())
{
lg2::error("No handler registered for long running response event with "
"MessageType={MT}, CommandCode={CC}, InstanceId={IID}",
"MT", static_cast<uint8_t>(messageType), "CC", commandCode,
"IID", instanceId);
return;
}
entryIt->second.timer.cancel();
ResponseHandler localHandler = std::move(entryIt->second.handler);
entries.erase(entryIt);
localHandler(boost::system::error_code{}, cc, reasonCode, responseData);
}