xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 0ec8b83db7e8629c721c0e632de702bf1018f58f)
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 
19*0ec8b83dSEd Tanous #include "generated/enums/pcie_device.hpp"
20*0ec8b83dSEd Tanous 
217e860f15SJohn Edward Broadbent #include <app.hpp>
22f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
23168e20c1SEd Tanous #include <dbus_utility.hpp>
2445ca1b86SEd Tanous #include <query.hpp>
25ed398213SEd Tanous #include <registries/privilege_registry.hpp>
26d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
27d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
28d1bde9e5SKrzysztof Grobelny #include <utils/dbus_utils.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 {
42b9d36b47SEd Tanous     auto getPCIeMapCallback =
43b9d36b47SEd Tanous         [asyncResp, name](const boost::system::error_code ec,
44b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
45b9d36b47SEd Tanous                               pcieDevicePaths) {
46f5c9f8bdSJason M. Bills         if (ec)
47f5c9f8bdSJason M. Bills         {
48a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
49f5c9f8bdSJason M. Bills                              << ec.message();
50a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
51f5c9f8bdSJason M. Bills             return;
52f5c9f8bdSJason M. Bills         }
53adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
54f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
55f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
56f5c9f8bdSJason M. Bills         {
573174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
58f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
59f5c9f8bdSJason M. Bills             {
60f5c9f8bdSJason M. Bills                 continue;
61f5c9f8bdSJason M. Bills             }
62f5c9f8bdSJason M. Bills 
63f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
64f5c9f8bdSJason M. Bills             if (devName.empty())
65f5c9f8bdSJason M. Bills             {
66f5c9f8bdSJason M. Bills                 continue;
67f5c9f8bdSJason M. Bills             }
681476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
691476687dSEd Tanous             pcieDevice["@odata.id"] =
701476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + devName;
711476687dSEd Tanous             pcieDeviceList.push_back(std::move(pcieDevice));
72f5c9f8bdSJason M. Bills         }
73002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
74f5c9f8bdSJason M. Bills     };
75f5c9f8bdSJason M. Bills     crow::connections::systemBus->async_method_call(
76f5c9f8bdSJason M. Bills         std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
77f5c9f8bdSJason M. Bills         "/xyz/openbmc_project/object_mapper",
78f5c9f8bdSJason M. Bills         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
79f5c9f8bdSJason M. Bills         std::string(pciePath) + "/", 1, std::array<std::string, 0>());
80f5c9f8bdSJason M. Bills }
81f5c9f8bdSJason M. Bills 
827e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
83adbe192aSJason M. Bills {
84adbe192aSJason M. Bills     /**
85adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
86adbe192aSJason M. Bills      */
8722d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
88ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
897e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
9045ca1b86SEd Tanous             [&app](const crow::Request& req,
9122d268cbSEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9222d268cbSEd Tanous                    const std::string& systemName) {
933ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
94adbe192aSJason M. Bills         {
9545ca1b86SEd Tanous             return;
9645ca1b86SEd Tanous         }
9722d268cbSEd Tanous         if (systemName != "system")
9822d268cbSEd Tanous         {
9922d268cbSEd Tanous             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
10022d268cbSEd Tanous                                        systemName);
10122d268cbSEd Tanous             return;
10222d268cbSEd Tanous         }
1031476687dSEd Tanous 
1041476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
1051476687dSEd Tanous             "#PCIeDeviceCollection.PCIeDeviceCollection";
1061476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
1071476687dSEd Tanous             "/redfish/v1/Systems/system/PCIeDevices";
1081476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
109002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
1101476687dSEd Tanous         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
1111476687dSEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = 0;
112adbe192aSJason M. Bills         getPCIeDeviceList(asyncResp, "Members");
1137e860f15SJohn Edward Broadbent         });
114f5c9f8bdSJason M. Bills }
115f5c9f8bdSJason M. Bills 
116*0ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes>
11762cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
11862cd45afSSpencer Ku {
11962cd45afSSpencer Ku     if (generationInUse ==
12062cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
12162cd45afSSpencer Ku     {
122*0ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen1;
12362cd45afSSpencer Ku     }
12462cd45afSSpencer Ku     if (generationInUse ==
12562cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
12662cd45afSSpencer Ku     {
127*0ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen2;
12862cd45afSSpencer Ku     }
12962cd45afSSpencer Ku     if (generationInUse ==
13062cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
13162cd45afSSpencer Ku     {
132*0ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen3;
13362cd45afSSpencer Ku     }
13462cd45afSSpencer Ku     if (generationInUse ==
13562cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
13662cd45afSSpencer Ku     {
137*0ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen4;
13862cd45afSSpencer Ku     }
13962cd45afSSpencer Ku     if (generationInUse ==
14062cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
14162cd45afSSpencer Ku     {
142*0ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen5;
14362cd45afSSpencer Ku     }
144e825cbc8SEd Tanous     if (generationInUse.empty() ||
145e825cbc8SEd Tanous         generationInUse ==
14662cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
14762cd45afSSpencer Ku     {
148*0ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Invalid;
14962cd45afSSpencer Ku     }
15062cd45afSSpencer Ku 
15162cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
15262cd45afSSpencer Ku     return std::nullopt;
15362cd45afSSpencer Ku }
15462cd45afSSpencer Ku 
1557e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDevice(App& app)
156f5c9f8bdSJason M. Bills {
15722d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
158ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDevice)
159002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
160002d39b4SEd Tanous             [&app](const crow::Request& req,
1617e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16222d268cbSEd Tanous                    const std::string& systemName, const std::string& device) {
1633ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1647e860f15SJohn Edward Broadbent         {
16545ca1b86SEd Tanous             return;
16645ca1b86SEd Tanous         }
16722d268cbSEd Tanous         if (systemName != "system")
16822d268cbSEd Tanous         {
16922d268cbSEd Tanous             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
17022d268cbSEd Tanous                                        systemName);
17122d268cbSEd Tanous             return;
17222d268cbSEd Tanous         }
17322d268cbSEd Tanous 
174168e20c1SEd Tanous         auto getPCIeDeviceCallback =
17545ca1b86SEd Tanous             [asyncResp, device](
17645ca1b86SEd Tanous                 const boost::system::error_code ec,
17745ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
178f5c9f8bdSJason M. Bills             if (ec)
179f5c9f8bdSJason M. Bills             {
180f5c9f8bdSJason M. Bills                 BMCWEB_LOG_DEBUG
181002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
182002d39b4SEd Tanous                     << ": " << ec.message();
18345ca1b86SEd Tanous                 if (ec.value() ==
18445ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
185f5c9f8bdSJason M. Bills                 {
186002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
187002d39b4SEd Tanous                                                device);
188f5c9f8bdSJason M. Bills                 }
189f5c9f8bdSJason M. Bills                 else
190f5c9f8bdSJason M. Bills                 {
191f5c9f8bdSJason M. Bills                     messages::internalError(asyncResp->res);
192f5c9f8bdSJason M. Bills                 }
193f5c9f8bdSJason M. Bills                 return;
194f5c9f8bdSJason M. Bills             }
195f5c9f8bdSJason M. Bills 
196d1bde9e5SKrzysztof Grobelny             const std::string* manufacturer = nullptr;
197d1bde9e5SKrzysztof Grobelny             const std::string* deviceType = nullptr;
198d1bde9e5SKrzysztof Grobelny             const std::string* generationInUse = nullptr;
199d1bde9e5SKrzysztof Grobelny 
200d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
201d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), pcieDevProperties,
202d1bde9e5SKrzysztof Grobelny                 "Manufacturer", manufacturer, "DeviceType", deviceType,
203d1bde9e5SKrzysztof Grobelny                 "GenerationInUse", generationInUse);
204d1bde9e5SKrzysztof Grobelny 
205d1bde9e5SKrzysztof Grobelny             if (!success)
206d1bde9e5SKrzysztof Grobelny             {
207d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
208d1bde9e5SKrzysztof Grobelny                 return;
209d1bde9e5SKrzysztof Grobelny             }
210d1bde9e5SKrzysztof Grobelny 
211d1bde9e5SKrzysztof Grobelny             if (generationInUse != nullptr)
212d1bde9e5SKrzysztof Grobelny             {
213*0ec8b83dSEd Tanous                 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
214d1bde9e5SKrzysztof Grobelny                     redfishPcieGenerationFromDbus(*generationInUse);
215d1bde9e5SKrzysztof Grobelny                 if (!redfishGenerationInUse)
216d1bde9e5SKrzysztof Grobelny                 {
217d1bde9e5SKrzysztof Grobelny                     messages::internalError(asyncResp->res);
218d1bde9e5SKrzysztof Grobelny                     return;
219d1bde9e5SKrzysztof Grobelny                 }
220*0ec8b83dSEd Tanous                 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
221d1bde9e5SKrzysztof Grobelny                 {
222d1bde9e5SKrzysztof Grobelny                     asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
223d1bde9e5SKrzysztof Grobelny                         *redfishGenerationInUse;
224d1bde9e5SKrzysztof Grobelny                 }
225a9f68bb5STony Lee             }
226d1bde9e5SKrzysztof Grobelny 
227d1bde9e5SKrzysztof Grobelny             if (manufacturer != nullptr)
228d1bde9e5SKrzysztof Grobelny             {
229d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
230d1bde9e5SKrzysztof Grobelny             }
231d1bde9e5SKrzysztof Grobelny 
232d1bde9e5SKrzysztof Grobelny             if (deviceType != nullptr)
233d1bde9e5SKrzysztof Grobelny             {
234d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["DeviceType"] = *deviceType;
235d1bde9e5SKrzysztof Grobelny             }
236d1bde9e5SKrzysztof Grobelny 
2371476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
2381476687dSEd Tanous                 "#PCIeDevice.v1_4_0.PCIeDevice";
2391476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
2401476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device;
2411476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Device";
2421476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = device;
2431476687dSEd Tanous 
2441476687dSEd Tanous             asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
24545ca1b86SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device +
2461476687dSEd Tanous                 "/PCIeFunctions";
247dede6a98SJason M. Bills         };
248dede6a98SJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
249dede6a98SJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
250d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
251d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
252d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
2537e860f15SJohn Edward Broadbent         });
254dede6a98SJason M. Bills }
255dede6a98SJason M. Bills 
2567e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
2577e860f15SJohn Edward Broadbent {
258dede6a98SJason M. Bills     /**
259dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
260dede6a98SJason M. Bills      */
2617e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2627e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
263ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
264002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
265002d39b4SEd Tanous             [&app](const crow::Request& req,
2667e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26745ca1b86SEd Tanous                    const std::string& device) {
2683ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
269dede6a98SJason M. Bills         {
27045ca1b86SEd Tanous             return;
27145ca1b86SEd Tanous         }
2721476687dSEd Tanous 
2731476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
2741476687dSEd Tanous             "#PCIeFunctionCollection.PCIeFunctionCollection";
2751476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
2761476687dSEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/" + device +
2771476687dSEd Tanous             "/PCIeFunctions";
2781476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
2791476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
2801476687dSEd Tanous             "Collection of PCIe Functions for PCIe Device " + device;
281dede6a98SJason M. Bills 
282b9d36b47SEd Tanous         auto getPCIeDeviceCallback =
28345ca1b86SEd Tanous             [asyncResp, device](
28445ca1b86SEd Tanous                 const boost::system::error_code ec,
28545ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
2867e860f15SJohn Edward Broadbent             if (ec)
2877e860f15SJohn Edward Broadbent             {
2887e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG
289002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
290002d39b4SEd Tanous                     << ": " << ec.message();
29145ca1b86SEd Tanous                 if (ec.value() ==
29245ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
2937e860f15SJohn Edward Broadbent                 {
294002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
295002d39b4SEd Tanous                                                device);
2967e860f15SJohn Edward Broadbent                 }
2977e860f15SJohn Edward Broadbent                 else
2987e860f15SJohn Edward Broadbent                 {
2997e860f15SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
3007e860f15SJohn Edward Broadbent                 }
3017e860f15SJohn Edward Broadbent                 return;
3027e860f15SJohn Edward Broadbent             }
3037e860f15SJohn Edward Broadbent 
3047e860f15SJohn Edward Broadbent             nlohmann::json& pcieFunctionList =
3057e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members"];
3067e860f15SJohn Edward Broadbent             pcieFunctionList = nlohmann::json::array();
3077e860f15SJohn Edward Broadbent             static constexpr const int maxPciFunctionNum = 8;
30845ca1b86SEd Tanous             for (int functionNum = 0; functionNum < maxPciFunctionNum;
30945ca1b86SEd Tanous                  functionNum++)
3107e860f15SJohn Edward Broadbent             {
311b9d36b47SEd Tanous                 // Check if this function exists by looking for a
312b9d36b47SEd Tanous                 // device ID
3137e860f15SJohn Edward Broadbent                 std::string devIDProperty =
314002d39b4SEd Tanous                     "Function" + std::to_string(functionNum) + "DeviceId";
315b9d36b47SEd Tanous                 const std::string* property = nullptr;
316b9d36b47SEd Tanous                 for (const auto& propEntry : pcieDevProperties)
3177e860f15SJohn Edward Broadbent                 {
318b9d36b47SEd Tanous                     if (propEntry.first == devIDProperty)
319b9d36b47SEd Tanous                     {
320002d39b4SEd Tanous                         property = std::get_if<std::string>(&propEntry.second);
321b9d36b47SEd Tanous                     }
322b9d36b47SEd Tanous                 }
323fb0ecc3eSNan Zhou                 if (property == nullptr || property->empty())
324b9d36b47SEd Tanous                 {
325e28ce0e6SNan Zhou                     continue;
326b9d36b47SEd Tanous                 }
3271476687dSEd Tanous                 nlohmann::json::object_t pcieFunction;
3281476687dSEd Tanous                 pcieFunction["@odata.id"] =
3291476687dSEd Tanous                     "/redfish/v1/Systems/system/PCIeDevices/" + device +
3301476687dSEd Tanous                     "/PCIeFunctions/" + std::to_string(functionNum);
3311476687dSEd Tanous                 pcieFunctionList.push_back(std::move(pcieFunction));
3327e860f15SJohn Edward Broadbent             }
333a818d15aSJiaqing Zhao             asyncResp->res.jsonValue["Members@odata.count"] =
3347e860f15SJohn Edward Broadbent                 pcieFunctionList.size();
3357e860f15SJohn Edward Broadbent         };
3367e860f15SJohn Edward Broadbent         std::string escapedPath = std::string(pciePath) + "/" + device;
3377e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(escapedPath);
338d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
339d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
340d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
3417e860f15SJohn Edward Broadbent         });
3427e860f15SJohn Edward Broadbent }
3437e860f15SJohn Edward Broadbent 
3447e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app)
3457e860f15SJohn Edward Broadbent {
3467e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
3477e860f15SJohn Edward Broadbent         app,
3487e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
349ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunction)
350002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
351002d39b4SEd Tanous             [&app](const crow::Request& req,
35245ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
353002d39b4SEd Tanous                    const std::string& device, const std::string& function) {
3543ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
35545ca1b86SEd Tanous         {
35645ca1b86SEd Tanous             return;
35745ca1b86SEd Tanous         }
358168e20c1SEd Tanous         auto getPCIeDeviceCallback =
359168e20c1SEd Tanous             [asyncResp, device, function](
3607e860f15SJohn Edward Broadbent                 const boost::system::error_code ec,
361b9d36b47SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
362dede6a98SJason M. Bills             if (ec)
363dede6a98SJason M. Bills             {
364dede6a98SJason M. Bills                 BMCWEB_LOG_DEBUG
365002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
366002d39b4SEd Tanous                     << ": " << ec.message();
367dede6a98SJason M. Bills                 if (ec.value() ==
368dede6a98SJason M. Bills                     boost::system::linux_error::bad_request_descriptor)
369dede6a98SJason M. Bills                 {
370002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
371002d39b4SEd Tanous                                                device);
372dede6a98SJason M. Bills                 }
373dede6a98SJason M. Bills                 else
374dede6a98SJason M. Bills                 {
375dede6a98SJason M. Bills                     messages::internalError(asyncResp->res);
376dede6a98SJason M. Bills                 }
377dede6a98SJason M. Bills                 return;
378dede6a98SJason M. Bills             }
379dede6a98SJason M. Bills 
3801476687dSEd Tanous             // Check if this function exists by looking for a device
3811476687dSEd Tanous             // ID
382b9d36b47SEd Tanous             std::string functionName = "Function" + function;
383b9d36b47SEd Tanous             std::string devIDProperty = functionName + "DeviceId";
384b9d36b47SEd Tanous 
385b9d36b47SEd Tanous             const std::string* devIdProperty = nullptr;
386b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
387b9d36b47SEd Tanous             {
388b9d36b47SEd Tanous                 if (property.first == devIDProperty)
389b9d36b47SEd Tanous                 {
390002d39b4SEd Tanous                     devIdProperty = std::get_if<std::string>(&property.second);
391b9d36b47SEd Tanous                     continue;
392b9d36b47SEd Tanous                 }
393b9d36b47SEd Tanous             }
394973c1355STony Lee             if (devIdProperty == nullptr || devIdProperty->empty())
395f5c9f8bdSJason M. Bills             {
396002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
397002d39b4SEd Tanous                                            function);
398f5c9f8bdSJason M. Bills                 return;
399f5c9f8bdSJason M. Bills             }
400f5c9f8bdSJason M. Bills 
4011476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
4021476687dSEd Tanous                 "#PCIeFunction.v1_2_0.PCIeFunction";
4031476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
404168e20c1SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device +
4051476687dSEd Tanous                 "/PCIeFunctions/" + function;
4061476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function";
4071476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = function;
408002d39b4SEd Tanous             asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
409002d39b4SEd Tanous             asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
4101476687dSEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/" + device;
411f5c9f8bdSJason M. Bills 
412b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
413f5c9f8bdSJason M. Bills             {
414b9d36b47SEd Tanous                 const std::string* strProperty =
415b9d36b47SEd Tanous                     std::get_if<std::string>(&property.second);
416b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceId")
417f5c9f8bdSJason M. Bills                 {
418b9d36b47SEd Tanous                     asyncResp->res.jsonValue["DeviceId"] = *strProperty;
419f5c9f8bdSJason M. Bills                 }
420b9d36b47SEd Tanous                 if (property.first == functionName + "VendorId")
421f5c9f8bdSJason M. Bills                 {
422b9d36b47SEd Tanous                     asyncResp->res.jsonValue["VendorId"] = *strProperty;
423f5c9f8bdSJason M. Bills                 }
424b9d36b47SEd Tanous                 if (property.first == functionName + "FunctionType")
425f5c9f8bdSJason M. Bills                 {
426002d39b4SEd Tanous                     asyncResp->res.jsonValue["FunctionType"] = *strProperty;
427f5c9f8bdSJason M. Bills                 }
428b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceClass")
429f5c9f8bdSJason M. Bills                 {
430002d39b4SEd Tanous                     asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
431f5c9f8bdSJason M. Bills                 }
432b9d36b47SEd Tanous                 if (property.first == functionName + "ClassCode")
433f5c9f8bdSJason M. Bills                 {
434002d39b4SEd Tanous                     asyncResp->res.jsonValue["ClassCode"] = *strProperty;
435f5c9f8bdSJason M. Bills                 }
436b9d36b47SEd Tanous                 if (property.first == functionName + "RevisionId")
437f5c9f8bdSJason M. Bills                 {
438002d39b4SEd Tanous                     asyncResp->res.jsonValue["RevisionId"] = *strProperty;
439f5c9f8bdSJason M. Bills                 }
440b9d36b47SEd Tanous                 if (property.first == functionName + "SubsystemId")
441b9d36b47SEd Tanous                 {
442002d39b4SEd Tanous                     asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
443b9d36b47SEd Tanous                 }
444002d39b4SEd Tanous                 if (property.first == functionName + "SubsystemVendorId")
445f5c9f8bdSJason M. Bills                 {
446168e20c1SEd Tanous                     asyncResp->res.jsonValue["SubsystemVendorId"] =
447b9d36b47SEd Tanous                         *strProperty;
448b9d36b47SEd Tanous                 }
449f5c9f8bdSJason M. Bills             }
450f5c9f8bdSJason M. Bills         };
451f5c9f8bdSJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
452f5c9f8bdSJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
453d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
454d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
455d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
4567e860f15SJohn Edward Broadbent         });
457f5c9f8bdSJason M. Bills }
458f5c9f8bdSJason M. Bills 
459f5c9f8bdSJason M. Bills } // namespace redfish
460