xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 543f9a75a0819ca9e3541b2c48fe8b4d5cf6c4f7)
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 =
37b8f38eadSLakshmi Yadlapati     "xyz.openbmc_project.Inventory.Item.PCIeDevice";
38f5c9f8bdSJason M. Bills 
39*543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath(
40*543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
41*543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
42*543f9a75SLakshmi Yadlapati     const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
43*543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
44*543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
45*543f9a75SLakshmi Yadlapati 
46*543f9a75SLakshmi Yadlapati {
47*543f9a75SLakshmi Yadlapati     for (const std::string& pcieDevicePath : pcieDevicePaths)
48*543f9a75SLakshmi Yadlapati     {
49*543f9a75SLakshmi Yadlapati         std::string pciecDeviceName =
50*543f9a75SLakshmi Yadlapati             sdbusplus::message::object_path(pcieDevicePath).filename();
51*543f9a75SLakshmi Yadlapati         if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
52*543f9a75SLakshmi Yadlapati         {
53*543f9a75SLakshmi Yadlapati             continue;
54*543f9a75SLakshmi Yadlapati         }
55*543f9a75SLakshmi Yadlapati 
56*543f9a75SLakshmi Yadlapati         dbus::utility::getDbusObject(
57*543f9a75SLakshmi Yadlapati             pcieDevicePath, {},
58*543f9a75SLakshmi Yadlapati             [pcieDevicePath, aResp,
59*543f9a75SLakshmi Yadlapati              callback](const boost::system::error_code& ec,
60*543f9a75SLakshmi Yadlapati                        const dbus::utility::MapperGetObject& object) {
61*543f9a75SLakshmi Yadlapati             if (ec || object.empty())
62*543f9a75SLakshmi Yadlapati             {
63*543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
64*543f9a75SLakshmi Yadlapati                 messages::internalError(aResp->res);
65*543f9a75SLakshmi Yadlapati                 return;
66*543f9a75SLakshmi Yadlapati             }
67*543f9a75SLakshmi Yadlapati             callback(pcieDevicePath, object.begin()->first);
68*543f9a75SLakshmi Yadlapati             });
69*543f9a75SLakshmi Yadlapati         return;
70*543f9a75SLakshmi Yadlapati     }
71*543f9a75SLakshmi Yadlapati 
72*543f9a75SLakshmi Yadlapati     BMCWEB_LOG_WARNING << "PCIe Device not found";
73*543f9a75SLakshmi Yadlapati     messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId);
74*543f9a75SLakshmi Yadlapati }
75*543f9a75SLakshmi Yadlapati 
76*543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath(
77*543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
78*543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
79*543f9a75SLakshmi Yadlapati     const std::function<void(const std::string& pcieDevicePath,
80*543f9a75SLakshmi Yadlapati                              const std::string& service)>& callback)
81*543f9a75SLakshmi Yadlapati {
82*543f9a75SLakshmi Yadlapati     constexpr std::array<std::string_view, 1> interfaces{
83*543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
84*543f9a75SLakshmi Yadlapati 
85*543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
86*543f9a75SLakshmi Yadlapati         "/xyz/openbmc_project/inventory", 0, interfaces,
87*543f9a75SLakshmi Yadlapati         [pcieDeviceId, aResp,
88*543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
89*543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
90*543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
91*543f9a75SLakshmi Yadlapati         if (ec)
92*543f9a75SLakshmi Yadlapati         {
93*543f9a75SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
94*543f9a75SLakshmi Yadlapati             messages::internalError(aResp->res);
95*543f9a75SLakshmi Yadlapati             return;
96*543f9a75SLakshmi Yadlapati         }
97*543f9a75SLakshmi Yadlapati         handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback);
98*543f9a75SLakshmi Yadlapati         return;
99*543f9a75SLakshmi Yadlapati         });
100*543f9a75SLakshmi Yadlapati }
101*543f9a75SLakshmi Yadlapati 
102b5a76932SEd Tanous static inline void
1038d1b46d7Szhanghch05     getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
104adbe192aSJason M. Bills                       const std::string& name)
105f5c9f8bdSJason M. Bills {
1067a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
1077a1dbc48SGeorge Liu         pciePath, 1, {},
1087a1dbc48SGeorge Liu         [asyncResp, name](const boost::system::error_code& ec,
109b9d36b47SEd Tanous                           const dbus::utility::MapperGetSubTreePathsResponse&
110b9d36b47SEd Tanous                               pcieDevicePaths) {
111f5c9f8bdSJason M. Bills         if (ec)
112f5c9f8bdSJason M. Bills         {
113a2730f01SAndrew Geissler             BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
114f5c9f8bdSJason M. Bills                              << ec.message();
115a2730f01SAndrew Geissler             // Not an error, system just doesn't have PCIe info
116f5c9f8bdSJason M. Bills             return;
117f5c9f8bdSJason M. Bills         }
118adbe192aSJason M. Bills         nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
119f5c9f8bdSJason M. Bills         pcieDeviceList = nlohmann::json::array();
120f5c9f8bdSJason M. Bills         for (const std::string& pcieDevicePath : pcieDevicePaths)
121f5c9f8bdSJason M. Bills         {
1223174e4dfSEd Tanous             size_t devStart = pcieDevicePath.rfind('/');
123f5c9f8bdSJason M. Bills             if (devStart == std::string::npos)
124f5c9f8bdSJason M. Bills             {
125f5c9f8bdSJason M. Bills                 continue;
126f5c9f8bdSJason M. Bills             }
127f5c9f8bdSJason M. Bills 
128f5c9f8bdSJason M. Bills             std::string devName = pcieDevicePath.substr(devStart + 1);
129f5c9f8bdSJason M. Bills             if (devName.empty())
130f5c9f8bdSJason M. Bills             {
131f5c9f8bdSJason M. Bills                 continue;
132f5c9f8bdSJason M. Bills             }
1331476687dSEd Tanous             nlohmann::json::object_t pcieDevice;
134eddfc437SWilly Tu             pcieDevice["@odata.id"] = crow::utility::urlFromPieces(
135eddfc437SWilly Tu                 "redfish", "v1", "Systems", "system", "PCIeDevices", devName);
1361476687dSEd Tanous             pcieDeviceList.push_back(std::move(pcieDevice));
137f5c9f8bdSJason M. Bills         }
138002d39b4SEd Tanous         asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
1397a1dbc48SGeorge Liu         });
140f5c9f8bdSJason M. Bills }
141f5c9f8bdSJason M. Bills 
142b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
143b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
144b38fa2abSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
145b38fa2abSLakshmi Yadlapati     const std::string& systemName)
146b38fa2abSLakshmi Yadlapati {
147b38fa2abSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
148b38fa2abSLakshmi Yadlapati     {
149b38fa2abSLakshmi Yadlapati         return;
150b38fa2abSLakshmi Yadlapati     }
151b38fa2abSLakshmi Yadlapati     if (systemName != "system")
152b38fa2abSLakshmi Yadlapati     {
153b38fa2abSLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
154b38fa2abSLakshmi Yadlapati         return;
155b38fa2abSLakshmi Yadlapati     }
156*543f9a75SLakshmi Yadlapati 
157b38fa2abSLakshmi Yadlapati     aResp->res.addHeader(boost::beast::http::field::link,
158b38fa2abSLakshmi Yadlapati                          "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
159b38fa2abSLakshmi Yadlapati                          "PCIeDeviceCollection.json>; rel=describedby");
160b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] =
161b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
162b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["@odata.id"] =
163b38fa2abSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices";
164b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device Collection";
165b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
166b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members"] = nlohmann::json::array();
167b38fa2abSLakshmi Yadlapati     aResp->res.jsonValue["Members@odata.count"] = 0;
168b38fa2abSLakshmi Yadlapati 
169b38fa2abSLakshmi Yadlapati     constexpr std::array<std::string_view, 1> interfaces{
170b38fa2abSLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
171b38fa2abSLakshmi Yadlapati     collection_util::getCollectionMembers(
172b38fa2abSLakshmi Yadlapati         aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
173b38fa2abSLakshmi Yadlapati         interfaces);
174b38fa2abSLakshmi Yadlapati }
175b38fa2abSLakshmi Yadlapati 
1767e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
177adbe192aSJason M. Bills {
178adbe192aSJason M. Bills     /**
179adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
180adbe192aSJason M. Bills      */
18122d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
182ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1837e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
184b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
185f5c9f8bdSJason M. Bills }
186f5c9f8bdSJason M. Bills 
1870ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes>
18862cd45afSSpencer Ku     redfishPcieGenerationFromDbus(const std::string& generationInUse)
18962cd45afSSpencer Ku {
19062cd45afSSpencer Ku     if (generationInUse ==
19162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
19262cd45afSSpencer Ku     {
1930ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen1;
19462cd45afSSpencer Ku     }
19562cd45afSSpencer Ku     if (generationInUse ==
19662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
19762cd45afSSpencer Ku     {
1980ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen2;
19962cd45afSSpencer Ku     }
20062cd45afSSpencer Ku     if (generationInUse ==
20162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
20262cd45afSSpencer Ku     {
2030ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen3;
20462cd45afSSpencer Ku     }
20562cd45afSSpencer Ku     if (generationInUse ==
20662cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
20762cd45afSSpencer Ku     {
2080ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen4;
20962cd45afSSpencer Ku     }
21062cd45afSSpencer Ku     if (generationInUse ==
21162cd45afSSpencer Ku         "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
21262cd45afSSpencer Ku     {
2130ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Gen5;
21462cd45afSSpencer Ku     }
215e825cbc8SEd Tanous     if (generationInUse.empty() ||
216e825cbc8SEd Tanous         generationInUse ==
21762cd45afSSpencer Ku             "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
21862cd45afSSpencer Ku     {
2190ec8b83dSEd Tanous         return pcie_device::PCIeTypes::Invalid;
22062cd45afSSpencer Ku     }
22162cd45afSSpencer Ku 
22262cd45afSSpencer Ku     // The value is not unknown or Gen1-5, need return an internal error.
22362cd45afSSpencer Ku     return std::nullopt;
22462cd45afSSpencer Ku }
22562cd45afSSpencer Ku 
226*543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
227*543f9a75SLakshmi Yadlapati     crow::Response& resp,
228*543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
229f5c9f8bdSJason M. Bills {
230d1bde9e5SKrzysztof Grobelny     const std::string* manufacturer = nullptr;
231d1bde9e5SKrzysztof Grobelny     const std::string* deviceType = nullptr;
232d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
233*543f9a75SLakshmi Yadlapati     const int64_t* lanesInUse = nullptr;
234d1bde9e5SKrzysztof Grobelny 
235d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
236*543f9a75SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
237*543f9a75SLakshmi Yadlapati         deviceType, "GenerationInUse", generationInUse, "LanesInUse",
238*543f9a75SLakshmi Yadlapati         lanesInUse, "Manufacturer", manufacturer);
239d1bde9e5SKrzysztof Grobelny 
240d1bde9e5SKrzysztof Grobelny     if (!success)
241d1bde9e5SKrzysztof Grobelny     {
242*543f9a75SLakshmi Yadlapati         messages::internalError(resp);
243d1bde9e5SKrzysztof Grobelny         return;
244d1bde9e5SKrzysztof Grobelny     }
245d1bde9e5SKrzysztof Grobelny 
246*543f9a75SLakshmi Yadlapati     if (deviceType != nullptr && !deviceType->empty())
247703f6741SMyung Bae     {
248*543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
249703f6741SMyung Bae     }
250703f6741SMyung Bae 
251d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
252d1bde9e5SKrzysztof Grobelny     {
2530ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
254d1bde9e5SKrzysztof Grobelny             redfishPcieGenerationFromDbus(*generationInUse);
255*543f9a75SLakshmi Yadlapati 
256d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
257d1bde9e5SKrzysztof Grobelny         {
258*543f9a75SLakshmi Yadlapati             messages::internalError(resp);
259d1bde9e5SKrzysztof Grobelny             return;
260d1bde9e5SKrzysztof Grobelny         }
2610ec8b83dSEd Tanous         if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
262d1bde9e5SKrzysztof Grobelny         {
263*543f9a75SLakshmi Yadlapati             resp.jsonValue["PCIeInterface"]["PCIeType"] =
264d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
265d1bde9e5SKrzysztof Grobelny         }
266a9f68bb5STony Lee     }
267d1bde9e5SKrzysztof Grobelny 
268*543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
269*543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
270*543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
271*543f9a75SLakshmi Yadlapati     {
272*543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
273*543f9a75SLakshmi Yadlapati     }
274*543f9a75SLakshmi Yadlapati 
275d1bde9e5SKrzysztof Grobelny     if (manufacturer != nullptr)
276d1bde9e5SKrzysztof Grobelny     {
277*543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["Manufacturer"] = *manufacturer;
278*543f9a75SLakshmi Yadlapati     }
279d1bde9e5SKrzysztof Grobelny }
280d1bde9e5SKrzysztof Grobelny 
281*543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
282*543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
283*543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
284*543f9a75SLakshmi Yadlapati     const std::function<void(
285*543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
286d1bde9e5SKrzysztof Grobelny {
287*543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
288*543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
289*543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
290*543f9a75SLakshmi Yadlapati         [aResp,
291*543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
292*543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
293*543f9a75SLakshmi Yadlapati         if (ec)
294*543f9a75SLakshmi Yadlapati         {
295*543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
296*543f9a75SLakshmi Yadlapati             {
297*543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
298*543f9a75SLakshmi Yadlapati                 messages::internalError(aResp->res);
299*543f9a75SLakshmi Yadlapati             }
300*543f9a75SLakshmi Yadlapati             return;
301*543f9a75SLakshmi Yadlapati         }
302*543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
303*543f9a75SLakshmi Yadlapati         });
304d1bde9e5SKrzysztof Grobelny }
305d1bde9e5SKrzysztof Grobelny 
306*543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
307*543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
308*543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
309*543f9a75SLakshmi Yadlapati {
310*543f9a75SLakshmi Yadlapati     aResp->res.addHeader(
311*543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
312*543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
313*543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
314*543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
315*543f9a75SLakshmi Yadlapati         "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId);
316*543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device";
317*543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Id"] = pcieDeviceId;
318*543f9a75SLakshmi Yadlapati }
3191476687dSEd Tanous 
320*543f9a75SLakshmi Yadlapati inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
321*543f9a75SLakshmi Yadlapati                                 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
322*543f9a75SLakshmi Yadlapati                                 const std::string& systemName,
323*543f9a75SLakshmi Yadlapati                                 const std::string& pcieDeviceId)
324*543f9a75SLakshmi Yadlapati {
325*543f9a75SLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
326*543f9a75SLakshmi Yadlapati     {
327*543f9a75SLakshmi Yadlapati         return;
328*543f9a75SLakshmi Yadlapati     }
329*543f9a75SLakshmi Yadlapati     if (systemName != "system")
330*543f9a75SLakshmi Yadlapati     {
331*543f9a75SLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
332*543f9a75SLakshmi Yadlapati         return;
333*543f9a75SLakshmi Yadlapati     }
334*543f9a75SLakshmi Yadlapati 
335*543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
336*543f9a75SLakshmi Yadlapati         pcieDeviceId, aResp,
337*543f9a75SLakshmi Yadlapati         [aResp, pcieDeviceId](const std::string& pcieDevicePath,
338*543f9a75SLakshmi Yadlapati                               const std::string& service) {
339*543f9a75SLakshmi Yadlapati         addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
340*543f9a75SLakshmi Yadlapati         getPCIeDeviceProperties(
341*543f9a75SLakshmi Yadlapati             aResp, pcieDevicePath, service,
342*543f9a75SLakshmi Yadlapati             [aResp](const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
343*543f9a75SLakshmi Yadlapati             addPCIeDeviceProperties(aResp->res, pcieDevProperties);
3447e860f15SJohn Edward Broadbent             });
345*543f9a75SLakshmi Yadlapati         });
346*543f9a75SLakshmi Yadlapati }
347*543f9a75SLakshmi Yadlapati 
348*543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
349*543f9a75SLakshmi Yadlapati {
350*543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
351*543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
352*543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
353*543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
354dede6a98SJason M. Bills }
355dede6a98SJason M. Bills 
3567e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
3577e860f15SJohn Edward Broadbent {
358dede6a98SJason M. Bills     /**
359dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
360dede6a98SJason M. Bills      */
3617e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
3627e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
363ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
364002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
365002d39b4SEd Tanous             [&app](const crow::Request& req,
3667e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
36745ca1b86SEd Tanous                    const std::string& device) {
3683ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
369dede6a98SJason M. Bills         {
37045ca1b86SEd Tanous             return;
37145ca1b86SEd Tanous         }
3721476687dSEd Tanous 
3731476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
3741476687dSEd Tanous             "#PCIeFunctionCollection.PCIeFunctionCollection";
375eddfc437SWilly Tu         asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
376eddfc437SWilly Tu             "redfish", "v1", "Systems", "system", "PCIeDevices", device,
377eddfc437SWilly Tu             "PCIeFunctions");
3781476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
3791476687dSEd Tanous         asyncResp->res.jsonValue["Description"] =
3801476687dSEd Tanous             "Collection of PCIe Functions for PCIe Device " + device;
381dede6a98SJason M. Bills 
382b9d36b47SEd Tanous         auto getPCIeDeviceCallback =
38345ca1b86SEd Tanous             [asyncResp, device](
3845e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
38545ca1b86SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
3867e860f15SJohn Edward Broadbent             if (ec)
3877e860f15SJohn Edward Broadbent             {
3887e860f15SJohn Edward Broadbent                 BMCWEB_LOG_DEBUG
389002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
390002d39b4SEd Tanous                     << ": " << ec.message();
39145ca1b86SEd Tanous                 if (ec.value() ==
39245ca1b86SEd Tanous                     boost::system::linux_error::bad_request_descriptor)
3937e860f15SJohn Edward Broadbent                 {
394002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
395002d39b4SEd Tanous                                                device);
3967e860f15SJohn Edward Broadbent                 }
3977e860f15SJohn Edward Broadbent                 else
3987e860f15SJohn Edward Broadbent                 {
3997e860f15SJohn Edward Broadbent                     messages::internalError(asyncResp->res);
4007e860f15SJohn Edward Broadbent                 }
4017e860f15SJohn Edward Broadbent                 return;
4027e860f15SJohn Edward Broadbent             }
4037e860f15SJohn Edward Broadbent 
4047e860f15SJohn Edward Broadbent             nlohmann::json& pcieFunctionList =
4057e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members"];
4067e860f15SJohn Edward Broadbent             pcieFunctionList = nlohmann::json::array();
4077e860f15SJohn Edward Broadbent             static constexpr const int maxPciFunctionNum = 8;
40845ca1b86SEd Tanous             for (int functionNum = 0; functionNum < maxPciFunctionNum;
40945ca1b86SEd Tanous                  functionNum++)
4107e860f15SJohn Edward Broadbent             {
411b9d36b47SEd Tanous                 // Check if this function exists by looking for a
412b9d36b47SEd Tanous                 // device ID
4137e860f15SJohn Edward Broadbent                 std::string devIDProperty =
414002d39b4SEd Tanous                     "Function" + std::to_string(functionNum) + "DeviceId";
415b9d36b47SEd Tanous                 const std::string* property = nullptr;
416b9d36b47SEd Tanous                 for (const auto& propEntry : pcieDevProperties)
4177e860f15SJohn Edward Broadbent                 {
418b9d36b47SEd Tanous                     if (propEntry.first == devIDProperty)
419b9d36b47SEd Tanous                     {
420002d39b4SEd Tanous                         property = std::get_if<std::string>(&propEntry.second);
421b9d36b47SEd Tanous                     }
422b9d36b47SEd Tanous                 }
423fb0ecc3eSNan Zhou                 if (property == nullptr || property->empty())
424b9d36b47SEd Tanous                 {
425e28ce0e6SNan Zhou                     continue;
426b9d36b47SEd Tanous                 }
4271476687dSEd Tanous                 nlohmann::json::object_t pcieFunction;
428eddfc437SWilly Tu                 pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
429eddfc437SWilly Tu                     "redfish", "v1", "Systems", "system", "PCIeDevices", device,
430eddfc437SWilly Tu                     "PCIeFunctions", std::to_string(functionNum));
4311476687dSEd Tanous                 pcieFunctionList.push_back(std::move(pcieFunction));
4327e860f15SJohn Edward Broadbent             }
433a818d15aSJiaqing Zhao             asyncResp->res.jsonValue["Members@odata.count"] =
4347e860f15SJohn Edward Broadbent                 pcieFunctionList.size();
4357e860f15SJohn Edward Broadbent         };
4367e860f15SJohn Edward Broadbent         std::string escapedPath = std::string(pciePath) + "/" + device;
4377e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(escapedPath);
438d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
439d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
440d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
4417e860f15SJohn Edward Broadbent         });
4427e860f15SJohn Edward Broadbent }
4437e860f15SJohn Edward Broadbent 
4447e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunction(App& app)
4457e860f15SJohn Edward Broadbent {
4467e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
4477e860f15SJohn Edward Broadbent         app,
4487e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
449ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunction)
450002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
451002d39b4SEd Tanous             [&app](const crow::Request& req,
45245ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
453002d39b4SEd Tanous                    const std::string& device, const std::string& function) {
4543ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
45545ca1b86SEd Tanous         {
45645ca1b86SEd Tanous             return;
45745ca1b86SEd Tanous         }
458168e20c1SEd Tanous         auto getPCIeDeviceCallback =
459168e20c1SEd Tanous             [asyncResp, device, function](
4605e7e2dc5SEd Tanous                 const boost::system::error_code& ec,
461b9d36b47SEd Tanous                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
462dede6a98SJason M. Bills             if (ec)
463dede6a98SJason M. Bills             {
464dede6a98SJason M. Bills                 BMCWEB_LOG_DEBUG
465002d39b4SEd Tanous                     << "failed to get PCIe Device properties ec: " << ec.value()
466002d39b4SEd Tanous                     << ": " << ec.message();
467dede6a98SJason M. Bills                 if (ec.value() ==
468dede6a98SJason M. Bills                     boost::system::linux_error::bad_request_descriptor)
469dede6a98SJason M. Bills                 {
470002d39b4SEd Tanous                     messages::resourceNotFound(asyncResp->res, "PCIeDevice",
471002d39b4SEd Tanous                                                device);
472dede6a98SJason M. Bills                 }
473dede6a98SJason M. Bills                 else
474dede6a98SJason M. Bills                 {
475dede6a98SJason M. Bills                     messages::internalError(asyncResp->res);
476dede6a98SJason M. Bills                 }
477dede6a98SJason M. Bills                 return;
478dede6a98SJason M. Bills             }
479dede6a98SJason M. Bills 
4801476687dSEd Tanous             // Check if this function exists by looking for a device
4811476687dSEd Tanous             // ID
482b9d36b47SEd Tanous             std::string functionName = "Function" + function;
483b9d36b47SEd Tanous             std::string devIDProperty = functionName + "DeviceId";
484b9d36b47SEd Tanous 
485b9d36b47SEd Tanous             const std::string* devIdProperty = nullptr;
486b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
487b9d36b47SEd Tanous             {
488b9d36b47SEd Tanous                 if (property.first == devIDProperty)
489b9d36b47SEd Tanous                 {
490002d39b4SEd Tanous                     devIdProperty = std::get_if<std::string>(&property.second);
491b9d36b47SEd Tanous                     continue;
492b9d36b47SEd Tanous                 }
493b9d36b47SEd Tanous             }
494973c1355STony Lee             if (devIdProperty == nullptr || devIdProperty->empty())
495f5c9f8bdSJason M. Bills             {
496002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
497002d39b4SEd Tanous                                            function);
498f5c9f8bdSJason M. Bills                 return;
499f5c9f8bdSJason M. Bills             }
500f5c9f8bdSJason M. Bills 
5011476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
5021476687dSEd Tanous                 "#PCIeFunction.v1_2_0.PCIeFunction";
5031476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
504eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
505eddfc437SWilly Tu                                              "system", "PCIeDevices", device,
506eddfc437SWilly Tu                                              "PCIeFunctions", function);
5071476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "PCIe Function";
5081476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = function;
509002d39b4SEd Tanous             asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
510002d39b4SEd Tanous             asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
511eddfc437SWilly Tu                 crow::utility::urlFromPieces("redfish", "v1", "Systems",
512eddfc437SWilly Tu                                              "system", "PCIeDevices", device);
513f5c9f8bdSJason M. Bills 
514b9d36b47SEd Tanous             for (const auto& property : pcieDevProperties)
515f5c9f8bdSJason M. Bills             {
516b9d36b47SEd Tanous                 const std::string* strProperty =
517b9d36b47SEd Tanous                     std::get_if<std::string>(&property.second);
518b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceId")
519f5c9f8bdSJason M. Bills                 {
520b9d36b47SEd Tanous                     asyncResp->res.jsonValue["DeviceId"] = *strProperty;
521f5c9f8bdSJason M. Bills                 }
522b9d36b47SEd Tanous                 if (property.first == functionName + "VendorId")
523f5c9f8bdSJason M. Bills                 {
524b9d36b47SEd Tanous                     asyncResp->res.jsonValue["VendorId"] = *strProperty;
525f5c9f8bdSJason M. Bills                 }
526b9d36b47SEd Tanous                 if (property.first == functionName + "FunctionType")
527f5c9f8bdSJason M. Bills                 {
528002d39b4SEd Tanous                     asyncResp->res.jsonValue["FunctionType"] = *strProperty;
529f5c9f8bdSJason M. Bills                 }
530b9d36b47SEd Tanous                 if (property.first == functionName + "DeviceClass")
531f5c9f8bdSJason M. Bills                 {
532002d39b4SEd Tanous                     asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
533f5c9f8bdSJason M. Bills                 }
534b9d36b47SEd Tanous                 if (property.first == functionName + "ClassCode")
535f5c9f8bdSJason M. Bills                 {
536002d39b4SEd Tanous                     asyncResp->res.jsonValue["ClassCode"] = *strProperty;
537f5c9f8bdSJason M. Bills                 }
538b9d36b47SEd Tanous                 if (property.first == functionName + "RevisionId")
539f5c9f8bdSJason M. Bills                 {
540002d39b4SEd Tanous                     asyncResp->res.jsonValue["RevisionId"] = *strProperty;
541f5c9f8bdSJason M. Bills                 }
542b9d36b47SEd Tanous                 if (property.first == functionName + "SubsystemId")
543b9d36b47SEd Tanous                 {
544002d39b4SEd Tanous                     asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
545b9d36b47SEd Tanous                 }
546002d39b4SEd Tanous                 if (property.first == functionName + "SubsystemVendorId")
547f5c9f8bdSJason M. Bills                 {
548168e20c1SEd Tanous                     asyncResp->res.jsonValue["SubsystemVendorId"] =
549b9d36b47SEd Tanous                         *strProperty;
550b9d36b47SEd Tanous                 }
551f5c9f8bdSJason M. Bills             }
552f5c9f8bdSJason M. Bills         };
553f5c9f8bdSJason M. Bills         std::string escapedPath = std::string(pciePath) + "/" + device;
554f5c9f8bdSJason M. Bills         dbus::utility::escapePathForDbus(escapedPath);
555d1bde9e5SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
556d1bde9e5SKrzysztof Grobelny             *crow::connections::systemBus, pcieService, escapedPath,
557d1bde9e5SKrzysztof Grobelny             pcieDeviceInterface, std::move(getPCIeDeviceCallback));
5587e860f15SJohn Edward Broadbent         });
559f5c9f8bdSJason M. Bills }
560f5c9f8bdSJason M. Bills 
561f5c9f8bdSJason M. Bills } // namespace redfish
562