xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 5e7e2dc585dc7a7e62d2b648b541e7f50c39ea5d)
1f5c9f8bdSJason M. Bills /*
2f5c9f8bdSJason M. Bills // Copyright (c) 2018 Intel Corporation
3f5c9f8bdSJason M. Bills //
4f5c9f8bdSJason M. Bills // Licensed under the Apache License, Version 2.0 (the "License");
5f5c9f8bdSJason M. Bills // you may not use this file except in compliance with the License.
6f5c9f8bdSJason M. Bills // You may obtain a copy of the License at
7f5c9f8bdSJason M. Bills //
8f5c9f8bdSJason M. Bills //      http://www.apache.org/licenses/LICENSE-2.0
9f5c9f8bdSJason M. Bills //
10f5c9f8bdSJason M. Bills // Unless required by applicable law or agreed to in writing, software
11f5c9f8bdSJason M. Bills // distributed under the License is distributed on an "AS IS" BASIS,
12f5c9f8bdSJason M. Bills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f5c9f8bdSJason M. Bills // See the License for the specific language governing permissions and
14f5c9f8bdSJason M. Bills // limitations under the License.
15f5c9f8bdSJason M. Bills */
16f5c9f8bdSJason M. Bills 
17f5c9f8bdSJason M. Bills #pragma once
18f5c9f8bdSJason M. Bills 
193ccb3adbSEd Tanous #include "app.hpp"
207a1dbc48SGeorge Liu #include "dbus_utility.hpp"
210ec8b83dSEd Tanous #include "generated/enums/pcie_device.hpp"
223ccb3adbSEd Tanous #include "query.hpp"
233ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
243ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
250ec8b83dSEd Tanous 
26f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
27d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
28d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
29f5c9f8bdSJason M. Bills 
30f5c9f8bdSJason M. Bills namespace redfish
31f5c9f8bdSJason M. Bills {
32f5c9f8bdSJason M. Bills 
33f5c9f8bdSJason M. Bills static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
34f5c9f8bdSJason M. Bills static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
35f5c9f8bdSJason M. Bills static constexpr char const* pcieDeviceInterface =
36f5c9f8bdSJason M. Bills     "xyz.openbmc_project.PCIe.Device";
37f5c9f8bdSJason M. Bills 
38b5a76932SEd Tanous static inline void
398d1b46d7Szhanghch05     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
40adbe192aSJason M. Bills                       const std::string& name)
41f5c9f8bdSJason M. Bills {
427a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
437a1dbc48SGeorge Liu         pciePath, 1, {},
447a1dbc48SGeorge Liu         [asyncResp, name](const boost::system::error_code& ec,
45b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
46b9d36b47SEd Tanous                               pcieDevicePaths) {
47f5c9f8bdSJason M. Bills         if (ec)
48f5c9f8bdSJason M. Bills         {
49a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
50f5c9f8bdSJason M. Bills                              << ec.message();
51a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
52f5c9f8bdSJason M. Bills             return;
53f5c9f8bdSJason M. Bills         }
54adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
55f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
56f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
57f5c9f8bdSJason M. Bills         {
583174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
59f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
60f5c9f8bdSJason M. Bills             {
61f5c9f8bdSJason M. Bills                 continue;
62f5c9f8bdSJason M. Bills             }
63f5c9f8bdSJason M. Bills 
64f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
65f5c9f8bdSJason M. Bills             if (devName.empty())
66f5c9f8bdSJason M. Bills             {
67f5c9f8bdSJason M. Bills                 continue;
68f5c9f8bdSJason M. Bills             }
691476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
70eddfc437SWilly Tu             pcieDevice["@odata.id"] = crow::utility::urlFromPieces(
71eddfc437SWilly Tu                 "redfish", "v1", "Systems", "system", "PCIeDevices", devName);
721476687dSEd Tanous             pcieDeviceList.push_back(std::move(pcieDevice));
73f5c9f8bdSJason M. Bills         }
74002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
757a1dbc48SGeorge Liu         });
76f5c9f8bdSJason M. Bills }
77f5c9f8bdSJason M. Bills 
787e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
79adbe192aSJason M. Bills {
80adbe192aSJason M. Bills     /**
81adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
82adbe192aSJason M. Bills      */
8322d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
84ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
857e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
8645ca1b86SEd Tanous             [&app](const crow::Request& req,
8722d268cbSEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8822d268cbSEd Tanous                    const std::string& systemName) {
893ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
90adbe192aSJason M. Bills         {
9145ca1b86SEd Tanous             return;
9245ca1b86SEd Tanous         }
9322d268cbSEd Tanous         if (systemName != "system")
9422d268cbSEd Tanous         {
9522d268cbSEd Tanous             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
9622d268cbSEd Tanous                                        systemName);
9722d268cbSEd Tanous             return;
9822d268cbSEd Tanous         }
991476687dSEd Tanous 
1001476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
1011476687dSEd Tanous             "#PCIeDeviceCollection.PCIeDeviceCollection";
1021476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
1031476687dSEd Tanous             "/redfish/v1/Systems/system/PCIeDevices";
1041476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
105002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
1061476687dSEd Tanous         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
1071476687dSEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = 0;
108adbe192aSJason M. Bills         getPCIeDeviceList(asyncResp, "Members");
1097e860f15SJohn Edward Broadbent         });
110f5c9f8bdSJason M. Bills }
111f5c9f8bdSJason M. Bills 
1120ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes>
11362cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
11462cd45afSSpencer Ku {
11562cd45afSSpencer Ku     if (generationInUse ==
11662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
11762cd45afSSpencer Ku     {
1180ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen1;
11962cd45afSSpencer Ku     }
12062cd45afSSpencer Ku     if (generationInUse ==
12162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
12262cd45afSSpencer Ku     {
1230ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen2;
12462cd45afSSpencer Ku     }
12562cd45afSSpencer Ku     if (generationInUse ==
12662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
12762cd45afSSpencer Ku     {
1280ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen3;
12962cd45afSSpencer Ku     }
13062cd45afSSpencer Ku     if (generationInUse ==
13162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
13262cd45afSSpencer Ku     {
1330ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen4;
13462cd45afSSpencer Ku     }
13562cd45afSSpencer Ku     if (generationInUse ==
13662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
13762cd45afSSpencer Ku     {
1380ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen5;
13962cd45afSSpencer Ku     }
140e825cbc8SEd Tanous     if (generationInUse.empty() ||
141e825cbc8SEd Tanous         generationInUse ==
14262cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
14362cd45afSSpencer Ku     {
1440ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Invalid;
14562cd45afSSpencer Ku     }
14662cd45afSSpencer Ku 
14762cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
14862cd45afSSpencer Ku     return std::nullopt;
14962cd45afSSpencer Ku }
15062cd45afSSpencer Ku 
1517e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDevice(App& app)
152f5c9f8bdSJason M. Bills {
15322d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
154ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDevice)
155002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
156002d39b4SEd Tanous             [&app](const crow::Request& req,
1577e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15822d268cbSEd Tanous                    const std::string& systemName, const std::string& device) {
1593ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1607e860f15SJohn Edward Broadbent         {
16145ca1b86SEd Tanous             return;
16245ca1b86SEd Tanous         }
16322d268cbSEd Tanous         if (systemName != "system")
16422d268cbSEd Tanous         {
16522d268cbSEd Tanous             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
16622d268cbSEd Tanous                                        systemName);
16722d268cbSEd Tanous             return;
16822d268cbSEd Tanous         }
16922d268cbSEd Tanous 
170168e20c1SEd Tanous         auto getPCIeDeviceCallback =
17145ca1b86SEd Tanous             [asyncResp, device](
172*5e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
17345ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
174f5c9f8bdSJason M. Bills             if (ec)
175f5c9f8bdSJason M. Bills             {
176f5c9f8bdSJason M. Bills                 BMCWEB_LOG_DEBUG
177002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
178002d39b4SEd Tanous                     << ": " << ec.message();
17945ca1b86SEd Tanous                 if (ec.value() ==
18045ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
181f5c9f8bdSJason M. Bills                 {
182002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
183002d39b4SEd Tanous                                                device);
184f5c9f8bdSJason M. Bills                 }
185f5c9f8bdSJason M. Bills                 else
186f5c9f8bdSJason M. Bills                 {
187f5c9f8bdSJason M. Bills                     messages::internalError(asyncResp->res);
188f5c9f8bdSJason M. Bills                 }
189f5c9f8bdSJason M. Bills                 return;
190f5c9f8bdSJason M. Bills             }
191f5c9f8bdSJason M. Bills 
192d1bde9e5SKrzysztof Grobelny             const std::string* manufacturer = nullptr;
193d1bde9e5SKrzysztof Grobelny             const std::string* deviceType = nullptr;
194d1bde9e5SKrzysztof Grobelny             const std::string* generationInUse = nullptr;
195703f6741SMyung Bae             const size_t* lanesInUse = nullptr;
196d1bde9e5SKrzysztof Grobelny 
197d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
198d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), pcieDevProperties,
199d1bde9e5SKrzysztof Grobelny                 "Manufacturer", manufacturer, "DeviceType", deviceType,
200703f6741SMyung Bae                 "LanesInUse", lanesInUse, "GenerationInUse", generationInUse);
201d1bde9e5SKrzysztof Grobelny 
202d1bde9e5SKrzysztof Grobelny             if (!success)
203d1bde9e5SKrzysztof Grobelny             {
204d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
205d1bde9e5SKrzysztof Grobelny                 return;
206d1bde9e5SKrzysztof Grobelny             }
207d1bde9e5SKrzysztof Grobelny 
208703f6741SMyung Bae             // The default value of LanesInUse is 0, and the field will be
209703f6741SMyung Bae             // left as off if it is a default value.
210703f6741SMyung Bae             if (lanesInUse != nullptr && *lanesInUse != 0)
211703f6741SMyung Bae             {
212703f6741SMyung Bae                 asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
213703f6741SMyung Bae                     *lanesInUse;
214703f6741SMyung Bae             }
215703f6741SMyung Bae 
216d1bde9e5SKrzysztof Grobelny             if (generationInUse != nullptr)
217d1bde9e5SKrzysztof Grobelny             {
2180ec8b83dSEd Tanous                 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
219d1bde9e5SKrzysztof Grobelny                     redfishPcieGenerationFromDbus(*generationInUse);
220d1bde9e5SKrzysztof Grobelny                 if (!redfishGenerationInUse)
221d1bde9e5SKrzysztof Grobelny                 {
222d1bde9e5SKrzysztof Grobelny                     messages::internalError(asyncResp->res);
223d1bde9e5SKrzysztof Grobelny                     return;
224d1bde9e5SKrzysztof Grobelny                 }
2250ec8b83dSEd Tanous                 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
226d1bde9e5SKrzysztof Grobelny                 {
227d1bde9e5SKrzysztof Grobelny                     asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
228d1bde9e5SKrzysztof Grobelny                         *redfishGenerationInUse;
229d1bde9e5SKrzysztof Grobelny                 }
230a9f68bb5STony Lee             }
231d1bde9e5SKrzysztof Grobelny 
232d1bde9e5SKrzysztof Grobelny             if (manufacturer != nullptr)
233d1bde9e5SKrzysztof Grobelny             {
234d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
235d1bde9e5SKrzysztof Grobelny             }
236d1bde9e5SKrzysztof Grobelny 
237d1bde9e5SKrzysztof Grobelny             if (deviceType != nullptr)
238d1bde9e5SKrzysztof Grobelny             {
239d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["DeviceType"] = *deviceType;
240d1bde9e5SKrzysztof Grobelny             }
241d1bde9e5SKrzysztof Grobelny 
2421476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
2431476687dSEd Tanous                 "#PCIeDevice.v1_4_0.PCIeDevice";
2441476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
245eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
246eddfc437SWilly Tu                                              "system", "PCIeDevices", device);
2471476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Device";
2481476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = device;
2491476687dSEd Tanous 
2501476687dSEd Tanous             asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
251eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
252eddfc437SWilly Tu                                              "system", "PCIeDevices", device,
253eddfc437SWilly Tu                                              "PCIeFunctions");
254dede6a98SJason M. Bills         };
255dede6a98SJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
256dede6a98SJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
257d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
258d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
259d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
2607e860f15SJohn Edward Broadbent         });
261dede6a98SJason M. Bills }
262dede6a98SJason M. Bills 
2637e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
2647e860f15SJohn Edward Broadbent {
265dede6a98SJason M. Bills     /**
266dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
267dede6a98SJason M. Bills      */
2687e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2697e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
270ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
271002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
272002d39b4SEd Tanous             [&app](const crow::Request& req,
2737e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27445ca1b86SEd Tanous                    const std::string& device) {
2753ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
276dede6a98SJason M. Bills         {
27745ca1b86SEd Tanous             return;
27845ca1b86SEd Tanous         }
2791476687dSEd Tanous 
2801476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
2811476687dSEd Tanous             "#PCIeFunctionCollection.PCIeFunctionCollection";
282eddfc437SWilly Tu         asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
283eddfc437SWilly Tu             "redfish", "v1", "Systems", "system", "PCIeDevices", device,
284eddfc437SWilly Tu             "PCIeFunctions");
2851476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
2861476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
2871476687dSEd Tanous             "Collection of PCIe Functions for PCIe Device " + device;
288dede6a98SJason M. Bills 
289b9d36b47SEd Tanous         auto getPCIeDeviceCallback =
29045ca1b86SEd Tanous             [asyncResp, device](
291*5e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
29245ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
2937e860f15SJohn Edward Broadbent             if (ec)
2947e860f15SJohn Edward Broadbent             {
2957e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG
296002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
297002d39b4SEd Tanous                     << ": " << ec.message();
29845ca1b86SEd Tanous                 if (ec.value() ==
29945ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
3007e860f15SJohn Edward Broadbent                 {
301002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
302002d39b4SEd Tanous                                                device);
3037e860f15SJohn Edward Broadbent                 }
3047e860f15SJohn Edward Broadbent                 else
3057e860f15SJohn Edward Broadbent                 {
3067e860f15SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
3077e860f15SJohn Edward Broadbent                 }
3087e860f15SJohn Edward Broadbent                 return;
3097e860f15SJohn Edward Broadbent             }
3107e860f15SJohn Edward Broadbent 
3117e860f15SJohn Edward Broadbent             nlohmann::json& pcieFunctionList =
3127e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members"];
3137e860f15SJohn Edward Broadbent             pcieFunctionList = nlohmann::json::array();
3147e860f15SJohn Edward Broadbent             static constexpr const int maxPciFunctionNum = 8;
31545ca1b86SEd Tanous             for (int functionNum = 0; functionNum < maxPciFunctionNum;
31645ca1b86SEd Tanous                  functionNum++)
3177e860f15SJohn Edward Broadbent             {
318b9d36b47SEd Tanous                 // Check if this function exists by looking for a
319b9d36b47SEd Tanous                 // device ID
3207e860f15SJohn Edward Broadbent                 std::string devIDProperty =
321002d39b4SEd Tanous                     "Function" + std::to_string(functionNum) + "DeviceId";
322b9d36b47SEd Tanous                 const std::string* property = nullptr;
323b9d36b47SEd Tanous                 for (const auto& propEntry : pcieDevProperties)
3247e860f15SJohn Edward Broadbent                 {
325b9d36b47SEd Tanous                     if (propEntry.first == devIDProperty)
326b9d36b47SEd Tanous                     {
327002d39b4SEd Tanous                         property = std::get_if<std::string>(&propEntry.second);
328b9d36b47SEd Tanous                     }
329b9d36b47SEd Tanous                 }
330fb0ecc3eSNan Zhou                 if (property == nullptr || property->empty())
331b9d36b47SEd Tanous                 {
332e28ce0e6SNan Zhou                     continue;
333b9d36b47SEd Tanous                 }
3341476687dSEd Tanous                 nlohmann::json::object_t pcieFunction;
335eddfc437SWilly Tu                 pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
336eddfc437SWilly Tu                     "redfish", "v1", "Systems", "system", "PCIeDevices", device,
337eddfc437SWilly Tu                     "PCIeFunctions", std::to_string(functionNum));
3381476687dSEd Tanous                 pcieFunctionList.push_back(std::move(pcieFunction));
3397e860f15SJohn Edward Broadbent             }
340a818d15aSJiaqing Zhao             asyncResp->res.jsonValue["Members@odata.count"] =
3417e860f15SJohn Edward Broadbent                 pcieFunctionList.size();
3427e860f15SJohn Edward Broadbent         };
3437e860f15SJohn Edward Broadbent         std::string escapedPath = std::string(pciePath) + "/" + device;
3447e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(escapedPath);
345d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
346d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
347d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
3487e860f15SJohn Edward Broadbent         });
3497e860f15SJohn Edward Broadbent }
3507e860f15SJohn Edward Broadbent 
3517e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app)
3527e860f15SJohn Edward Broadbent {
3537e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
3547e860f15SJohn Edward Broadbent         app,
3557e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
356ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunction)
357002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
358002d39b4SEd Tanous             [&app](const crow::Request& req,
35945ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
360002d39b4SEd Tanous                    const std::string& device, const std::string& function) {
3613ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
36245ca1b86SEd Tanous         {
36345ca1b86SEd Tanous             return;
36445ca1b86SEd Tanous         }
365168e20c1SEd Tanous         auto getPCIeDeviceCallback =
366168e20c1SEd Tanous             [asyncResp, device, function](
367*5e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
368b9d36b47SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
369dede6a98SJason M. Bills             if (ec)
370dede6a98SJason M. Bills             {
371dede6a98SJason M. Bills                 BMCWEB_LOG_DEBUG
372002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
373002d39b4SEd Tanous                     << ": " << ec.message();
374dede6a98SJason M. Bills                 if (ec.value() ==
375dede6a98SJason M. Bills                     boost::system::linux_error::bad_request_descriptor)
376dede6a98SJason M. Bills                 {
377002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
378002d39b4SEd Tanous                                                device);
379dede6a98SJason M. Bills                 }
380dede6a98SJason M. Bills                 else
381dede6a98SJason M. Bills                 {
382dede6a98SJason M. Bills                     messages::internalError(asyncResp->res);
383dede6a98SJason M. Bills                 }
384dede6a98SJason M. Bills                 return;
385dede6a98SJason M. Bills             }
386dede6a98SJason M. Bills 
3871476687dSEd Tanous             // Check if this function exists by looking for a device
3881476687dSEd Tanous             // ID
389b9d36b47SEd Tanous             std::string functionName = "Function" + function;
390b9d36b47SEd Tanous             std::string devIDProperty = functionName + "DeviceId";
391b9d36b47SEd Tanous 
392b9d36b47SEd Tanous             const std::string* devIdProperty = nullptr;
393b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
394b9d36b47SEd Tanous             {
395b9d36b47SEd Tanous                 if (property.first == devIDProperty)
396b9d36b47SEd Tanous                 {
397002d39b4SEd Tanous                     devIdProperty = std::get_if<std::string>(&property.second);
398b9d36b47SEd Tanous                     continue;
399b9d36b47SEd Tanous                 }
400b9d36b47SEd Tanous             }
401973c1355STony Lee             if (devIdProperty == nullptr || devIdProperty->empty())
402f5c9f8bdSJason M. Bills             {
403002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
404002d39b4SEd Tanous                                            function);
405f5c9f8bdSJason M. Bills                 return;
406f5c9f8bdSJason M. Bills             }
407f5c9f8bdSJason M. Bills 
4081476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
4091476687dSEd Tanous                 "#PCIeFunction.v1_2_0.PCIeFunction";
4101476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
411eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
412eddfc437SWilly Tu                                              "system", "PCIeDevices", device,
413eddfc437SWilly Tu                                              "PCIeFunctions", function);
4141476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function";
4151476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = function;
416002d39b4SEd Tanous             asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
417002d39b4SEd Tanous             asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
418eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
419eddfc437SWilly Tu                                              "system", "PCIeDevices", device);
420f5c9f8bdSJason M. Bills 
421b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
422f5c9f8bdSJason M. Bills             {
423b9d36b47SEd Tanous                 const std::string* strProperty =
424b9d36b47SEd Tanous                     std::get_if<std::string>(&property.second);
425b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceId")
426f5c9f8bdSJason M. Bills                 {
427b9d36b47SEd Tanous                     asyncResp->res.jsonValue["DeviceId"] = *strProperty;
428f5c9f8bdSJason M. Bills                 }
429b9d36b47SEd Tanous                 if (property.first == functionName + "VendorId")
430f5c9f8bdSJason M. Bills                 {
431b9d36b47SEd Tanous                     asyncResp->res.jsonValue["VendorId"] = *strProperty;
432f5c9f8bdSJason M. Bills                 }
433b9d36b47SEd Tanous                 if (property.first == functionName + "FunctionType")
434f5c9f8bdSJason M. Bills                 {
435002d39b4SEd Tanous                     asyncResp->res.jsonValue["FunctionType"] = *strProperty;
436f5c9f8bdSJason M. Bills                 }
437b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceClass")
438f5c9f8bdSJason M. Bills                 {
439002d39b4SEd Tanous                     asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
440f5c9f8bdSJason M. Bills                 }
441b9d36b47SEd Tanous                 if (property.first == functionName + "ClassCode")
442f5c9f8bdSJason M. Bills                 {
443002d39b4SEd Tanous                     asyncResp->res.jsonValue["ClassCode"] = *strProperty;
444f5c9f8bdSJason M. Bills                 }
445b9d36b47SEd Tanous                 if (property.first == functionName + "RevisionId")
446f5c9f8bdSJason M. Bills                 {
447002d39b4SEd Tanous                     asyncResp->res.jsonValue["RevisionId"] = *strProperty;
448f5c9f8bdSJason M. Bills                 }
449b9d36b47SEd Tanous                 if (property.first == functionName + "SubsystemId")
450b9d36b47SEd Tanous                 {
451002d39b4SEd Tanous                     asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
452b9d36b47SEd Tanous                 }
453002d39b4SEd Tanous                 if (property.first == functionName + "SubsystemVendorId")
454f5c9f8bdSJason M. Bills                 {
455168e20c1SEd Tanous                     asyncResp->res.jsonValue["SubsystemVendorId"] =
456b9d36b47SEd Tanous                         *strProperty;
457b9d36b47SEd Tanous                 }
458f5c9f8bdSJason M. Bills             }
459f5c9f8bdSJason M. Bills         };
460f5c9f8bdSJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
461f5c9f8bdSJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
462d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
463d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
464d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
4657e860f15SJohn Edward Broadbent         });
466f5c9f8bdSJason M. Bills }
467f5c9f8bdSJason M. Bills 
468f5c9f8bdSJason M. Bills } // namespace redfish
469