| /* |
| * SPDX-FileCopyrightText: Copyright OpenBMC Authors |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "NvidiaPciePort.hpp" |
| |
| #include "Utils.hpp" |
| |
| #include <bits/basic_string.h> |
| |
| #include <MctpRequester.hpp> |
| #include <NvidiaGpuMctpVdm.hpp> |
| #include <NvidiaPcieDevice.hpp> |
| #include <NvidiaPcieInterface.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 <functional> |
| #include <limits> |
| #include <memory> |
| #include <span> |
| #include <string> |
| #include <system_error> |
| #include <vector> |
| |
| using std::string; |
| |
| using namespace std::literals; |
| |
| NvidiaPciePortInfo::NvidiaPciePortInfo( |
| std::shared_ptr<sdbusplus::asio::connection>& 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<uint64_t>::max()); |
| |
| pciePortInterface->register_property("Width", |
| std::numeric_limits<size_t>::max()); |
| |
| if (!pciePortInterface->initialize()) |
| { |
| lg2::error( |
| "Error initializing PCIe Device Interface for EID={EID}, PortType={PT}, PortNumber={PN}", |
| "EID", eid, "PT", static_cast<uint8_t>(portType), "PN", portNumber); |
| } |
| |
| std::vector<Association> 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<uint8_t>(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<const uint8_t> 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<uint8_t>(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<uint8_t>(cc), "RESC", reasonCode, "EID", |
| eid, "PT", static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(portType), "PN", |
| portNumber); |
| return; |
| } |
| |
| mctpRequester.sendRecvMsg( |
| eid, request, |
| [weak{weak_from_this()}](const std::error_code& ec, |
| std::span<const uint8_t> buffer) { |
| std::shared_ptr<NvidiaPciePortInfo> self = weak.lock(); |
| if (!self) |
| { |
| lg2::error("Invalid reference to NvidiaPciePortInfo"); |
| return; |
| } |
| self->processResponse(ec, buffer); |
| }); |
| } |