xref: /openbmc/dbus-sensors/src/nvidia-gpu/NvidiaPcieInterface.cpp (revision e0b80e1e58bddcf218369f2f9e3ba2002b59b6f9)
1 /*
2  * SPDX-FileCopyrightText: Copyright OpenBMC Authors
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include "NvidiaPcieInterface.hpp"
7 
8 #include "Utils.hpp"
9 
10 #include <bits/basic_string.h>
11 
12 #include <MctpRequester.hpp>
13 #include <NvidiaGpuMctpVdm.hpp>
14 #include <NvidiaPcieDevice.hpp>
15 #include <OcpMctpVdm.hpp>
16 #include <phosphor-logging/lg2.hpp>
17 #include <sdbusplus/asio/connection.hpp>
18 #include <sdbusplus/asio/object_server.hpp>
19 
20 #include <cmath>
21 #include <cstddef>
22 #include <cstdint>
23 #include <functional>
24 #include <limits>
25 #include <memory>
26 #include <span>
27 #include <string>
28 #include <system_error>
29 #include <vector>
30 
31 using std::string;
32 
33 using namespace std::literals;
34 
NvidiaPcieInterface(std::shared_ptr<sdbusplus::asio::connection> & conn,mctp::MctpRequester & mctpRequester,const std::string & name,const std::string & path,uint8_t eid,sdbusplus::asio::object_server & objectServer)35 NvidiaPcieInterface::NvidiaPcieInterface(
36     std::shared_ptr<sdbusplus::asio::connection>& conn,
37     mctp::MctpRequester& mctpRequester, const std::string& name,
38     const std::string& path, uint8_t eid,
39     sdbusplus::asio::object_server& objectServer) :
40     eid(eid), path(path), conn(conn), mctpRequester(mctpRequester)
41 {
42     const std::string dbusPath = pcieDevicePathPrefix + escapeName(name);
43 
44     pcieDeviceInterface = objectServer.add_interface(
45         dbusPath, "xyz.openbmc_project.Inventory.Item.PCIeDevice");
46 
47     switchInterface = objectServer.add_interface(
48         dbusPath, "xyz.openbmc_project.Inventory.Item.PCIeSwitch");
49 
50     pcieDeviceInterface->register_property(
51         "GenerationInUse",
52         std::string(
53             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown"));
54 
55     pcieDeviceInterface->register_property("LanesInUse",
56                                            std::numeric_limits<size_t>::max());
57 
58     pcieDeviceInterface->register_property(
59         "GenerationSupported",
60         std::string(
61             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown"));
62 
63     pcieDeviceInterface->register_property("MaxLanes", static_cast<size_t>(0));
64 
65     if (!pcieDeviceInterface->initialize())
66     {
67         lg2::error("Error initializing PCIe Device Interface for EID={EID}",
68                    "EID", eid);
69     }
70 
71     if (!switchInterface->initialize())
72     {
73         lg2::error("Error initializing Switch Interface for EID={EID}", "EID",
74                    eid);
75     }
76 }
77 
mapPcieGeneration(uint32_t value)78 string NvidiaPcieInterface::mapPcieGeneration(uint32_t value)
79 {
80     switch (value)
81     {
82         case 1:
83             return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1";
84         case 2:
85             return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2";
86         case 3:
87             return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3";
88         case 4:
89             return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4";
90         case 5:
91             return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5";
92         case 6:
93             return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen6";
94         default:
95             return "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown";
96     }
97 }
98 
decodeLinkWidth(uint32_t value)99 size_t NvidiaPcieInterface::decodeLinkWidth(uint32_t value)
100 {
101     return (value > 0) ? pow(2, value - 1) : 0;
102 }
103 
processResponse(const std::error_code & ec,std::span<const uint8_t> response)104 void NvidiaPcieInterface::processResponse(const std::error_code& ec,
105                                           std::span<const uint8_t> response)
106 {
107     if (ec)
108     {
109         lg2::error(
110             "Error updating PCIe Interface: sending message over MCTP failed, "
111             "rc={RC}, EID={EID}",
112             "RC", ec.value(), "EID", eid);
113         return;
114     }
115 
116     ocp::accelerator_management::CompletionCode cc{};
117     uint16_t reasonCode = 0;
118     size_t numTelemetryValue = 0;
119 
120     auto rc = gpu::decodeQueryScalarGroupTelemetryV2Response(
121         response, cc, reasonCode, numTelemetryValue, telemetryValues);
122 
123     if (rc != 0 || cc != ocp::accelerator_management::CompletionCode::SUCCESS)
124     {
125         lg2::error("Error updating PCIe Interface: decode failed, "
126                    "rc={RC}, cc={CC}, reasonCode={RESC}, EID={EID}",
127                    "RC", rc, "CC", static_cast<uint8_t>(cc), "RESC", reasonCode,
128                    "EID", eid);
129         return;
130     }
131 
132     if (!telemetryValues.empty())
133     {
134         pcieDeviceInterface->set_property(
135             "GenerationInUse", mapPcieGeneration(telemetryValues[0]));
136     }
137 
138     if (telemetryValues.size() > 1)
139     {
140         pcieDeviceInterface->set_property(
141             "LanesInUse",
142             decodeLinkWidth(static_cast<size_t>(telemetryValues[1])));
143     }
144 
145     if (telemetryValues.size() > 3)
146     {
147         pcieDeviceInterface->set_property(
148             "GenerationSupported", mapPcieGeneration(telemetryValues[3]));
149     }
150 
151     if (telemetryValues.size() > 4)
152     {
153         pcieDeviceInterface->set_property(
154             "MaxLanes",
155             decodeLinkWidth(static_cast<size_t>(telemetryValues[4])));
156     }
157 }
158 
update()159 void NvidiaPcieInterface::update()
160 {
161     auto rc =
162         gpu::encodeQueryScalarGroupTelemetryV2Request(0, {}, 0, 0, 1, request);
163 
164     if (rc != 0)
165     {
166         lg2::error("Error updating PCIe Interface: failed, rc={RC}, EID={EID}",
167                    "RC", rc, "EID", eid);
168         return;
169     }
170 
171     mctpRequester.sendRecvMsg(
172         eid, request,
173         [weak{weak_from_this()}](const std::error_code& ec,
174                                  std::span<const uint8_t> buffer) {
175             std::shared_ptr<NvidiaPcieInterface> self = weak.lock();
176             if (!self)
177             {
178                 lg2::error(
179                     "Invalid reference to NvidiaPcieInterface for EID {EID}",
180                     "EID", self->eid);
181                 return;
182             }
183             self->processResponse(ec, buffer);
184         });
185 }
186