blob: 15b2280e6fefe4afb8d3331e517e87a2e7fa1115 [file] [log] [blame]
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -08001/*
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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070019#include <app.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080020#include <boost/system/linux_error.hpp>
21
22namespace redfish
23{
24
Gunnar Mills1214b7e2020-06-04 10:11:30 -050025static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
26static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
27static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080028 "xyz.openbmc_project.PCIe.Device";
29
Ed Tanousb5a76932020-09-29 16:16:58 -070030static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080031 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -070032 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080033{
Jason M. Billsadbe1922019-10-14 15:44:35 -070034 auto getPCIeMapCallback = [asyncResp, name](
35 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050036 std::vector<std::string>& pcieDevicePaths) {
Jason M. Billsadbe1922019-10-14 15:44:35 -070037 if (ec)
38 {
39 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
40 << ec.message();
41 // Not an error, system just doesn't have PCIe info
42 return;
43 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -050044 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
Jason M. Billsadbe1922019-10-14 15:44:35 -070045 pcieDeviceList = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -050046 for (const std::string& pcieDevicePath : pcieDevicePaths)
Jason M. Billsadbe1922019-10-14 15:44:35 -070047 {
Ed Tanous3174e4d2020-10-07 11:41:22 -070048 size_t devStart = pcieDevicePath.rfind('/');
Jason M. Billsadbe1922019-10-14 15:44:35 -070049 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080050 {
Jason M. Billsadbe1922019-10-14 15:44:35 -070051 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080052 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080053
Jason M. Billsadbe1922019-10-14 15:44:35 -070054 std::string devName = pcieDevicePath.substr(devStart + 1);
55 if (devName.empty())
56 {
57 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080058 }
Jason M. Billsadbe1922019-10-14 15:44:35 -070059 pcieDeviceList.push_back(
60 {{"@odata.id",
61 "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
62 }
63 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
64 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080065 crow::connections::systemBus->async_method_call(
66 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
67 "/xyz/openbmc_project/object_mapper",
68 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
69 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
70}
71
John Edward Broadbent7e860f12021-04-08 15:57:16 -070072inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -070073{
Jason M. Billsadbe1922019-10-14 15:44:35 -070074 /**
75 * Functions triggers appropriate requests on DBus
76 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -070077 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/")
78 .privileges({"Login"})
79 .methods(boost::beast::http::verb::get)(
80 [](const crow::Request&,
81 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Jason M. Billsadbe1922019-10-14 15:44:35 -070082
John Edward Broadbent7e860f12021-04-08 15:57:16 -070083 {
84 asyncResp->res.jsonValue = {
85 {"@odata.type",
86 "#PCIeDeviceCollection.PCIeDeviceCollection"},
87 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices"},
88 {"Name", "PCIe Device Collection"},
89 {"Description", "Collection of PCIe Devices"},
90 {"Members", nlohmann::json::array()},
91 {"Members@odata.count", 0}};
92 getPCIeDeviceList(asyncResp, "Members");
93 });
94}
95
96inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080097{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070098 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
99 .privileges({"Login"})
100 .methods(boost::beast::http::verb::get)(
101 [](const crow::Request&,
102 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
103 const std::string& device)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800104
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700105 {
106 auto getPCIeDeviceCallback = [asyncResp, device](
107 const boost::system::error_code
108 ec,
109 boost::container::flat_map<
110 std::string,
111 std::variant<std::string>>&
112 pcieDevProperties) {
113 if (ec)
114 {
115 BMCWEB_LOG_DEBUG
116 << "failed to get PCIe Device properties ec: "
117 << ec.value() << ": " << ec.message();
118 if (ec.value() ==
119 boost::system::linux_error::bad_request_descriptor)
120 {
121 messages::resourceNotFound(asyncResp->res,
122 "PCIeDevice", device);
123 }
124 else
125 {
126 messages::internalError(asyncResp->res);
127 }
128 return;
129 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800130
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700131 asyncResp->res.jsonValue = {
132 {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
133 {"@odata.id",
134 "/redfish/v1/Systems/system/PCIeDevices/" + device},
135 {"Name", "PCIe Device"},
136 {"Id", device}};
137
138 if (std::string* property = std::get_if<std::string>(
139 &pcieDevProperties["Manufacturer"]);
140 property)
141 {
142 asyncResp->res.jsonValue["Manufacturer"] = *property;
143 }
144
145 if (std::string* property = std::get_if<std::string>(
146 &pcieDevProperties["DeviceType"]);
147 property)
148 {
149 asyncResp->res.jsonValue["DeviceType"] = *property;
150 }
151
152 asyncResp->res.jsonValue["PCIeFunctions"] = {
153 {"@odata.id",
154 "/redfish/v1/Systems/system/PCIeDevices/" + device +
155 "/PCIeFunctions"}};
156 };
157 std::string escapedPath = std::string(pciePath) + "/" + device;
158 dbus::utility::escapePathForDbus(escapedPath);
159 crow::connections::systemBus->async_method_call(
160 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
161 "org.freedesktop.DBus.Properties", "GetAll",
162 pcieDeviceInterface);
163 });
164}
165
166inline void requestRoutesSystemPCIeFunctionCollection(App& app)
167{
168 /**
169 * Functions triggers appropriate requests on DBus
170 */
171 BMCWEB_ROUTE(app,
172 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
173 .privileges({"Login"})
174 .methods(boost::beast::http::verb::get)(
175 [](const crow::Request&,
176 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
177 const std::string& device)
178
179 {
180 asyncResp->res.jsonValue = {
181 {"@odata.type",
182 "#PCIeFunctionCollection.PCIeFunctionCollection"},
183 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
184 device + "/PCIeFunctions"},
185 {"Name", "PCIe Function Collection"},
186 {"Description",
187 "Collection of PCIe Functions for PCIe Device " + device}};
188
189 auto getPCIeDeviceCallback = [asyncResp, device](
190 const boost::system::error_code
191 ec,
192 boost::container::flat_map<
193 std::string,
194 std::variant<std::string>>&
195 pcieDevProperties) {
196 if (ec)
197 {
198 BMCWEB_LOG_DEBUG
199 << "failed to get PCIe Device properties ec: "
200 << ec.value() << ": " << ec.message();
201 if (ec.value() ==
202 boost::system::linux_error::bad_request_descriptor)
203 {
204 messages::resourceNotFound(asyncResp->res,
205 "PCIeDevice", device);
206 }
207 else
208 {
209 messages::internalError(asyncResp->res);
210 }
211 return;
212 }
213
214 nlohmann::json& pcieFunctionList =
215 asyncResp->res.jsonValue["Members"];
216 pcieFunctionList = nlohmann::json::array();
217 static constexpr const int maxPciFunctionNum = 8;
218 for (int functionNum = 0; functionNum < maxPciFunctionNum;
219 functionNum++)
220 {
221 // Check if this function exists by looking for a device
222 // ID
223 std::string devIDProperty =
224 "Function" + std::to_string(functionNum) +
225 "DeviceId";
226 std::string* property = std::get_if<std::string>(
227 &pcieDevProperties[devIDProperty]);
228 if (property && !property->empty())
229 {
230 pcieFunctionList.push_back(
231 {{"@odata.id",
232 "/redfish/v1/Systems/system/PCIeDevices/" +
233 device + "/PCIeFunctions/" +
234 std::to_string(functionNum)}});
235 }
236 }
237 asyncResp->res.jsonValue["PCIeFunctions@odata.count"] =
238 pcieFunctionList.size();
239 };
240 std::string escapedPath = std::string(pciePath) + "/" + device;
241 dbus::utility::escapePathForDbus(escapedPath);
242 crow::connections::systemBus->async_method_call(
243 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
244 "org.freedesktop.DBus.Properties", "GetAll",
245 pcieDeviceInterface);
246 });
247}
248
249inline void requestRoutesSystemPCIeFunction(App& app)
250{
251 BMCWEB_ROUTE(
252 app,
253 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
254 .privileges({"Login"})
255 .methods(
256 boost::beast::http::verb::get)([](const crow::Request&,
257 const std::shared_ptr<
258 bmcweb::AsyncResp>& asyncResp,
259 const std::string& device,
260 const std::string& function) {
261 auto getPCIeDeviceCallback = [asyncResp, device, function](
262 const boost::system::error_code ec,
263 boost::container::flat_map<
264 std::string,
265 std::variant<std::string>>&
266 pcieDevProperties) {
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800267 if (ec)
268 {
269 BMCWEB_LOG_DEBUG
270 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700271 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800272 if (ec.value() ==
273 boost::system::linux_error::bad_request_descriptor)
274 {
275 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
276 device);
277 }
278 else
279 {
280 messages::internalError(asyncResp->res);
281 }
282 return;
283 }
284
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700285 // Check if this function exists by looking for a device ID
286 std::string devIDProperty = "Function" + function + "DeviceId";
287 if (std::string* property = std::get_if<std::string>(
288 &pcieDevProperties[devIDProperty]);
289 property && property->empty())
290 {
291 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
292 function);
293 return;
294 }
295
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800296 asyncResp->res.jsonValue = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700297 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
Jason M. Billsdede6a92019-10-14 15:41:30 -0700298 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700299 device + "/PCIeFunctions/" + function},
300 {"Name", "PCIe Function"},
301 {"Id", function},
302 {"FunctionId", std::stoi(function)},
303 {"Links",
304 {{"PCIeDevice",
305 {{"@odata.id",
306 "/redfish/v1/Systems/system/PCIeDevices/" +
307 device}}}}}};
308
309 if (std::string* property = std::get_if<std::string>(
310 &pcieDevProperties["Function" + function + "DeviceId"]);
311 property)
312 {
313 asyncResp->res.jsonValue["DeviceId"] = *property;
314 }
315
316 if (std::string* property = std::get_if<std::string>(
317 &pcieDevProperties["Function" + function + "VendorId"]);
318 property)
319 {
320 asyncResp->res.jsonValue["VendorId"] = *property;
321 }
322
323 if (std::string* property = std::get_if<std::string>(
324 &pcieDevProperties["Function" + function +
325 "FunctionType"]);
326 property)
327 {
328 asyncResp->res.jsonValue["FunctionType"] = *property;
329 }
330
331 if (std::string* property = std::get_if<std::string>(
332 &pcieDevProperties["Function" + function +
333 "DeviceClass"]);
334 property)
335 {
336 asyncResp->res.jsonValue["DeviceClass"] = *property;
337 }
338
339 if (std::string* property = std::get_if<std::string>(
340 &pcieDevProperties["Function" + function +
341 "ClassCode"]);
342 property)
343 {
344 asyncResp->res.jsonValue["ClassCode"] = *property;
345 }
346
347 if (std::string* property = std::get_if<std::string>(
348 &pcieDevProperties["Function" + function +
349 "RevisionId"]);
350 property)
351 {
352 asyncResp->res.jsonValue["RevisionId"] = *property;
353 }
354
355 if (std::string* property = std::get_if<std::string>(
356 &pcieDevProperties["Function" + function +
357 "SubsystemId"]);
358 property)
359 {
360 asyncResp->res.jsonValue["SubsystemId"] = *property;
361 }
362
363 if (std::string* property = std::get_if<std::string>(
364 &pcieDevProperties["Function" + function +
365 "SubsystemVendorId"]);
366 property)
367 {
368 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
369 }
Jason M. Billsdede6a92019-10-14 15:41:30 -0700370 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700371 std::string escapedPath = std::string(pciePath) + "/" + device;
372 dbus::utility::escapePathForDbus(escapedPath);
373 crow::connections::systemBus->async_method_call(
374 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
375 "org.freedesktop.DBus.Properties", "GetAll",
376 pcieDeviceInterface);
377 });
378}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800379
380} // namespace redfish