xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision d5e74b807e54fe85d37f06b1fb4b633ccb058ee3)
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>
28ef4c65b7SEd Tanous #include <boost/url/format.hpp>
29d1bde9e5SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp>
30d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
31f5c9f8bdSJason M. Bills 
32f5c9f8bdSJason M. Bills namespace redfish
33f5c9f8bdSJason M. Bills {
34f5c9f8bdSJason M. Bills 
3589492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
3694c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
3794c3a10bSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
38f5c9f8bdSJason M. Bills 
39543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath(
40543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
41543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
42543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
43543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
44543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
45543f9a75SLakshmi Yadlapati 
46543f9a75SLakshmi Yadlapati {
47543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
48543f9a75SLakshmi Yadlapati     {
49543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
50543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
51543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
52543f9a75SLakshmi Yadlapati         {
53543f9a75SLakshmi Yadlapati             continue;
54543f9a75SLakshmi Yadlapati         }
55543f9a75SLakshmi Yadlapati 
56543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
57543f9a75SLakshmi Yadlapati             pcieDevicePath, {},
58543f9a75SLakshmi Yadlapati             [pcieDevicePath, aResp,
59543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
60543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
61543f9a75SLakshmi Yadlapati             if (ec || object.empty())
62543f9a75SLakshmi Yadlapati             {
63543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
64543f9a75SLakshmi Yadlapati                 messages::internalError(aResp->res);
65543f9a75SLakshmi Yadlapati                 return;
66543f9a75SLakshmi Yadlapati             }
67543f9a75SLakshmi Yadlapati             callback(pcieDevicePath, object.begin()->first);
68543f9a75SLakshmi Yadlapati             });
69543f9a75SLakshmi Yadlapati         return;
70543f9a75SLakshmi Yadlapati     }
71543f9a75SLakshmi Yadlapati 
72543f9a75SLakshmi Yadlapati     BMCWEB_LOG_WARNING << "PCIe Device not found";
73543f9a75SLakshmi Yadlapati     messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId);
74543f9a75SLakshmi Yadlapati }
75543f9a75SLakshmi Yadlapati 
76543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath(
77543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
78543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
79543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
80543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
81543f9a75SLakshmi Yadlapati {
82543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
8394c3a10bSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
84543f9a75SLakshmi Yadlapati         [pcieDeviceId, aResp,
85543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
86543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
87543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
88543f9a75SLakshmi Yadlapati         if (ec)
89543f9a75SLakshmi Yadlapati         {
90543f9a75SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
91543f9a75SLakshmi Yadlapati             messages::internalError(aResp->res);
92543f9a75SLakshmi Yadlapati             return;
93543f9a75SLakshmi Yadlapati         }
94543f9a75SLakshmi Yadlapati         handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback);
95543f9a75SLakshmi Yadlapati         return;
96543f9a75SLakshmi Yadlapati         });
97543f9a75SLakshmi Yadlapati }
98543f9a75SLakshmi Yadlapati 
99b5a76932SEd Tanous static inline void
1008d1b46d7Szhanghch05     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
101adbe192aSJason M. Bills                       const std::string& name)
102f5c9f8bdSJason M. Bills {
1037a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
10438e3d67dSLakshmi Yadlapati         inventoryPath, 0, pcieDeviceInterface,
1057a1dbc48SGeorge Liu         [asyncResp, name](const boost::system::error_code& ec,
106b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
107b9d36b47SEd Tanous                               pcieDevicePaths) {
108f5c9f8bdSJason M. Bills         if (ec)
109f5c9f8bdSJason M. Bills         {
110a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
111f5c9f8bdSJason M. Bills                              << ec.message();
112a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
113f5c9f8bdSJason M. Bills             return;
114f5c9f8bdSJason M. Bills         }
115adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
116f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
117f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
118f5c9f8bdSJason M. Bills         {
1193174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
120f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
121f5c9f8bdSJason M. Bills             {
122f5c9f8bdSJason M. Bills                 continue;
123f5c9f8bdSJason M. Bills             }
124f5c9f8bdSJason M. Bills 
125f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
126f5c9f8bdSJason M. Bills             if (devName.empty())
127f5c9f8bdSJason M. Bills             {
128f5c9f8bdSJason M. Bills                 continue;
129f5c9f8bdSJason M. Bills             }
1301476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
131ef4c65b7SEd Tanous             pcieDevice["@odata.id"] = boost::urls::format(
132ef4c65b7SEd Tanous                 "/redfish/v1/Systems/system/PCIeDevices/{}", devName);
133b2ba3072SPatrick Williams             pcieDeviceList.emplace_back(std::move(pcieDevice));
134f5c9f8bdSJason M. Bills         }
135002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
1367a1dbc48SGeorge Liu         });
137f5c9f8bdSJason M. Bills }
138f5c9f8bdSJason M. Bills 
139b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
140b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
141b38fa2abSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
142b38fa2abSLakshmi Yadlapati     const std::string& systemName)
143b38fa2abSLakshmi Yadlapati {
144b38fa2abSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
145b38fa2abSLakshmi Yadlapati     {
146b38fa2abSLakshmi Yadlapati         return;
147b38fa2abSLakshmi Yadlapati     }
148b38fa2abSLakshmi Yadlapati     if (systemName != "system")
149b38fa2abSLakshmi Yadlapati     {
150b38fa2abSLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
151b38fa2abSLakshmi Yadlapati         return;
152b38fa2abSLakshmi Yadlapati     }
153543f9a75SLakshmi Yadlapati 
154b38fa2abSLakshmi Yadlapati     aResp->res.addHeader(boost::beast::http::field::link,
155b38fa2abSLakshmi Yadlapati                          "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
156b38fa2abSLakshmi Yadlapati                          "PCIeDeviceCollection.json>; rel=describedby");
157b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] =
158b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
159b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.id"] =
160b38fa2abSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices";
161b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device Collection";
162b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
163b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members"] = nlohmann::json::array();
164b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members@odata.count"] = 0;
165b38fa2abSLakshmi Yadlapati 
166b38fa2abSLakshmi Yadlapati     collection_util::getCollectionMembers(
167b38fa2abSLakshmi Yadlapati         aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
16894c3a10bSLakshmi Yadlapati         pcieDeviceInterface);
169b38fa2abSLakshmi Yadlapati }
170b38fa2abSLakshmi Yadlapati 
1717e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
172adbe192aSJason M. Bills {
173adbe192aSJason M. Bills     /**
174adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
175adbe192aSJason M. Bills      */
17622d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
177ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1787e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
179b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
180f5c9f8bdSJason M. Bills }
181f5c9f8bdSJason M. Bills 
1820ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes>
18362cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
18462cd45afSSpencer Ku {
18562cd45afSSpencer Ku     if (generationInUse ==
18662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
18762cd45afSSpencer Ku     {
1880ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen1;
18962cd45afSSpencer Ku     }
19062cd45afSSpencer Ku     if (generationInUse ==
19162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
19262cd45afSSpencer Ku     {
1930ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen2;
19462cd45afSSpencer Ku     }
19562cd45afSSpencer Ku     if (generationInUse ==
19662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
19762cd45afSSpencer Ku     {
1980ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen3;
19962cd45afSSpencer Ku     }
20062cd45afSSpencer Ku     if (generationInUse ==
20162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
20262cd45afSSpencer Ku     {
2030ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen4;
20462cd45afSSpencer Ku     }
20562cd45afSSpencer Ku     if (generationInUse ==
20662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
20762cd45afSSpencer Ku     {
2080ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen5;
20962cd45afSSpencer Ku     }
210e825cbc8SEd Tanous     if (generationInUse.empty() ||
211e825cbc8SEd Tanous         generationInUse ==
21262cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
21362cd45afSSpencer Ku     {
2140ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Invalid;
21562cd45afSSpencer Ku     }
21662cd45afSSpencer Ku 
21762cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
21862cd45afSSpencer Ku     return std::nullopt;
21962cd45afSSpencer Ku }
22062cd45afSSpencer Ku 
221c6bb3285SLakshmi Yadlapati inline void getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
222c6bb3285SLakshmi Yadlapati                                const std::string& pcieDevicePath,
223c6bb3285SLakshmi Yadlapati                                const std::string& service)
224c6bb3285SLakshmi Yadlapati {
225c6bb3285SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
226c6bb3285SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
227c6bb3285SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item", "Present",
228c6bb3285SLakshmi Yadlapati         [aResp](const boost::system::error_code& ec, const bool value) {
229c6bb3285SLakshmi Yadlapati         if (ec)
230c6bb3285SLakshmi Yadlapati         {
231c6bb3285SLakshmi Yadlapati             if (ec.value() != EBADR)
232c6bb3285SLakshmi Yadlapati             {
233c6bb3285SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for State";
234c6bb3285SLakshmi Yadlapati                 messages::internalError(aResp->res);
235c6bb3285SLakshmi Yadlapati             }
236c6bb3285SLakshmi Yadlapati             return;
237c6bb3285SLakshmi Yadlapati         }
238c6bb3285SLakshmi Yadlapati 
239c6bb3285SLakshmi Yadlapati         if (!value)
240c6bb3285SLakshmi Yadlapati         {
241c6bb3285SLakshmi Yadlapati             aResp->res.jsonValue["Status"]["State"] = "Absent";
242c6bb3285SLakshmi Yadlapati         }
243c6bb3285SLakshmi Yadlapati         });
244c6bb3285SLakshmi Yadlapati }
245c6bb3285SLakshmi Yadlapati 
246913e7732SSunnySrivastava1984 inline void getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
247913e7732SSunnySrivastava1984                                const std::string& pcieDevicePath,
248913e7732SSunnySrivastava1984                                const std::string& service)
249913e7732SSunnySrivastava1984 {
250913e7732SSunnySrivastava1984     sdbusplus::asio::getAllProperties(
251913e7732SSunnySrivastava1984         *crow::connections::systemBus, service, pcieDevicePath,
252913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
253913e7732SSunnySrivastava1984         [pcieDevicePath,
254913e7732SSunnySrivastava1984          aResp{aResp}](const boost::system::error_code& ec,
255913e7732SSunnySrivastava1984                        const dbus::utility::DBusPropertiesMap& assetList) {
256913e7732SSunnySrivastava1984         if (ec)
257913e7732SSunnySrivastava1984         {
258913e7732SSunnySrivastava1984             if (ec.value() != EBADR)
259913e7732SSunnySrivastava1984             {
260913e7732SSunnySrivastava1984                 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
261913e7732SSunnySrivastava1984                                  << ec.value();
262913e7732SSunnySrivastava1984                 messages::internalError(aResp->res);
263913e7732SSunnySrivastava1984             }
264913e7732SSunnySrivastava1984             return;
265913e7732SSunnySrivastava1984         }
266913e7732SSunnySrivastava1984 
267913e7732SSunnySrivastava1984         const std::string* manufacturer = nullptr;
268913e7732SSunnySrivastava1984         const std::string* model = nullptr;
269913e7732SSunnySrivastava1984         const std::string* partNumber = nullptr;
270913e7732SSunnySrivastava1984         const std::string* serialNumber = nullptr;
271913e7732SSunnySrivastava1984         const std::string* sparePartNumber = nullptr;
272913e7732SSunnySrivastava1984 
273913e7732SSunnySrivastava1984         const bool success = sdbusplus::unpackPropertiesNoThrow(
274913e7732SSunnySrivastava1984             dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
275913e7732SSunnySrivastava1984             manufacturer, "Model", model, "PartNumber", partNumber,
276913e7732SSunnySrivastava1984             "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
277913e7732SSunnySrivastava1984 
278913e7732SSunnySrivastava1984         if (!success)
279913e7732SSunnySrivastava1984         {
280913e7732SSunnySrivastava1984             messages::internalError(aResp->res);
281913e7732SSunnySrivastava1984             return;
282913e7732SSunnySrivastava1984         }
283913e7732SSunnySrivastava1984 
284913e7732SSunnySrivastava1984         if (manufacturer != nullptr)
285913e7732SSunnySrivastava1984         {
286913e7732SSunnySrivastava1984             aResp->res.jsonValue["Manufacturer"] = *manufacturer;
287913e7732SSunnySrivastava1984         }
288913e7732SSunnySrivastava1984         if (model != nullptr)
289913e7732SSunnySrivastava1984         {
290913e7732SSunnySrivastava1984             aResp->res.jsonValue["Model"] = *model;
291913e7732SSunnySrivastava1984         }
292913e7732SSunnySrivastava1984 
293913e7732SSunnySrivastava1984         if (partNumber != nullptr)
294913e7732SSunnySrivastava1984         {
295913e7732SSunnySrivastava1984             aResp->res.jsonValue["PartNumber"] = *partNumber;
296913e7732SSunnySrivastava1984         }
297913e7732SSunnySrivastava1984 
298913e7732SSunnySrivastava1984         if (serialNumber != nullptr)
299913e7732SSunnySrivastava1984         {
300913e7732SSunnySrivastava1984             aResp->res.jsonValue["SerialNumber"] = *serialNumber;
301913e7732SSunnySrivastava1984         }
302913e7732SSunnySrivastava1984 
303913e7732SSunnySrivastava1984         if (sparePartNumber != nullptr && !sparePartNumber->empty())
304913e7732SSunnySrivastava1984         {
305913e7732SSunnySrivastava1984             aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
306913e7732SSunnySrivastava1984         }
307913e7732SSunnySrivastava1984         });
308913e7732SSunnySrivastava1984 }
309913e7732SSunnySrivastava1984 
310543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
31135ad613dSLakshmi Yadlapati     crow::Response& resp, const std::string& pcieDeviceId,
312543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
313f5c9f8bdSJason M. Bills {
314d1bde9e5SKrzysztof Grobelny     const std::string* deviceType = nullptr;
315d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
316543f9a75SLakshmi Yadlapati     const int64_t* lanesInUse = nullptr;
317d1bde9e5SKrzysztof Grobelny 
318d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
319543f9a75SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
320543f9a75SLakshmi Yadlapati         deviceType, "GenerationInUse", generationInUse, "LanesInUse",
321bad2c4a9SLakshmi Yadlapati         lanesInUse);
322d1bde9e5SKrzysztof Grobelny 
323d1bde9e5SKrzysztof Grobelny     if (!success)
324d1bde9e5SKrzysztof Grobelny     {
325543f9a75SLakshmi Yadlapati         messages::internalError(resp);
326d1bde9e5SKrzysztof Grobelny         return;
327d1bde9e5SKrzysztof Grobelny     }
328d1bde9e5SKrzysztof Grobelny 
329543f9a75SLakshmi Yadlapati     if (deviceType != nullptr && !deviceType->empty())
330703f6741SMyung Bae     {
331543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
332703f6741SMyung Bae     }
333703f6741SMyung Bae 
334d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
335d1bde9e5SKrzysztof Grobelny     {
3360ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
337d1bde9e5SKrzysztof Grobelny             redfishPcieGenerationFromDbus(*generationInUse);
338543f9a75SLakshmi Yadlapati 
339d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
340d1bde9e5SKrzysztof Grobelny         {
341543f9a75SLakshmi Yadlapati             messages::internalError(resp);
342d1bde9e5SKrzysztof Grobelny             return;
343d1bde9e5SKrzysztof Grobelny         }
3440ec8b83dSEd Tanous         if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
345d1bde9e5SKrzysztof Grobelny         {
346543f9a75SLakshmi Yadlapati             resp.jsonValue["PCIeInterface"]["PCIeType"] =
347d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
348d1bde9e5SKrzysztof Grobelny         }
349a9f68bb5STony Lee     }
350d1bde9e5SKrzysztof Grobelny 
351543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
352543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
353543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
354543f9a75SLakshmi Yadlapati     {
355543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
356543f9a75SLakshmi Yadlapati     }
357543f9a75SLakshmi Yadlapati 
358ef4c65b7SEd Tanous     resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format(
359ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
360ef4c65b7SEd Tanous         pcieDeviceId);
361d1bde9e5SKrzysztof Grobelny }
362d1bde9e5SKrzysztof Grobelny 
363543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
364543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
365543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
366543f9a75SLakshmi Yadlapati     const std::function<void(
367543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
368d1bde9e5SKrzysztof Grobelny {
369543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
370543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
371543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
372543f9a75SLakshmi Yadlapati         [aResp,
373543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
374543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
375543f9a75SLakshmi Yadlapati         if (ec)
376543f9a75SLakshmi Yadlapati         {
377543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
378543f9a75SLakshmi Yadlapati             {
379543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
380543f9a75SLakshmi Yadlapati                 messages::internalError(aResp->res);
381543f9a75SLakshmi Yadlapati             }
382543f9a75SLakshmi Yadlapati             return;
383543f9a75SLakshmi Yadlapati         }
384543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
385543f9a75SLakshmi Yadlapati         });
386d1bde9e5SKrzysztof Grobelny }
387d1bde9e5SKrzysztof Grobelny 
388543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
389543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
390543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
391543f9a75SLakshmi Yadlapati {
392543f9a75SLakshmi Yadlapati     aResp->res.addHeader(
393543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
394543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
395543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
396ef4c65b7SEd Tanous     aResp->res.jsonValue["@odata.id"] = boost::urls::format(
397ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
398543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device";
399543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Id"] = pcieDeviceId;
400c6bb3285SLakshmi Yadlapati     aResp->res.jsonValue["Status"]["State"] = "Enabled";
401543f9a75SLakshmi Yadlapati }
4021476687dSEd Tanous 
403543f9a75SLakshmi Yadlapati inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
404543f9a75SLakshmi Yadlapati                                 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
405543f9a75SLakshmi Yadlapati                                 const std::string& systemName,
406543f9a75SLakshmi Yadlapati                                 const std::string& pcieDeviceId)
407543f9a75SLakshmi Yadlapati {
408543f9a75SLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
409543f9a75SLakshmi Yadlapati     {
410543f9a75SLakshmi Yadlapati         return;
411543f9a75SLakshmi Yadlapati     }
412543f9a75SLakshmi Yadlapati     if (systemName != "system")
413543f9a75SLakshmi Yadlapati     {
414543f9a75SLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
415543f9a75SLakshmi Yadlapati         return;
416543f9a75SLakshmi Yadlapati     }
417543f9a75SLakshmi Yadlapati 
418543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
419543f9a75SLakshmi Yadlapati         pcieDeviceId, aResp,
420543f9a75SLakshmi Yadlapati         [aResp, pcieDeviceId](const std::string& pcieDevicePath,
421543f9a75SLakshmi Yadlapati                               const std::string& service) {
422543f9a75SLakshmi Yadlapati         addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
423913e7732SSunnySrivastava1984         getPCIeDeviceAsset(aResp, pcieDevicePath, service);
424c6bb3285SLakshmi Yadlapati         getPCIeDeviceState(aResp, pcieDevicePath, service);
425543f9a75SLakshmi Yadlapati         getPCIeDeviceProperties(
426543f9a75SLakshmi Yadlapati             aResp, pcieDevicePath, service,
42735ad613dSLakshmi Yadlapati             [aResp, pcieDeviceId](
42835ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
42935ad613dSLakshmi Yadlapati             addPCIeDeviceProperties(aResp->res, pcieDeviceId,
43035ad613dSLakshmi Yadlapati                                     pcieDevProperties);
4317e860f15SJohn Edward Broadbent             });
432543f9a75SLakshmi Yadlapati         });
433543f9a75SLakshmi Yadlapati }
434543f9a75SLakshmi Yadlapati 
435543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
436543f9a75SLakshmi Yadlapati {
437543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
438543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
439543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
440543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
441dede6a98SJason M. Bills }
442dede6a98SJason M. Bills 
44335ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
44435ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
44535ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
44635ad613dSLakshmi Yadlapati {
44735ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
44835ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
44935ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
45035ad613dSLakshmi Yadlapati 
45135ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
45235ad613dSLakshmi Yadlapati     {
45335ad613dSLakshmi Yadlapati         // Check if this function exists by
45435ad613dSLakshmi Yadlapati         // looking for a device ID
45589492a15SPatrick Williams         std::string devIDProperty = "Function" + std::to_string(functionNum) +
45689492a15SPatrick Williams                                     "DeviceId";
45735ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
45835ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
45935ad613dSLakshmi Yadlapati         {
46035ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
46135ad613dSLakshmi Yadlapati             {
46235ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
46335ad613dSLakshmi Yadlapati                 break;
46435ad613dSLakshmi Yadlapati             }
46535ad613dSLakshmi Yadlapati         }
46635ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
46735ad613dSLakshmi Yadlapati         {
46835ad613dSLakshmi Yadlapati             continue;
46935ad613dSLakshmi Yadlapati         }
47035ad613dSLakshmi Yadlapati 
47135ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
472ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
473ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
474ef4c65b7SEd Tanous             pcieDeviceId, std::to_string(functionNum));
475b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
47635ad613dSLakshmi Yadlapati     }
47735ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
47835ad613dSLakshmi Yadlapati }
47935ad613dSLakshmi Yadlapati 
48035ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
48135ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
48235ad613dSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
48335ad613dSLakshmi Yadlapati     const std::string& pcieDeviceId)
48435ad613dSLakshmi Yadlapati {
48535ad613dSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
48635ad613dSLakshmi Yadlapati     {
48735ad613dSLakshmi Yadlapati         return;
48835ad613dSLakshmi Yadlapati     }
48935ad613dSLakshmi Yadlapati 
49035ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
49135ad613dSLakshmi Yadlapati         pcieDeviceId, aResp,
49235ad613dSLakshmi Yadlapati         [aResp, pcieDeviceId](const std::string& pcieDevicePath,
49335ad613dSLakshmi Yadlapati                               const std::string& service) {
49435ad613dSLakshmi Yadlapati         aResp->res.addHeader(
49535ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
49635ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
49735ad613dSLakshmi Yadlapati         aResp->res.jsonValue["@odata.type"] =
49835ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
499ef4c65b7SEd Tanous         aResp->res.jsonValue["@odata.id"] = boost::urls::format(
500ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
501ef4c65b7SEd Tanous             pcieDeviceId);
50235ad613dSLakshmi Yadlapati         aResp->res.jsonValue["Name"] = "PCIe Function Collection";
50335ad613dSLakshmi Yadlapati         aResp->res.jsonValue["Description"] =
50435ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
50535ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
50635ad613dSLakshmi Yadlapati             aResp, pcieDevicePath, service,
50735ad613dSLakshmi Yadlapati             [aResp, pcieDeviceId](
50835ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
50935ad613dSLakshmi Yadlapati             addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
51035ad613dSLakshmi Yadlapati             });
51135ad613dSLakshmi Yadlapati         });
51235ad613dSLakshmi Yadlapati }
51335ad613dSLakshmi Yadlapati 
5147e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
5157e860f15SJohn Edward Broadbent {
516dede6a98SJason M. Bills     /**
517dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
518dede6a98SJason M. Bills      */
5197e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
5207e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
521ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
522002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
52335ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
5247e860f15SJohn Edward Broadbent }
5257e860f15SJohn Edward Broadbent 
526727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
527*d5e74b80SMyung Bae     uint64_t pcieFunctionId,
528727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
5297e860f15SJohn Edward Broadbent {
530*d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
531b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
532b9d36b47SEd Tanous 
533b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
534b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
535b9d36b47SEd Tanous     {
536b9d36b47SEd Tanous         if (property.first == devIDProperty)
537b9d36b47SEd Tanous         {
538002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
539727a046cSLakshmi Yadlapati             break;
540b9d36b47SEd Tanous         }
541b9d36b47SEd Tanous     }
542727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
543727a046cSLakshmi Yadlapati }
544727a046cSLakshmi Yadlapati 
545727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
546e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
547727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
548f5c9f8bdSJason M. Bills {
549e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
550b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
551f5c9f8bdSJason M. Bills     {
552b9d36b47SEd Tanous         const std::string* strProperty =
553b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
554727a046cSLakshmi Yadlapati 
555b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
556f5c9f8bdSJason M. Bills         {
557727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
558f5c9f8bdSJason M. Bills         }
559b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
560f5c9f8bdSJason M. Bills         {
561727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
562f5c9f8bdSJason M. Bills         }
563727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
564727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
565727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
566b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
567f5c9f8bdSJason M. Bills         {
568727a046cSLakshmi Yadlapati             if (!strProperty->empty())
569727a046cSLakshmi Yadlapati             {
570727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
571727a046cSLakshmi Yadlapati             }
572f5c9f8bdSJason M. Bills         }
573b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
574f5c9f8bdSJason M. Bills         {
575727a046cSLakshmi Yadlapati             if (!strProperty->empty())
576727a046cSLakshmi Yadlapati             {
577727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
578727a046cSLakshmi Yadlapati             }
579f5c9f8bdSJason M. Bills         }
580b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
581f5c9f8bdSJason M. Bills         {
582727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
583f5c9f8bdSJason M. Bills         }
584b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
585f5c9f8bdSJason M. Bills         {
586727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
587f5c9f8bdSJason M. Bills         }
588b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
589b9d36b47SEd Tanous         {
590727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
591b9d36b47SEd Tanous         }
592002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
593f5c9f8bdSJason M. Bills         {
594727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
595b9d36b47SEd Tanous         }
596f5c9f8bdSJason M. Bills     }
597727a046cSLakshmi Yadlapati }
598727a046cSLakshmi Yadlapati 
599727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
600727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
601e14742caSEd Tanous                                             uint64_t pcieFunctionId)
602727a046cSLakshmi Yadlapati {
603727a046cSLakshmi Yadlapati     resp.addHeader(
604727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
605727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
606727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
607ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
608ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
609ef4c65b7SEd Tanous         pcieDeviceId, pcieFunctionId);
610727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
611e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
612e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
613ef4c65b7SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
614ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
615727a046cSLakshmi Yadlapati }
616727a046cSLakshmi Yadlapati 
617727a046cSLakshmi Yadlapati inline void
618727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
619727a046cSLakshmi Yadlapati                           const std::shared_ptr<bmcweb::AsyncResp>& aResp,
620727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
621e14742caSEd Tanous                           const std::string& pcieFunctionIdStr)
622727a046cSLakshmi Yadlapati {
623727a046cSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
624727a046cSLakshmi Yadlapati     {
625727a046cSLakshmi Yadlapati         return;
626727a046cSLakshmi Yadlapati     }
627e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
628e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
629e14742caSEd Tanous         &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
630e14742caSEd Tanous     if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
631e14742caSEd Tanous     {
632e14742caSEd Tanous         messages::resourceNotFound(aResp->res, "PCIeFunction",
633e14742caSEd Tanous                                    pcieFunctionIdStr);
634e14742caSEd Tanous         return;
635e14742caSEd Tanous     }
636727a046cSLakshmi Yadlapati 
637727a046cSLakshmi Yadlapati     getValidPCIeDevicePath(
638727a046cSLakshmi Yadlapati         pcieDeviceId, aResp,
639727a046cSLakshmi Yadlapati         [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath,
640727a046cSLakshmi Yadlapati                                               const std::string& service) {
641727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
642727a046cSLakshmi Yadlapati             aResp, pcieDevicePath, service,
643727a046cSLakshmi Yadlapati             [aResp, pcieDeviceId, pcieFunctionId](
644727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
645*d5e74b80SMyung Bae             if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties))
646*d5e74b80SMyung Bae             {
647*d5e74b80SMyung Bae                 messages::resourceNotFound(aResp->res, "PCIeFunction",
648*d5e74b80SMyung Bae                                            std::to_string(pcieFunctionId));
649*d5e74b80SMyung Bae                 return;
650*d5e74b80SMyung Bae             }
651727a046cSLakshmi Yadlapati             addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId,
652727a046cSLakshmi Yadlapati                                             pcieFunctionId);
653727a046cSLakshmi Yadlapati             addPCIeFunctionProperties(aResp->res, pcieFunctionId,
654727a046cSLakshmi Yadlapati                                       pcieDevProperties);
6557e860f15SJohn Edward Broadbent             });
656727a046cSLakshmi Yadlapati         });
657727a046cSLakshmi Yadlapati }
658727a046cSLakshmi Yadlapati 
659727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
660727a046cSLakshmi Yadlapati {
661727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
662727a046cSLakshmi Yadlapati         app,
663727a046cSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
664727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
665727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
666727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
667f5c9f8bdSJason M. Bills }
668f5c9f8bdSJason M. Bills 
669f5c9f8bdSJason M. Bills } // namespace redfish
670