xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision b8f38ead9e5d89aa636f2340f1103b40393053b8)
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"
24b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp"
253ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
260ec8b83dSEd Tanous 
27f5c9f8bdSJason M. Bills #include <boost/system/linux_error.hpp>
28d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
30f5c9f8bdSJason M. Bills 
31f5c9f8bdSJason M. Bills namespace redfish
32f5c9f8bdSJason M. Bills {
33f5c9f8bdSJason M. Bills 
34f5c9f8bdSJason M. Bills static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
35f5c9f8bdSJason M. Bills static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
36f5c9f8bdSJason M. Bills static constexpr char const* pcieDeviceInterface =
37*b8f38eadSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice";
38f5c9f8bdSJason M. Bills 
39b5a76932SEd Tanous static inline void
408d1b46d7Szhanghch05     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
41adbe192aSJason M. Bills                       const std::string& name)
42f5c9f8bdSJason M. Bills {
437a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
447a1dbc48SGeorge Liu         pciePath, 1, {},
457a1dbc48SGeorge Liu         [asyncResp, name](const boost::system::error_code& ec,
46b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
47b9d36b47SEd Tanous                               pcieDevicePaths) {
48f5c9f8bdSJason M. Bills         if (ec)
49f5c9f8bdSJason M. Bills         {
50a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
51f5c9f8bdSJason M. Bills                              << ec.message();
52a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
53f5c9f8bdSJason M. Bills             return;
54f5c9f8bdSJason M. Bills         }
55adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
56f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
57f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
58f5c9f8bdSJason M. Bills         {
593174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
60f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
61f5c9f8bdSJason M. Bills             {
62f5c9f8bdSJason M. Bills                 continue;
63f5c9f8bdSJason M. Bills             }
64f5c9f8bdSJason M. Bills 
65f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
66f5c9f8bdSJason M. Bills             if (devName.empty())
67f5c9f8bdSJason M. Bills             {
68f5c9f8bdSJason M. Bills                 continue;
69f5c9f8bdSJason M. Bills             }
701476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
71eddfc437SWilly Tu             pcieDevice["@odata.id"] = crow::utility::urlFromPieces(
72eddfc437SWilly Tu                 "redfish", "v1", "Systems", "system", "PCIeDevices", devName);
731476687dSEd Tanous             pcieDeviceList.push_back(std::move(pcieDevice));
74f5c9f8bdSJason M. Bills         }
75002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
767a1dbc48SGeorge Liu         });
77f5c9f8bdSJason M. Bills }
78f5c9f8bdSJason M. Bills 
79b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
80b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
81b38fa2abSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
82b38fa2abSLakshmi Yadlapati     const std::string& systemName)
83b38fa2abSLakshmi Yadlapati {
84b38fa2abSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
85b38fa2abSLakshmi Yadlapati     {
86b38fa2abSLakshmi Yadlapati         return;
87b38fa2abSLakshmi Yadlapati     }
88b38fa2abSLakshmi Yadlapati     if (systemName != "system")
89b38fa2abSLakshmi Yadlapati     {
90b38fa2abSLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
91b38fa2abSLakshmi Yadlapati         return;
92b38fa2abSLakshmi Yadlapati     }
93b38fa2abSLakshmi Yadlapati     aResp->res.addHeader(boost::beast::http::field::link,
94b38fa2abSLakshmi Yadlapati                          "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
95b38fa2abSLakshmi Yadlapati                          "PCIeDeviceCollection.json>; rel=describedby");
96b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] =
97b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
98b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.id"] =
99b38fa2abSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices";
100b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device Collection";
101b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
102b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members"] = nlohmann::json::array();
103b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members@odata.count"] = 0;
104b38fa2abSLakshmi Yadlapati 
105b38fa2abSLakshmi Yadlapati     constexpr std::array<std::string_view, 1> interfaces{
106b38fa2abSLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
107b38fa2abSLakshmi Yadlapati     collection_util::getCollectionMembers(
108b38fa2abSLakshmi Yadlapati         aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
109b38fa2abSLakshmi Yadlapati         interfaces);
110b38fa2abSLakshmi Yadlapati }
111b38fa2abSLakshmi Yadlapati 
1127e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
113adbe192aSJason M. Bills {
114adbe192aSJason M. Bills     /**
115adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
116adbe192aSJason M. Bills      */
11722d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
118ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1197e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
120b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
121f5c9f8bdSJason M. Bills }
122f5c9f8bdSJason M. Bills 
1230ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes>
12462cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
12562cd45afSSpencer Ku {
12662cd45afSSpencer Ku     if (generationInUse ==
12762cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
12862cd45afSSpencer Ku     {
1290ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen1;
13062cd45afSSpencer Ku     }
13162cd45afSSpencer Ku     if (generationInUse ==
13262cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
13362cd45afSSpencer Ku     {
1340ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen2;
13562cd45afSSpencer Ku     }
13662cd45afSSpencer Ku     if (generationInUse ==
13762cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
13862cd45afSSpencer Ku     {
1390ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen3;
14062cd45afSSpencer Ku     }
14162cd45afSSpencer Ku     if (generationInUse ==
14262cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
14362cd45afSSpencer Ku     {
1440ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen4;
14562cd45afSSpencer Ku     }
14662cd45afSSpencer Ku     if (generationInUse ==
14762cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
14862cd45afSSpencer Ku     {
1490ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen5;
15062cd45afSSpencer Ku     }
151e825cbc8SEd Tanous     if (generationInUse.empty() ||
152e825cbc8SEd Tanous         generationInUse ==
15362cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
15462cd45afSSpencer Ku     {
1550ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Invalid;
15662cd45afSSpencer Ku     }
15762cd45afSSpencer Ku 
15862cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
15962cd45afSSpencer Ku     return std::nullopt;
16062cd45afSSpencer Ku }
16162cd45afSSpencer Ku 
1627e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDevice(App& app)
163f5c9f8bdSJason M. Bills {
16422d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
165ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDevice)
166002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
167002d39b4SEd Tanous             [&app](const crow::Request& req,
1687e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16922d268cbSEd Tanous                    const std::string& systemName, const std::string& device) {
1703ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1717e860f15SJohn Edward Broadbent         {
17245ca1b86SEd Tanous             return;
17345ca1b86SEd Tanous         }
17422d268cbSEd Tanous         if (systemName != "system")
17522d268cbSEd Tanous         {
17622d268cbSEd Tanous             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
17722d268cbSEd Tanous                                        systemName);
17822d268cbSEd Tanous             return;
17922d268cbSEd Tanous         }
18022d268cbSEd Tanous 
181168e20c1SEd Tanous         auto getPCIeDeviceCallback =
18245ca1b86SEd Tanous             [asyncResp, device](
1835e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
18445ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
185f5c9f8bdSJason M. Bills             if (ec)
186f5c9f8bdSJason M. Bills             {
187f5c9f8bdSJason M. Bills                 BMCWEB_LOG_DEBUG
188002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
189002d39b4SEd Tanous                     << ": " << ec.message();
19045ca1b86SEd Tanous                 if (ec.value() ==
19145ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
192f5c9f8bdSJason M. Bills                 {
193002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
194002d39b4SEd Tanous                                                device);
195f5c9f8bdSJason M. Bills                 }
196f5c9f8bdSJason M. Bills                 else
197f5c9f8bdSJason M. Bills                 {
198f5c9f8bdSJason M. Bills                     messages::internalError(asyncResp->res);
199f5c9f8bdSJason M. Bills                 }
200f5c9f8bdSJason M. Bills                 return;
201f5c9f8bdSJason M. Bills             }
202f5c9f8bdSJason M. Bills 
203d1bde9e5SKrzysztof Grobelny             const std::string* manufacturer = nullptr;
204d1bde9e5SKrzysztof Grobelny             const std::string* deviceType = nullptr;
205d1bde9e5SKrzysztof Grobelny             const std::string* generationInUse = nullptr;
206703f6741SMyung Bae             const size_t* lanesInUse = nullptr;
207d1bde9e5SKrzysztof Grobelny 
208d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
209d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), pcieDevProperties,
210d1bde9e5SKrzysztof Grobelny                 "Manufacturer", manufacturer, "DeviceType", deviceType,
211703f6741SMyung Bae                 "LanesInUse", lanesInUse, "GenerationInUse", generationInUse);
212d1bde9e5SKrzysztof Grobelny 
213d1bde9e5SKrzysztof Grobelny             if (!success)
214d1bde9e5SKrzysztof Grobelny             {
215d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
216d1bde9e5SKrzysztof Grobelny                 return;
217d1bde9e5SKrzysztof Grobelny             }
218d1bde9e5SKrzysztof Grobelny 
219703f6741SMyung Bae             // The default value of LanesInUse is 0, and the field will be
220703f6741SMyung Bae             // left as off if it is a default value.
221703f6741SMyung Bae             if (lanesInUse != nullptr && *lanesInUse != 0)
222703f6741SMyung Bae             {
223703f6741SMyung Bae                 asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] =
224703f6741SMyung Bae                     *lanesInUse;
225703f6741SMyung Bae             }
226703f6741SMyung Bae 
227d1bde9e5SKrzysztof Grobelny             if (generationInUse != nullptr)
228d1bde9e5SKrzysztof Grobelny             {
2290ec8b83dSEd Tanous                 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
230d1bde9e5SKrzysztof Grobelny                     redfishPcieGenerationFromDbus(*generationInUse);
231d1bde9e5SKrzysztof Grobelny                 if (!redfishGenerationInUse)
232d1bde9e5SKrzysztof Grobelny                 {
233d1bde9e5SKrzysztof Grobelny                     messages::internalError(asyncResp->res);
234d1bde9e5SKrzysztof Grobelny                     return;
235d1bde9e5SKrzysztof Grobelny                 }
2360ec8b83dSEd Tanous                 if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
237d1bde9e5SKrzysztof Grobelny                 {
238d1bde9e5SKrzysztof Grobelny                     asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
239d1bde9e5SKrzysztof Grobelny                         *redfishGenerationInUse;
240d1bde9e5SKrzysztof Grobelny                 }
241a9f68bb5STony Lee             }
242d1bde9e5SKrzysztof Grobelny 
243d1bde9e5SKrzysztof Grobelny             if (manufacturer != nullptr)
244d1bde9e5SKrzysztof Grobelny             {
245d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
246d1bde9e5SKrzysztof Grobelny             }
247d1bde9e5SKrzysztof Grobelny 
248d1bde9e5SKrzysztof Grobelny             if (deviceType != nullptr)
249d1bde9e5SKrzysztof Grobelny             {
250d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["DeviceType"] = *deviceType;
251d1bde9e5SKrzysztof Grobelny             }
252d1bde9e5SKrzysztof Grobelny 
2531476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
2541476687dSEd Tanous                 "#PCIeDevice.v1_4_0.PCIeDevice";
2551476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
256eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
257eddfc437SWilly Tu                                              "system", "PCIeDevices", device);
2581476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Device";
2591476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = device;
2601476687dSEd Tanous 
2611476687dSEd Tanous             asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
262eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
263eddfc437SWilly Tu                                              "system", "PCIeDevices", device,
264eddfc437SWilly Tu                                              "PCIeFunctions");
265dede6a98SJason M. Bills         };
266dede6a98SJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
267dede6a98SJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
268d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
269d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
270d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
2717e860f15SJohn Edward Broadbent         });
272dede6a98SJason M. Bills }
273dede6a98SJason M. Bills 
2747e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
2757e860f15SJohn Edward Broadbent {
276dede6a98SJason M. Bills     /**
277dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
278dede6a98SJason M. Bills      */
2797e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2807e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
281ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
282002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
283002d39b4SEd Tanous             [&app](const crow::Request& req,
2847e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
28545ca1b86SEd Tanous                    const std::string& device) {
2863ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
287dede6a98SJason M. Bills         {
28845ca1b86SEd Tanous             return;
28945ca1b86SEd Tanous         }
2901476687dSEd Tanous 
2911476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
2921476687dSEd Tanous             "#PCIeFunctionCollection.PCIeFunctionCollection";
293eddfc437SWilly Tu         asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
294eddfc437SWilly Tu             "redfish", "v1", "Systems", "system", "PCIeDevices", device,
295eddfc437SWilly Tu             "PCIeFunctions");
2961476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
2971476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
2981476687dSEd Tanous             "Collection of PCIe Functions for PCIe Device " + device;
299dede6a98SJason M. Bills 
300b9d36b47SEd Tanous         auto getPCIeDeviceCallback =
30145ca1b86SEd Tanous             [asyncResp, device](
3025e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
30345ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
3047e860f15SJohn Edward Broadbent             if (ec)
3057e860f15SJohn Edward Broadbent             {
3067e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG
307002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
308002d39b4SEd Tanous                     << ": " << ec.message();
30945ca1b86SEd Tanous                 if (ec.value() ==
31045ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
3117e860f15SJohn Edward Broadbent                 {
312002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
313002d39b4SEd Tanous                                                device);
3147e860f15SJohn Edward Broadbent                 }
3157e860f15SJohn Edward Broadbent                 else
3167e860f15SJohn Edward Broadbent                 {
3177e860f15SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
3187e860f15SJohn Edward Broadbent                 }
3197e860f15SJohn Edward Broadbent                 return;
3207e860f15SJohn Edward Broadbent             }
3217e860f15SJohn Edward Broadbent 
3227e860f15SJohn Edward Broadbent             nlohmann::json& pcieFunctionList =
3237e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members"];
3247e860f15SJohn Edward Broadbent             pcieFunctionList = nlohmann::json::array();
3257e860f15SJohn Edward Broadbent             static constexpr const int maxPciFunctionNum = 8;
32645ca1b86SEd Tanous             for (int functionNum = 0; functionNum < maxPciFunctionNum;
32745ca1b86SEd Tanous                  functionNum++)
3287e860f15SJohn Edward Broadbent             {
329b9d36b47SEd Tanous                 // Check if this function exists by looking for a
330b9d36b47SEd Tanous                 // device ID
3317e860f15SJohn Edward Broadbent                 std::string devIDProperty =
332002d39b4SEd Tanous                     "Function" + std::to_string(functionNum) + "DeviceId";
333b9d36b47SEd Tanous                 const std::string* property = nullptr;
334b9d36b47SEd Tanous                 for (const auto& propEntry : pcieDevProperties)
3357e860f15SJohn Edward Broadbent                 {
336b9d36b47SEd Tanous                     if (propEntry.first == devIDProperty)
337b9d36b47SEd Tanous                     {
338002d39b4SEd Tanous                         property = std::get_if<std::string>(&propEntry.second);
339b9d36b47SEd Tanous                     }
340b9d36b47SEd Tanous                 }
341fb0ecc3eSNan Zhou                 if (property == nullptr || property->empty())
342b9d36b47SEd Tanous                 {
343e28ce0e6SNan Zhou                     continue;
344b9d36b47SEd Tanous                 }
3451476687dSEd Tanous                 nlohmann::json::object_t pcieFunction;
346eddfc437SWilly Tu                 pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
347eddfc437SWilly Tu                     "redfish", "v1", "Systems", "system", "PCIeDevices", device,
348eddfc437SWilly Tu                     "PCIeFunctions", std::to_string(functionNum));
3491476687dSEd Tanous                 pcieFunctionList.push_back(std::move(pcieFunction));
3507e860f15SJohn Edward Broadbent             }
351a818d15aSJiaqing Zhao             asyncResp->res.jsonValue["Members@odata.count"] =
3527e860f15SJohn Edward Broadbent                 pcieFunctionList.size();
3537e860f15SJohn Edward Broadbent         };
3547e860f15SJohn Edward Broadbent         std::string escapedPath = std::string(pciePath) + "/" + device;
3557e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(escapedPath);
356d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
357d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
358d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
3597e860f15SJohn Edward Broadbent         });
3607e860f15SJohn Edward Broadbent }
3617e860f15SJohn Edward Broadbent 
3627e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app)
3637e860f15SJohn Edward Broadbent {
3647e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
3657e860f15SJohn Edward Broadbent         app,
3667e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
367ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunction)
368002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
369002d39b4SEd Tanous             [&app](const crow::Request& req,
37045ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
371002d39b4SEd Tanous                    const std::string& device, const std::string& function) {
3723ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
37345ca1b86SEd Tanous         {
37445ca1b86SEd Tanous             return;
37545ca1b86SEd Tanous         }
376168e20c1SEd Tanous         auto getPCIeDeviceCallback =
377168e20c1SEd Tanous             [asyncResp, device, function](
3785e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
379b9d36b47SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
380dede6a98SJason M. Bills             if (ec)
381dede6a98SJason M. Bills             {
382dede6a98SJason M. Bills                 BMCWEB_LOG_DEBUG
383002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
384002d39b4SEd Tanous                     << ": " << ec.message();
385dede6a98SJason M. Bills                 if (ec.value() ==
386dede6a98SJason M. Bills                     boost::system::linux_error::bad_request_descriptor)
387dede6a98SJason M. Bills                 {
388002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
389002d39b4SEd Tanous                                                device);
390dede6a98SJason M. Bills                 }
391dede6a98SJason M. Bills                 else
392dede6a98SJason M. Bills                 {
393dede6a98SJason M. Bills                     messages::internalError(asyncResp->res);
394dede6a98SJason M. Bills                 }
395dede6a98SJason M. Bills                 return;
396dede6a98SJason M. Bills             }
397dede6a98SJason M. Bills 
3981476687dSEd Tanous             // Check if this function exists by looking for a device
3991476687dSEd Tanous             // ID
400b9d36b47SEd Tanous             std::string functionName = "Function" + function;
401b9d36b47SEd Tanous             std::string devIDProperty = functionName + "DeviceId";
402b9d36b47SEd Tanous 
403b9d36b47SEd Tanous             const std::string* devIdProperty = nullptr;
404b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
405b9d36b47SEd Tanous             {
406b9d36b47SEd Tanous                 if (property.first == devIDProperty)
407b9d36b47SEd Tanous                 {
408002d39b4SEd Tanous                     devIdProperty = std::get_if<std::string>(&property.second);
409b9d36b47SEd Tanous                     continue;
410b9d36b47SEd Tanous                 }
411b9d36b47SEd Tanous             }
412973c1355STony Lee             if (devIdProperty == nullptr || devIdProperty->empty())
413f5c9f8bdSJason M. Bills             {
414002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
415002d39b4SEd Tanous                                            function);
416f5c9f8bdSJason M. Bills                 return;
417f5c9f8bdSJason M. Bills             }
418f5c9f8bdSJason M. Bills 
4191476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
4201476687dSEd Tanous                 "#PCIeFunction.v1_2_0.PCIeFunction";
4211476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
422eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
423eddfc437SWilly Tu                                              "system", "PCIeDevices", device,
424eddfc437SWilly Tu                                              "PCIeFunctions", function);
4251476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function";
4261476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = function;
427002d39b4SEd Tanous             asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
428002d39b4SEd Tanous             asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
429eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
430eddfc437SWilly Tu                                              "system", "PCIeDevices", device);
431f5c9f8bdSJason M. Bills 
432b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
433f5c9f8bdSJason M. Bills             {
434b9d36b47SEd Tanous                 const std::string* strProperty =
435b9d36b47SEd Tanous                     std::get_if<std::string>(&property.second);
436b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceId")
437f5c9f8bdSJason M. Bills                 {
438b9d36b47SEd Tanous                     asyncResp->res.jsonValue["DeviceId"] = *strProperty;
439f5c9f8bdSJason M. Bills                 }
440b9d36b47SEd Tanous                 if (property.first == functionName + "VendorId")
441f5c9f8bdSJason M. Bills                 {
442b9d36b47SEd Tanous                     asyncResp->res.jsonValue["VendorId"] = *strProperty;
443f5c9f8bdSJason M. Bills                 }
444b9d36b47SEd Tanous                 if (property.first == functionName + "FunctionType")
445f5c9f8bdSJason M. Bills                 {
446002d39b4SEd Tanous                     asyncResp->res.jsonValue["FunctionType"] = *strProperty;
447f5c9f8bdSJason M. Bills                 }
448b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceClass")
449f5c9f8bdSJason M. Bills                 {
450002d39b4SEd Tanous                     asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
451f5c9f8bdSJason M. Bills                 }
452b9d36b47SEd Tanous                 if (property.first == functionName + "ClassCode")
453f5c9f8bdSJason M. Bills                 {
454002d39b4SEd Tanous                     asyncResp->res.jsonValue["ClassCode"] = *strProperty;
455f5c9f8bdSJason M. Bills                 }
456b9d36b47SEd Tanous                 if (property.first == functionName + "RevisionId")
457f5c9f8bdSJason M. Bills                 {
458002d39b4SEd Tanous                     asyncResp->res.jsonValue["RevisionId"] = *strProperty;
459f5c9f8bdSJason M. Bills                 }
460b9d36b47SEd Tanous                 if (property.first == functionName + "SubsystemId")
461b9d36b47SEd Tanous                 {
462002d39b4SEd Tanous                     asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
463b9d36b47SEd Tanous                 }
464002d39b4SEd Tanous                 if (property.first == functionName + "SubsystemVendorId")
465f5c9f8bdSJason M. Bills                 {
466168e20c1SEd Tanous                     asyncResp->res.jsonValue["SubsystemVendorId"] =
467b9d36b47SEd Tanous                         *strProperty;
468b9d36b47SEd Tanous                 }
469f5c9f8bdSJason M. Bills             }
470f5c9f8bdSJason M. Bills         };
471f5c9f8bdSJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
472f5c9f8bdSJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
473d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
474d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
475d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
4767e860f15SJohn Edward Broadbent         });
477f5c9f8bdSJason M. Bills }
478f5c9f8bdSJason M. Bills 
479f5c9f8bdSJason M. Bills } // namespace redfish
480