xref: /openbmc/bmcweb/redfish-core/lib/pcie.hpp (revision cb103130)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 
17 #pragma once
18 
19 #include "node.hpp"
20 
21 #include <boost/system/linux_error.hpp>
22 
23 namespace redfish
24 {
25 
26 static constexpr char const *pcieService = "xyz.openbmc_project.PCIe";
27 static constexpr char const *pciePath = "/xyz/openbmc_project/PCIe";
28 static constexpr char const *pcieDeviceInterface =
29     "xyz.openbmc_project.PCIe.Device";
30 
31 static inline void getPCIeDeviceList(std::shared_ptr<AsyncResp> asyncResp)
32 {
33     auto getPCIeMapCallback =
34         [asyncResp](const boost::system::error_code ec,
35                     std::vector<std::string> &pcieDevicePaths) {
36             if (ec)
37             {
38                 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
39                                  << ec.message();
40                 // Not an error, system just doesn't have PCIe info
41                 return;
42             }
43             nlohmann::json &pcieDeviceList =
44                 asyncResp->res.jsonValue["PCIeDevices"];
45             pcieDeviceList = nlohmann::json::array();
46             for (const std::string &pcieDevicePath : pcieDevicePaths)
47             {
48                 size_t devStart = pcieDevicePath.rfind("/");
49                 if (devStart == std::string::npos)
50                 {
51                     continue;
52                 }
53 
54                 std::string devName = pcieDevicePath.substr(devStart + 1);
55                 if (devName.empty())
56                 {
57                     continue;
58                 }
59                 pcieDeviceList.push_back(
60                     {{"@odata.id",
61                       "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
62             }
63             asyncResp->res.jsonValue["PCIeDevices@odata.count"] =
64                 pcieDeviceList.size();
65         };
66     crow::connections::systemBus->async_method_call(
67         std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
68         "/xyz/openbmc_project/object_mapper",
69         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
70         std::string(pciePath) + "/", 1, std::array<std::string, 0>());
71 }
72 
73 class SystemPCIeDevice : public Node
74 {
75   public:
76     SystemPCIeDevice(CrowApp &app) :
77         Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/",
78              std::string())
79     {
80         entityPrivileges = {
81             {boost::beast::http::verb::get, {{"Login"}}},
82             {boost::beast::http::verb::head, {{"Login"}}},
83             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
84             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
85             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
86             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
87     }
88 
89   private:
90     void doGet(crow::Response &res, const crow::Request &req,
91                const std::vector<std::string> &params) override
92     {
93         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
94         if (params.size() != 1)
95         {
96             messages::internalError(asyncResp->res);
97             return;
98         }
99         const std::string &device = params[0];
100 
101         auto getPCIeDeviceCallback =
102             [asyncResp,
103              device](const boost::system::error_code ec,
104                      boost::container::flat_map<
105                          std::string, sdbusplus::message::variant<std::string>>
106                          &pcieDevProperties) {
107                 if (ec)
108                 {
109                     BMCWEB_LOG_DEBUG
110                         << "failed to get PCIe Device properties ec: "
111                         << ec.value() << ": " << ec.message();
112                     if (ec.value() ==
113                         boost::system::linux_error::bad_request_descriptor)
114                     {
115                         messages::resourceNotFound(asyncResp->res, "PCIeDevice",
116                                                    device);
117                     }
118                     else
119                     {
120                         messages::internalError(asyncResp->res);
121                     }
122                     return;
123                 }
124 
125                 asyncResp->res.jsonValue = {
126                     {"@odata.type", "#PCIeDevice.v1_2_0.PCIeDevice"},
127                     {"@odata.context",
128                      "/redfish/v1/$metadata#PCIeDevice.v1_2_0.PCIeDevice"},
129                     {"@odata.id",
130                      "/redfish/v1/Systems/system/PCIeDevices/" + device},
131                     {"Name", "PCIe Device"},
132                     {"Id", device}};
133 
134                 if (std::string *property =
135                         sdbusplus::message::variant_ns::get_if<std::string>(
136                             &pcieDevProperties["Manufacturer"]);
137                     property)
138                 {
139                     asyncResp->res.jsonValue["Manufacturer"] = *property;
140                 }
141 
142                 if (std::string *property =
143                         sdbusplus::message::variant_ns::get_if<std::string>(
144                             &pcieDevProperties["DeviceType"]);
145                     property)
146                 {
147                     asyncResp->res.jsonValue["DeviceType"] = *property;
148                 }
149 
150                 nlohmann::json &pcieFunctionList =
151                     asyncResp->res.jsonValue["Links"]["PCIeFunctions"];
152                 pcieFunctionList = nlohmann::json::array();
153                 static constexpr const int maxPciFunctionNum = 8;
154                 for (int functionNum = 0; functionNum < maxPciFunctionNum;
155                      functionNum++)
156                 {
157                     // Check if this function exists by looking for a device ID
158                     std::string devIDProperty =
159                         "Function" + std::to_string(functionNum) + "DeviceId";
160                     if (std::string *property =
161                             sdbusplus::message::variant_ns::get_if<std::string>(
162                                 &pcieDevProperties[devIDProperty]);
163                         property && !property->empty())
164                     {
165                         pcieFunctionList.push_back(
166                             {{"@odata.id",
167                               "/redfish/v1/Systems/system/PCIeDevices/" +
168                                   device + "/PCIeFunctions/" +
169                                   std::to_string(functionNum)}});
170                     }
171                 }
172                 asyncResp->res.jsonValue["Links"]["PCIeFunctions@odata.count"] =
173                     pcieFunctionList.size();
174             };
175         std::string escapedPath = std::string(pciePath) + "/" + device;
176         dbus::utility::escapePathForDbus(escapedPath);
177         crow::connections::systemBus->async_method_call(
178             std::move(getPCIeDeviceCallback), pcieService, escapedPath,
179             "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
180     }
181 };
182 
183 class SystemPCIeFunction : public Node
184 {
185   public:
186     SystemPCIeFunction(CrowApp &app) :
187         Node(
188             app,
189             "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/",
190             std::string(), std::string())
191     {
192         entityPrivileges = {
193             {boost::beast::http::verb::get, {{"Login"}}},
194             {boost::beast::http::verb::head, {{"Login"}}},
195             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
196             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
197             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
198             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
199     }
200 
201   private:
202     void doGet(crow::Response &res, const crow::Request &req,
203                const std::vector<std::string> &params) override
204     {
205         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
206         if (params.size() != 2)
207         {
208             messages::internalError(asyncResp->res);
209             return;
210         }
211         const std::string &device = params[0];
212         const std::string &function = params[1];
213 
214         auto getPCIeDeviceCallback =
215             [asyncResp, device, function](
216                 const boost::system::error_code ec,
217                 boost::container::flat_map<
218                     std::string, sdbusplus::message::variant<std::string>>
219                     &pcieDevProperties) {
220                 if (ec)
221                 {
222                     BMCWEB_LOG_DEBUG
223                         << "failed to get PCIe Device properties ec: "
224                         << ec.value() << ": " << ec.message();
225                     if (ec.value() ==
226                         boost::system::linux_error::bad_request_descriptor)
227                     {
228                         messages::resourceNotFound(asyncResp->res, "PCIeDevice",
229                                                    device);
230                     }
231                     else
232                     {
233                         messages::internalError(asyncResp->res);
234                     }
235                     return;
236                 }
237 
238                 // Check if this function exists by looking for a device ID
239                 std::string devIDProperty = "Function" + function + "DeviceId";
240                 if (std::string *property =
241                         sdbusplus::message::variant_ns::get_if<std::string>(
242                             &pcieDevProperties[devIDProperty]);
243                     property && property->empty())
244                 {
245                     messages::resourceNotFound(asyncResp->res, "PCIeFunction",
246                                                function);
247                     return;
248                 }
249 
250                 asyncResp->res.jsonValue = {
251                     {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
252                     {"@odata.context",
253                      "/redfish/v1/$metadata#PCIeFunction.PCIeFunction"},
254                     {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
255                                       device + "/PCIeFunctions/" + function},
256                     {"Name", "PCIe Function"},
257                     {"Id", function},
258                     {"FunctionId", std::stoi(function)},
259                     {"Links",
260                      {{"PCIeDevice",
261                        {{"@odata.id",
262                          "/redfish/v1/Systems/system/PCIeDevices/" +
263                              device}}}}}};
264 
265                 if (std::string *property =
266                         sdbusplus::message::variant_ns::get_if<std::string>(
267                             &pcieDevProperties["Function" + function +
268                                                "DeviceId"]);
269                     property)
270                 {
271                     asyncResp->res.jsonValue["DeviceId"] = *property;
272                 }
273 
274                 if (std::string *property =
275                         sdbusplus::message::variant_ns::get_if<std::string>(
276                             &pcieDevProperties["Function" + function +
277                                                "VendorId"]);
278                     property)
279                 {
280                     asyncResp->res.jsonValue["VendorId"] = *property;
281                 }
282 
283                 if (std::string *property =
284                         sdbusplus::message::variant_ns::get_if<std::string>(
285                             &pcieDevProperties["Function" + function +
286                                                "FunctionType"]);
287                     property)
288                 {
289                     asyncResp->res.jsonValue["FunctionType"] = *property;
290                 }
291 
292                 if (std::string *property =
293                         sdbusplus::message::variant_ns::get_if<std::string>(
294                             &pcieDevProperties["Function" + function +
295                                                "DeviceClass"]);
296                     property)
297                 {
298                     asyncResp->res.jsonValue["DeviceClass"] = *property;
299                 }
300 
301                 if (std::string *property =
302                         sdbusplus::message::variant_ns::get_if<std::string>(
303                             &pcieDevProperties["Function" + function +
304                                                "ClassCode"]);
305                     property)
306                 {
307                     asyncResp->res.jsonValue["ClassCode"] = *property;
308                 }
309 
310                 if (std::string *property =
311                         sdbusplus::message::variant_ns::get_if<std::string>(
312                             &pcieDevProperties["Function" + function +
313                                                "RevisionId"]);
314                     property)
315                 {
316                     asyncResp->res.jsonValue["RevisionId"] = *property;
317                 }
318 
319                 if (std::string *property =
320                         sdbusplus::message::variant_ns::get_if<std::string>(
321                             &pcieDevProperties["Function" + function +
322                                                "SubsystemId"]);
323                     property)
324                 {
325                     asyncResp->res.jsonValue["SubsystemId"] = *property;
326                 }
327 
328                 if (std::string *property =
329                         sdbusplus::message::variant_ns::get_if<std::string>(
330                             &pcieDevProperties["Function" + function +
331                                                "SubsystemVendorId"]);
332                     property)
333                 {
334                     asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
335                 }
336             };
337         std::string escapedPath = std::string(pciePath) + "/" + device;
338         dbus::utility::escapePathForDbus(escapedPath);
339         crow::connections::systemBus->async_method_call(
340             std::move(getPCIeDeviceCallback), pcieService, escapedPath,
341             "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
342     }
343 };
344 
345 } // namespace redfish
346