blob: 0d9942b1e89877817c6b38e66b3662d0bb327dbc [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright OpenBMC Authors
* SPDX-License-Identifier: Apache-2.0
*/
#include "NvidiaGpuClockFrequencyMetric.hpp"
#include "NvidiaUtils.hpp"
#include "Utils.hpp"
#include <bits/basic_string.h>
#include <MctpRequester.hpp>
#include <NvidiaGpuMctpVdm.hpp>
#include <OcpMctpVdm.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/message/native_types.hpp>
#include <cstdint>
#include <memory>
#include <span>
#include <string>
#include <system_error>
#include <vector>
using namespace std::literals;
static constexpr uint32_t mhzToHzFactor = 1'000'000;
NvidiaGpuClockFrequencyMetric::NvidiaGpuClockFrequencyMetric(
mctp::MctpRequester& mctpRequester, const std::string& name, uint8_t eid,
sdbusplus::asio::object_server& objectServer) :
mctpRequester(mctpRequester), name(name), eid(eid),
objectServer(objectServer)
{
const int rc = gpu::encodeGetCurrentClockFrequencyRequest(
0, gpu::ClockType::GRAPHICS_CLOCK, requestBuffer);
if (rc == 0)
{
requestEncoded = true;
}
else
{
lg2::error(
"Failed to encode clock frequency request for {NAME}: rc={RC}",
"NAME", name, "RC", rc);
}
const sdbusplus::object_path inventoryPath = inventoryPrefix / this->name;
const std::string metricDbusPath =
metricPath + this->name + "/OperatingFrequency";
metricInterface = objectServer.add_interface(
metricDbusPath, "xyz.openbmc_project.Metric.Value");
metricInterface->register_property(
"Unit", "xyz.openbmc_project.Metric.Value.Unit.Frequency"s);
metricInterface->register_property("Value", 0.0);
if (!metricInterface->initialize())
{
lg2::error(
"Error initializing Clock Frequency Metric interface for {NAME}, eid={EID}",
"NAME", name, "EID", eid);
}
associationInterface =
objectServer.add_interface(metricDbusPath, association::interface);
std::vector<Association> associations;
associations.emplace_back("measuring", "measured_by", inventoryPath);
associationInterface->register_property("Associations", associations);
if (!associationInterface->initialize())
{
lg2::error(
"Error initializing Association interface for Clock Frequency Metric for {NAME}, eid={EID}",
"NAME", name, "EID", eid);
}
}
NvidiaGpuClockFrequencyMetric::~NvidiaGpuClockFrequencyMetric()
{
objectServer.remove_interface(metricInterface);
objectServer.remove_interface(associationInterface);
}
void NvidiaGpuClockFrequencyMetric::update()
{
if (!requestEncoded)
{
return;
}
mctpRequester.sendRecvMsg(
eid, requestBuffer,
[weak{weak_from_this()}](const std::error_code& ec,
std::span<const uint8_t> buffer) {
auto self = weak.lock();
if (!self)
{
lg2::error("Invalid NvidiaGpuClockFrequencyMetric reference");
return;
}
self->handleResponse(ec, buffer);
});
}
void NvidiaGpuClockFrequencyMetric::handleResponse(
const std::error_code& ec, std::span<const uint8_t> buffer)
{
if (ec)
{
lg2::error(
"Error reading clock frequency for {NAME}: MCTP failed, rc={RC}",
"NAME", name, "RC", ec.message());
return;
}
ocp::accelerator_management::CompletionCode cc{};
uint16_t reasonCode = 0;
uint32_t clockFrequencyMhz = 0;
int rc = gpu::decodeGetCurrentClockFrequencyResponse(buffer, cc, reasonCode,
clockFrequencyMhz);
if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
{
lg2::error(
"Error decoding clock frequency for {NAME}: rc={RC}, cc={CC}, reasonCode={REASON}",
"NAME", name, "RC", rc, "CC", static_cast<uint8_t>(cc), "REASON",
reasonCode);
return;
}
double freqHz = static_cast<double>(clockFrequencyMhz) * mhzToHzFactor;
metricInterface->set_property("Value", freqHz);
}