/* * SPDX-FileCopyrightText: Copyright OpenBMC Authors * SPDX-License-Identifier: Apache-2.0 */ #include "NvidiaPciePort.hpp" #include "Utils.hpp" #include #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; NvidiaPciePortInfo::NvidiaPciePortInfo( std::shared_ptr& conn, mctp::MctpRequester& mctpRequester, const std::string& name, const std::string& pcieDeviceName, const std::string& path, uint8_t eid, gpu::PciePortType portType, uint8_t upstreamPortNumber, uint8_t portNumber, sdbusplus::asio::object_server& objectServer) : eid(eid), portType(portType), upstreamPortNumber(upstreamPortNumber), portNumber(portNumber), path(path), conn(conn), mctpRequester(mctpRequester) { const sdbusplus::message::object_path dbusPath = sdbusplus::message::object_path(pcieDevicePathPrefix) / pcieDeviceName / name; pciePortInterface = objectServer.add_interface( dbusPath, "xyz.openbmc_project.Inventory.Connector.Port"); std::string portTypeStr; if (portType == gpu::PciePortType::UPSTREAM) { portTypeStr = "UpstreamPort"; } else { portTypeStr = "DownstreamPort"; } pciePortInterface->register_property( "PortType", "xyz.openbmc_project.Inventory.Connector.Port.PortType." + portTypeStr); pciePortInterface->register_property( "PortProtocol", std::string( "xyz.openbmc_project.Inventory.Connector.Port.PortProtocol.PCIe")); pciePortInterface->register_property("Speed", std::numeric_limits::max()); pciePortInterface->register_property("Width", std::numeric_limits::max()); if (!pciePortInterface->initialize()) { lg2::error( "Error initializing PCIe Device Interface for EID={EID}, PortType={PT}, PortNumber={PN}", "EID", eid, "PT", static_cast(portType), "PN", portNumber); } std::vector associations; associations.emplace_back("connected_to", "connecting", pcieDevicePathPrefix + pcieDeviceName); associationInterface = objectServer.add_interface(dbusPath, association::interface); associationInterface->register_property("Associations", associations); if (!associationInterface->initialize()) { lg2::error( "Error initializing Association Interface for PCIe Port Info for EID={EID}, PortType={PT}, PortNumber={PN}", "EID", eid, "PT", static_cast(portType), "PN", portNumber); } } uint64_t NvidiaPciePortInfo::mapPcieGenToLinkSpeedBitsPerSecond(uint32_t value) { static constexpr int gbpsToBps = 1 << 30; switch (value) { case 1: return 2.5 * gbpsToBps; case 2: return 5.0 * gbpsToBps; case 3: return 8.0 * gbpsToBps; case 4: return 16.0 * gbpsToBps; case 5: return 32.0 * gbpsToBps; case 6: return 64.0 * gbpsToBps; default: return 0; } } void NvidiaPciePortInfo::processResponse( const std::error_code& sendRecvMsgResult, std::span response) { if (sendRecvMsgResult) { lg2::error( "Error updating PCIe Port Info: sending message over MCTP failed, " "rc={RC}, EID={EID}, PortType={PT}, PortNumber={PN}", "RC", sendRecvMsgResult.message(), "EID", eid, "PT", static_cast(portType), "PN", portNumber); return; } ocp::accelerator_management::CompletionCode cc{}; uint16_t reasonCode = 0; size_t numTelemetryValue = 0; const int rc = gpu::decodeQueryScalarGroupTelemetryV2Response( response, cc, reasonCode, numTelemetryValue, telemetryValues); if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS) { lg2::error( "Error updating PCIe Port Info: decode failed, " "rc={RC}, cc={CC}, reasonCode={RESC}, EID={EID}, PortType={PT}, PortNumber={PN}", "RC", rc, "CC", static_cast(cc), "RESC", reasonCode, "EID", eid, "PT", static_cast(portType), "PN", portNumber); return; } if (telemetryValues.size() < 2) { lg2::error( "Error updating PCIe Port Info: insufficient telemetry values, " "NumValues={NUM}, EID={EID}, PortType={PT}, PortNumber={PN}", "NUM", telemetryValues.size(), "EID", eid, "PT", static_cast(portType), "PN", portNumber); return; } pciePortInterface->set_property( "Speed", mapPcieGenToLinkSpeedBitsPerSecond(telemetryValues[0])); pciePortInterface->set_property( "Width", NvidiaPcieInterface::decodeLinkWidth(telemetryValues[1])); } void NvidiaPciePortInfo::update() { auto rc = gpu::encodeQueryScalarGroupTelemetryV2Request( 0, portType, upstreamPortNumber, portNumber, 1, request); if (rc != 0) { lg2::error( "Error updating PCIe Port Info: encode failed, rc={RC}, EID={EID}, PortType={PT}, PortNumber={PN}", "RC", rc, "EID", eid, "PT", static_cast(portType), "PN", portNumber); 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 NvidiaPciePortInfo"); return; } self->processResponse(ec, buffer); }); }