blob: dbe19fb360d0e4ffdac8ac8b7d0cdf47c9a963b7 [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright OpenBMC Authors
* SPDX-License-Identifier: Apache-2.0
*/
#include "NvidiaPcieFunction.hpp"
#include "Utils.hpp"
#include <MctpRequester.hpp>
#include <NvidiaGpuMctpVdm.hpp>
#include <NvidiaUtils.hpp>
#include <OcpMctpVdm.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/message/native_types.hpp>
#include <cstddef>
#include <cstdint>
#include <format>
#include <memory>
#include <span>
#include <string>
#include <system_error>
#include <tuple>
#include <vector>
using Association = std::tuple<std::string, std::string, std::string>;
NvidiaPcieFunction::NvidiaPcieFunction(
std::shared_ptr<sdbusplus::asio::connection>& conn,
mctp::MctpRequester& mctpRequester, const std::string& pcieDeviceName,
const std::string& path, uint8_t eid, uint8_t functionNumber,
sdbusplus::asio::object_server& objectServer,
gpu::DeviceIdentification deviceType) :
eid(eid), path(path), conn(conn), mctpRequester(mctpRequester),
objectServer(objectServer), deviceType(deviceType)
{
int rc = 0;
switch (deviceType)
{
case gpu::DeviceIdentification::DEVICE_GPU:
request.resize(gpu::queryScalarGroupTelemetryV1RequestSize);
rc = gpu::encodeQueryScalarGroupTelemetryV1Request(
0, 0, gpu::PcieScalarGroupId::PciIdentity, request);
break;
case gpu::DeviceIdentification::DEVICE_PCIE:
request.resize(gpu::queryScalarGroupTelemetryV2RequestSize);
rc = gpu::encodeQueryScalarGroupTelemetryV2Request(
0, {}, 0, 0, gpu::PcieScalarGroupId::PciIdentity, request);
break;
default:
break;
}
if (rc != 0)
{
request.clear();
lg2::error("Failed to encode PCIe Function request: rc={RC}, EID={EID}",
"RC", rc, "EID", eid);
}
const sdbusplus::object_path dbusPath =
inventoryPrefix / pcieDeviceName /
std::format("Function{}", functionNumber);
pcieFunctionInterface = objectServer.add_interface(
dbusPath, "xyz.openbmc_project.Inventory.Item.PCIeFunction");
pcieFunctionInterface->register_property("FunctionNumber", functionNumber);
pcieFunctionInterface->register_property("VendorId",
static_cast<uint16_t>(0));
pcieFunctionInterface->register_property("DeviceId",
static_cast<uint16_t>(0));
pcieFunctionInterface->register_property("SubsystemVendorId",
static_cast<uint16_t>(0));
pcieFunctionInterface->register_property("SubsystemId",
static_cast<uint16_t>(0));
if (deviceType == gpu::DeviceIdentification::DEVICE_GPU)
{
pcieFunctionInterface->register_property(
"DeviceClass",
std::string("xyz.openbmc_project.Inventory.Item.PCIeFunction"
".DeviceClasses.ProcessingAccelerators"));
pcieFunctionInterface->register_property(
"FunctionType",
std::string("xyz.openbmc_project.Inventory.Item.PCIeFunction"
".FunctionTypes.Physical"));
}
if (!pcieFunctionInterface->initialize())
{
lg2::error("Error initializing PCIe Function interface, eid={EID}",
"EID", eid);
}
const sdbusplus::object_path pcieDevicePath =
inventoryPrefix / pcieDeviceName;
std::vector<Association> associations;
associations.emplace_back("exposed_by", "exposing", pcieDevicePath);
associationInterface =
objectServer.add_interface(dbusPath, association::interface);
associationInterface->register_property("Associations", associations);
if (!associationInterface->initialize())
{
lg2::error(
"Error initializing Association interface for PCIe Function, eid={EID}",
"EID", eid);
}
}
NvidiaPcieFunction::~NvidiaPcieFunction()
{
objectServer.remove_interface(pcieFunctionInterface);
objectServer.remove_interface(associationInterface);
}
void NvidiaPcieFunction::processResponse(const std::error_code& ec,
std::span<const uint8_t> response)
{
if (ec)
{
lg2::error(
"Error updating PCIe Function: sending message over MCTP failed, "
"rc={RC}, EID={EID}",
"RC", ec.value(), "EID", eid);
return;
}
ocp::accelerator_management::CompletionCode cc{};
uint16_t reasonCode = 0;
size_t numTelemetryValue = 0;
int rc = 0;
switch (deviceType)
{
case gpu::DeviceIdentification::DEVICE_GPU:
rc = gpu::decodeQueryScalarGroupTelemetryV1Response(
response, cc, reasonCode, numTelemetryValue, telemetryValues);
break;
case gpu::DeviceIdentification::DEVICE_PCIE:
rc = gpu::decodeQueryScalarGroupTelemetryV2Response(
response, cc, reasonCode, numTelemetryValue, telemetryValues);
break;
default:
return;
}
if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
{
lg2::error("Error updating PCIe Function: decode failed, "
"rc={RC}, cc={CC}, reasonCode={RESC}, EID={EID}",
"RC", rc, "CC", static_cast<uint8_t>(cc), "RESC", reasonCode,
"EID", eid);
return;
}
if (numTelemetryValue < 4)
{
lg2::error(
"Error updating PCIe Function: insufficient telemetry values, "
"NumValues={NUM}, EID={EID}",
"NUM", numTelemetryValue, "EID", eid);
return;
}
pcieFunctionInterface->set_property(
"VendorId", static_cast<uint16_t>(telemetryValues[0]));
pcieFunctionInterface->set_property(
"DeviceId", static_cast<uint16_t>(telemetryValues[1]));
pcieFunctionInterface->set_property(
"SubsystemVendorId", static_cast<uint16_t>(telemetryValues[2]));
pcieFunctionInterface->set_property(
"SubsystemId", static_cast<uint16_t>(telemetryValues[3]));
}
void NvidiaPcieFunction::update()
{
if (request.empty())
{
return;
}
mctpRequester.sendRecvMsg(
eid, request,
[weak{weak_from_this()}](const std::error_code& ec,
std::span<const uint8_t> buffer) {
std::shared_ptr<NvidiaPcieFunction> self = weak.lock();
if (!self)
{
lg2::error("Invalid reference to NvidiaPcieFunction");
return;
}
self->processResponse(ec, buffer);
});
}