blob: fa65ef0ded9e4821dc0b9b6aa329780f733ab15c [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright OpenBMC Authors
* SPDX-License-Identifier: Apache-2.0
*/
#include "NvidiaGpuEccMode.hpp"
#include <MctpRequester.hpp>
#include <NvidiaGpuLongRunningCommand.hpp>
#include <NvidiaGpuMctpVdm.hpp>
#include <NvidiaLongRunningHandler.hpp>
#include <NvidiaUtils.hpp>
#include <OcpMctpVdm.hpp>
#include <SerialQueue.hpp>
#include <Utils.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/message/native_types.hpp>
#include <cstdint>
#include <functional>
#include <memory>
#include <span>
#include <string>
#include <utility>
#include <vector>
NvidiaGpuEccMode::NvidiaGpuEccMode(
mctp::MctpRequester& mctpRequester,
sdbusplus::asio::object_server& objectServer, const std::string& deviceName,
uint8_t eid, std::shared_ptr<SerialQueue> longRunningQueue,
std::shared_ptr<NvidiaLongRunningResponseHandler>
longRunningResponseHandler) :
mctpRequester(mctpRequester), eid(eid),
longRunningQueue(std::move(longRunningQueue)),
longRunningResponseHandler(std::move(longRunningResponseHandler)),
objectServer(objectServer)
{
const sdbusplus::object_path controlPath =
sdbusplus::object_path("/xyz/openbmc_project/control/processor") /
deviceName;
eccModeInterface = objectServer.add_interface(
controlPath, "xyz.openbmc_project.Control.Processor.EccMode");
eccModeInterface->register_property(
"Active", false, sdbusplus::asio::PropertyPermission::readOnly);
eccModeInterface->register_property(
"Enabled", false, sdbusplus::asio::PropertyPermission::readOnly);
if (!eccModeInterface->initialize())
{
lg2::error(
"Error initializing ECC mode interface for {NAME}, eid={EID}",
"NAME", deviceName, "EID", eid);
}
const sdbusplus::object_path inventoryPath = inventoryPrefix / deviceName;
std::vector<Association> associations;
associations.emplace_back("controlling", "controlled_by", inventoryPath);
eccModeAssociationInterface =
objectServer.add_interface(controlPath, association::interface);
eccModeAssociationInterface->register_property("Associations",
associations);
if (!eccModeAssociationInterface->initialize())
{
lg2::error(
"Error initializing ECC mode association interface for {NAME}, eid={EID}",
"NAME", deviceName, "EID", eid);
}
getCmd = std::make_shared<NvidiaGpuLongRunningCommand>(
eid, this->mctpRequester, this->longRunningQueue,
this->longRunningResponseHandler,
NvidiaGpuLongRunningCommand::Config{
.metricName = "GPU ECC Mode",
.messageType = gpu::MessageType::PLATFORM_ENVIRONMENTAL,
.commandId = gpu::PlatformEnvironmentalCommands::GET_ECC_MODE,
.requestSize = gpu::getEccModeRequestSize,
.encodeRequest =
std::bind_front(&gpu::encodeGetEccModeRequest, uint8_t{0}),
.onImmediateSuccess =
std::bind_front(&NvidiaGpuEccMode::onGetImmediateSuccess, this),
.onLongRunningPayload = std::bind_front(
&NvidiaGpuEccMode::onGetLongRunningPayload, this),
});
}
NvidiaGpuEccMode::~NvidiaGpuEccMode()
{
objectServer.remove_interface(eccModeInterface);
objectServer.remove_interface(eccModeAssociationInterface);
}
void NvidiaGpuEccMode::update()
{
getCmd->update();
}
void NvidiaGpuEccMode::onGetImmediateSuccess(
std::span<const uint8_t> fullBuffer)
{
ocp::accelerator_management::CompletionCode cc{};
uint16_t reasonCode = 0;
bool active = false;
bool enabled = false;
const int rc = gpu::decodeGetEccModeResponse(fullBuffer, cc, reasonCode,
active, enabled);
if (rc != 0)
{
lg2::error("Error updating GPU ECC Mode: decode failed, "
"rc={RC}, cc={CC}, reasonCode={RESC}, EID={EID}",
"RC", rc, "CC", static_cast<uint8_t>(cc), "RESC", reasonCode,
"EID", eid);
return;
}
applyEccModeToDbus(active, enabled);
}
void NvidiaGpuEccMode::onGetLongRunningPayload(std::span<const uint8_t> payload)
{
bool active = false;
bool enabled = false;
const int rc = gpu::decodeGetEccModeResponse(payload, active, enabled);
if (rc != 0)
{
lg2::error("Error updating GPU ECC Mode: "
"failed to decode long running response, rc={RC}, EID={EID}",
"RC", rc, "EID", eid);
return;
}
applyEccModeToDbus(active, enabled);
}
void NvidiaGpuEccMode::applyEccModeToDbus(bool active, bool enabled)
{
eccModeInterface->set_property("Active", active);
eccModeInterface->set_property("Enabled", enabled);
}