/* * SPDX-FileCopyrightText: Copyright OpenBMC Authors * SPDX-License-Identifier: Apache-2.0 */ #include "NvidiaPcieInterface.hpp" #include "Utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using std::string; using namespace std::literals; NvidiaPcieInterface::NvidiaPcieInterface( std::shared_ptr& conn, mctp::MctpRequester& mctpRequester, const std::string& name, const std::string& path, uint8_t eid, sdbusplus::asio::object_server& objectServer) : eid(eid), path(path), conn(conn), mctpRequester(mctpRequester) { const std::string dbusPath = pcieDevicePathPrefix + escapeName(name); pcieDeviceInterface = objectServer.add_interface( dbusPath, "xyz.openbmc_project.Inventory.Item.PCIeDevice"); switchInterface = objectServer.add_interface( dbusPath, "xyz.openbmc_project.Inventory.Item.PCIeSwitch"); pcieDeviceInterface->register_property( "GenerationInUse", std::string( "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")); pcieDeviceInterface->register_property("LanesInUse", std::numeric_limits::max()); pcieDeviceInterface->register_property( "GenerationSupported", std::string( "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")); pcieDeviceInterface->register_property("MaxLanes", static_cast(0)); if (!pcieDeviceInterface->initialize()) { lg2::error("Error initializing PCIe Device Interface for EID={EID}", "EID", eid); } if (!switchInterface->initialize()) { lg2::error("Error initializing Switch Interface for EID={EID}", "EID", eid); } } string NvidiaPcieInterface::mapPcieGeneration(uint32_t value) { switch (value) { case 1: return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1"; case 2: return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2"; case 3: return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3"; case 4: return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4"; case 5: return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5"; case 6: return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen6"; default: return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown"; } } size_t NvidiaPcieInterface::decodeLinkWidth(uint32_t value) { return (value > 0) ? pow(2, value - 1) : 0; } void NvidiaPcieInterface::processResponse(const std::error_code& ec, std::span response) { if (ec) { lg2::error( "Error updating PCIe Interface: 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; auto rc = gpu::decodeQueryScalarGroupTelemetryV2Response( response, cc, reasonCode, numTelemetryValue, telemetryValues); if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS) { lg2::error("Error updating PCIe Interface: decode failed, " "rc={RC}, cc={CC}, reasonCode={RESC}, EID={EID}", "RC", rc, "CC", static_cast(cc), "RESC", reasonCode, "EID", eid); return; } if (!telemetryValues.empty()) { pcieDeviceInterface->set_property( "GenerationInUse", mapPcieGeneration(telemetryValues[0])); } if (telemetryValues.size() > 1) { pcieDeviceInterface->set_property( "LanesInUse", decodeLinkWidth(static_cast(telemetryValues[1]))); } if (telemetryValues.size() > 3) { pcieDeviceInterface->set_property( "GenerationSupported", mapPcieGeneration(telemetryValues[3])); } if (telemetryValues.size() > 4) { pcieDeviceInterface->set_property( "MaxLanes", decodeLinkWidth(static_cast(telemetryValues[4]))); } } void NvidiaPcieInterface::update() { auto rc = gpu::encodeQueryScalarGroupTelemetryV2Request(0, {}, 0, 0, 1, request); if (rc != 0) { lg2::error("Error updating PCIe Interface: failed, rc={RC}, EID={EID}", "RC", rc, "EID", eid); return; } mctpRequester.sendRecvMsg( eid, request, [weak{weak_from_this()}](const std::error_code& ec, std::span buffer) { std::shared_ptr self = weak.lock(); if (!self) { lg2::error( "Invalid reference to NvidiaPcieInterface for EID {EID}", "EID", self->eid); return; } self->processResponse(ec, buffer); }); }