xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision 727a046ccfa1d936ce984e30d6e257ea027ef587)
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 
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     constexpr std::array<std::string_view, 1> interfaces{
83543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
84543f9a75SLakshmi Yadlapati 
85543f9a75SLakshmi Yadlapati     dbus::utility::getSubTreePaths(
86543f9a75SLakshmi Yadlapati         "/xyz/openbmc_project/inventory", 0, interfaces,
87543f9a75SLakshmi Yadlapati         [pcieDeviceId, aResp,
88543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
89543f9a75SLakshmi Yadlapati                    const dbus::utility::MapperGetSubTreePathsResponse&
90543f9a75SLakshmi Yadlapati                        pcieDevicePaths) {
91543f9a75SLakshmi Yadlapati         if (ec)
92543f9a75SLakshmi Yadlapati         {
93543f9a75SLakshmi Yadlapati             BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
94543f9a75SLakshmi Yadlapati             messages::internalError(aResp->res);
95543f9a75SLakshmi Yadlapati             return;
96543f9a75SLakshmi Yadlapati         }
97543f9a75SLakshmi Yadlapati         handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback);
98543f9a75SLakshmi Yadlapati         return;
99543f9a75SLakshmi Yadlapati         });
100543f9a75SLakshmi Yadlapati }
101543f9a75SLakshmi 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     }
156543f9a75SLakshmi 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 
226543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
22735ad613dSLakshmi Yadlapati     crow::Response& resp, const std::string& pcieDeviceId,
228543f9a75SLakshmi 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;
233543f9a75SLakshmi Yadlapati     const int64_t* lanesInUse = nullptr;
234d1bde9e5SKrzysztof Grobelny 
235d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
236543f9a75SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
237543f9a75SLakshmi Yadlapati         deviceType, "GenerationInUse", generationInUse, "LanesInUse",
238543f9a75SLakshmi Yadlapati         lanesInUse, "Manufacturer", manufacturer);
239d1bde9e5SKrzysztof Grobelny 
240d1bde9e5SKrzysztof Grobelny     if (!success)
241d1bde9e5SKrzysztof Grobelny     {
242543f9a75SLakshmi Yadlapati         messages::internalError(resp);
243d1bde9e5SKrzysztof Grobelny         return;
244d1bde9e5SKrzysztof Grobelny     }
245d1bde9e5SKrzysztof Grobelny 
246543f9a75SLakshmi Yadlapati     if (deviceType != nullptr && !deviceType->empty())
247703f6741SMyung Bae     {
248543f9a75SLakshmi 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);
255543f9a75SLakshmi Yadlapati 
256d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
257d1bde9e5SKrzysztof Grobelny         {
258543f9a75SLakshmi Yadlapati             messages::internalError(resp);
259d1bde9e5SKrzysztof Grobelny             return;
260d1bde9e5SKrzysztof Grobelny         }
2610ec8b83dSEd Tanous         if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
262d1bde9e5SKrzysztof Grobelny         {
263543f9a75SLakshmi Yadlapati             resp.jsonValue["PCIeInterface"]["PCIeType"] =
264d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
265d1bde9e5SKrzysztof Grobelny         }
266a9f68bb5STony Lee     }
267d1bde9e5SKrzysztof Grobelny 
268543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
269543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
270543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
271543f9a75SLakshmi Yadlapati     {
272543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
273543f9a75SLakshmi Yadlapati     }
274543f9a75SLakshmi Yadlapati 
275d1bde9e5SKrzysztof Grobelny     if (manufacturer != nullptr)
276d1bde9e5SKrzysztof Grobelny     {
277543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["Manufacturer"] = *manufacturer;
278543f9a75SLakshmi Yadlapati     }
27935ad613dSLakshmi Yadlapati 
28035ad613dSLakshmi Yadlapati     resp.jsonValue["PCIeFunctions"]["@odata.id"] = crow::utility::urlFromPieces(
28135ad613dSLakshmi Yadlapati         "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
28235ad613dSLakshmi Yadlapati         "PCIeFunctions");
283d1bde9e5SKrzysztof Grobelny }
284d1bde9e5SKrzysztof Grobelny 
285543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
286543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
287543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
288543f9a75SLakshmi Yadlapati     const std::function<void(
289543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
290d1bde9e5SKrzysztof Grobelny {
291543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
292543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
293543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
294543f9a75SLakshmi Yadlapati         [aResp,
295543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
296543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
297543f9a75SLakshmi Yadlapati         if (ec)
298543f9a75SLakshmi Yadlapati         {
299543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
300543f9a75SLakshmi Yadlapati             {
301543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
302543f9a75SLakshmi Yadlapati                 messages::internalError(aResp->res);
303543f9a75SLakshmi Yadlapati             }
304543f9a75SLakshmi Yadlapati             return;
305543f9a75SLakshmi Yadlapati         }
306543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
307543f9a75SLakshmi Yadlapati         });
308d1bde9e5SKrzysztof Grobelny }
309d1bde9e5SKrzysztof Grobelny 
310543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
311543f9a75SLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
312543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
313543f9a75SLakshmi Yadlapati {
314543f9a75SLakshmi Yadlapati     aResp->res.addHeader(
315543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
316543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
317543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
318543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
319543f9a75SLakshmi Yadlapati         "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId);
320543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Name"] = "PCIe Device";
321543f9a75SLakshmi Yadlapati     aResp->res.jsonValue["Id"] = pcieDeviceId;
322543f9a75SLakshmi Yadlapati }
3231476687dSEd Tanous 
324543f9a75SLakshmi Yadlapati inline void handlePCIeDeviceGet(App& app, const crow::Request& req,
325543f9a75SLakshmi Yadlapati                                 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
326543f9a75SLakshmi Yadlapati                                 const std::string& systemName,
327543f9a75SLakshmi Yadlapati                                 const std::string& pcieDeviceId)
328543f9a75SLakshmi Yadlapati {
329543f9a75SLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
330543f9a75SLakshmi Yadlapati     {
331543f9a75SLakshmi Yadlapati         return;
332543f9a75SLakshmi Yadlapati     }
333543f9a75SLakshmi Yadlapati     if (systemName != "system")
334543f9a75SLakshmi Yadlapati     {
335543f9a75SLakshmi Yadlapati         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
336543f9a75SLakshmi Yadlapati         return;
337543f9a75SLakshmi Yadlapati     }
338543f9a75SLakshmi Yadlapati 
339543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
340543f9a75SLakshmi Yadlapati         pcieDeviceId, aResp,
341543f9a75SLakshmi Yadlapati         [aResp, pcieDeviceId](const std::string& pcieDevicePath,
342543f9a75SLakshmi Yadlapati                               const std::string& service) {
343543f9a75SLakshmi Yadlapati         addPCIeDeviceCommonProperties(aResp, pcieDeviceId);
344543f9a75SLakshmi Yadlapati         getPCIeDeviceProperties(
345543f9a75SLakshmi Yadlapati             aResp, pcieDevicePath, service,
34635ad613dSLakshmi Yadlapati             [aResp, pcieDeviceId](
34735ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
34835ad613dSLakshmi Yadlapati             addPCIeDeviceProperties(aResp->res, pcieDeviceId,
34935ad613dSLakshmi Yadlapati                                     pcieDevProperties);
3507e860f15SJohn Edward Broadbent             });
351543f9a75SLakshmi Yadlapati         });
352543f9a75SLakshmi Yadlapati }
353543f9a75SLakshmi Yadlapati 
354543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
355543f9a75SLakshmi Yadlapati {
356543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
357543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
358543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
359543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
360dede6a98SJason M. Bills }
361dede6a98SJason M. Bills 
36235ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
36335ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
36435ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
36535ad613dSLakshmi Yadlapati {
36635ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
36735ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
36835ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
36935ad613dSLakshmi Yadlapati 
37035ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
37135ad613dSLakshmi Yadlapati     {
37235ad613dSLakshmi Yadlapati         // Check if this function exists by
37335ad613dSLakshmi Yadlapati         // looking for a device ID
37435ad613dSLakshmi Yadlapati         std::string devIDProperty =
37535ad613dSLakshmi Yadlapati             "Function" + std::to_string(functionNum) + "DeviceId";
37635ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
37735ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
37835ad613dSLakshmi Yadlapati         {
37935ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
38035ad613dSLakshmi Yadlapati             {
38135ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
38235ad613dSLakshmi Yadlapati                 break;
38335ad613dSLakshmi Yadlapati             }
38435ad613dSLakshmi Yadlapati         }
38535ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
38635ad613dSLakshmi Yadlapati         {
38735ad613dSLakshmi Yadlapati             continue;
38835ad613dSLakshmi Yadlapati         }
38935ad613dSLakshmi Yadlapati 
39035ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
39135ad613dSLakshmi Yadlapati         pcieFunction["@odata.id"] = crow::utility::urlFromPieces(
39235ad613dSLakshmi Yadlapati             "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
39335ad613dSLakshmi Yadlapati             "PCIeFunctions", std::to_string(functionNum));
39435ad613dSLakshmi Yadlapati         pcieFunctionList.push_back(std::move(pcieFunction));
39535ad613dSLakshmi Yadlapati     }
39635ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
39735ad613dSLakshmi Yadlapati }
39835ad613dSLakshmi Yadlapati 
39935ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
40035ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
40135ad613dSLakshmi Yadlapati     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
40235ad613dSLakshmi Yadlapati     const std::string& pcieDeviceId)
40335ad613dSLakshmi Yadlapati {
40435ad613dSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
40535ad613dSLakshmi Yadlapati     {
40635ad613dSLakshmi Yadlapati         return;
40735ad613dSLakshmi Yadlapati     }
40835ad613dSLakshmi Yadlapati 
40935ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
41035ad613dSLakshmi Yadlapati         pcieDeviceId, aResp,
41135ad613dSLakshmi Yadlapati         [aResp, pcieDeviceId](const std::string& pcieDevicePath,
41235ad613dSLakshmi Yadlapati                               const std::string& service) {
41335ad613dSLakshmi Yadlapati         aResp->res.addHeader(
41435ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
41535ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
41635ad613dSLakshmi Yadlapati         aResp->res.jsonValue["@odata.type"] =
41735ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
41835ad613dSLakshmi Yadlapati         aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
41935ad613dSLakshmi Yadlapati             "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
42035ad613dSLakshmi Yadlapati             "PCIeFunctions");
42135ad613dSLakshmi Yadlapati         aResp->res.jsonValue["Name"] = "PCIe Function Collection";
42235ad613dSLakshmi Yadlapati         aResp->res.jsonValue["Description"] =
42335ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
42435ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
42535ad613dSLakshmi Yadlapati             aResp, pcieDevicePath, service,
42635ad613dSLakshmi Yadlapati             [aResp, pcieDeviceId](
42735ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
42835ad613dSLakshmi Yadlapati             addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties);
42935ad613dSLakshmi Yadlapati             });
43035ad613dSLakshmi Yadlapati         });
43135ad613dSLakshmi Yadlapati }
43235ad613dSLakshmi Yadlapati 
4337e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
4347e860f15SJohn Edward Broadbent {
435dede6a98SJason M. Bills     /**
436dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
437dede6a98SJason M. Bills      */
4387e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
4397e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
440ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
441002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
44235ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
4437e860f15SJohn Edward Broadbent }
4447e860f15SJohn Edward Broadbent 
445*727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
446*727a046cSLakshmi Yadlapati     const std::string& pcieFunctionId,
447*727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
4487e860f15SJohn Edward Broadbent {
449*727a046cSLakshmi Yadlapati     std::string functionName = "Function" + pcieFunctionId;
450b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
451b9d36b47SEd Tanous 
452b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
453b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
454b9d36b47SEd Tanous     {
455b9d36b47SEd Tanous         if (property.first == devIDProperty)
456b9d36b47SEd Tanous         {
457002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
458*727a046cSLakshmi Yadlapati             break;
459b9d36b47SEd Tanous         }
460b9d36b47SEd Tanous     }
461*727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
462*727a046cSLakshmi Yadlapati }
463*727a046cSLakshmi Yadlapati 
464*727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
465*727a046cSLakshmi Yadlapati     crow::Response& resp, const std::string& pcieFunctionId,
466*727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
467f5c9f8bdSJason M. Bills {
468*727a046cSLakshmi Yadlapati     std::string functionName = "Function" + pcieFunctionId;
469*727a046cSLakshmi Yadlapati     if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties))
470*727a046cSLakshmi Yadlapati     {
471*727a046cSLakshmi Yadlapati         messages::resourceNotFound(resp, "PCIeFunction", pcieFunctionId);
472f5c9f8bdSJason M. Bills         return;
473f5c9f8bdSJason M. Bills     }
474b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
475f5c9f8bdSJason M. Bills     {
476b9d36b47SEd Tanous         const std::string* strProperty =
477b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
478*727a046cSLakshmi Yadlapati 
479b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
480f5c9f8bdSJason M. Bills         {
481*727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
482f5c9f8bdSJason M. Bills         }
483b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
484f5c9f8bdSJason M. Bills         {
485*727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
486f5c9f8bdSJason M. Bills         }
487*727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
488*727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
489*727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
490b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
491f5c9f8bdSJason M. Bills         {
492*727a046cSLakshmi Yadlapati             if (!strProperty->empty())
493*727a046cSLakshmi Yadlapati             {
494*727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
495*727a046cSLakshmi Yadlapati             }
496f5c9f8bdSJason M. Bills         }
497b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
498f5c9f8bdSJason M. Bills         {
499*727a046cSLakshmi Yadlapati             if (!strProperty->empty())
500*727a046cSLakshmi Yadlapati             {
501*727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
502*727a046cSLakshmi Yadlapati             }
503f5c9f8bdSJason M. Bills         }
504b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
505f5c9f8bdSJason M. Bills         {
506*727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
507f5c9f8bdSJason M. Bills         }
508b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
509f5c9f8bdSJason M. Bills         {
510*727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
511f5c9f8bdSJason M. Bills         }
512b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
513b9d36b47SEd Tanous         {
514*727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
515b9d36b47SEd Tanous         }
516002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
517f5c9f8bdSJason M. Bills         {
518*727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
519b9d36b47SEd Tanous         }
520f5c9f8bdSJason M. Bills     }
521*727a046cSLakshmi Yadlapati }
522*727a046cSLakshmi Yadlapati 
523*727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
524*727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
525*727a046cSLakshmi Yadlapati                                             const std::string& pcieFunctionId)
526*727a046cSLakshmi Yadlapati {
527*727a046cSLakshmi Yadlapati     resp.addHeader(
528*727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
529*727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
530*727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
531*727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
532*727a046cSLakshmi Yadlapati         "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId,
533*727a046cSLakshmi Yadlapati         "PCIeFunctions", pcieFunctionId);
534*727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
535*727a046cSLakshmi Yadlapati     resp.jsonValue["Id"] = pcieFunctionId;
536*727a046cSLakshmi Yadlapati     resp.jsonValue["FunctionId"] = std::stoi(pcieFunctionId);
537*727a046cSLakshmi Yadlapati     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
538*727a046cSLakshmi Yadlapati         crow::utility::urlFromPieces("redfish", "v1", "Systems", "system",
539*727a046cSLakshmi Yadlapati                                      "PCIeDevices", pcieDeviceId);
540*727a046cSLakshmi Yadlapati }
541*727a046cSLakshmi Yadlapati 
542*727a046cSLakshmi Yadlapati inline void
543*727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
544*727a046cSLakshmi Yadlapati                           const std::shared_ptr<bmcweb::AsyncResp>& aResp,
545*727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
546*727a046cSLakshmi Yadlapati                           const std::string& pcieFunctionId)
547*727a046cSLakshmi Yadlapati {
548*727a046cSLakshmi Yadlapati     if (!redfish::setUpRedfishRoute(app, req, aResp))
549*727a046cSLakshmi Yadlapati     {
550*727a046cSLakshmi Yadlapati         return;
551*727a046cSLakshmi Yadlapati     }
552*727a046cSLakshmi Yadlapati 
553*727a046cSLakshmi Yadlapati     getValidPCIeDevicePath(
554*727a046cSLakshmi Yadlapati         pcieDeviceId, aResp,
555*727a046cSLakshmi Yadlapati         [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath,
556*727a046cSLakshmi Yadlapati                                               const std::string& service) {
557*727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
558*727a046cSLakshmi Yadlapati             aResp, pcieDevicePath, service,
559*727a046cSLakshmi Yadlapati             [aResp, pcieDeviceId, pcieFunctionId](
560*727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
561*727a046cSLakshmi Yadlapati             addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId,
562*727a046cSLakshmi Yadlapati                                             pcieFunctionId);
563*727a046cSLakshmi Yadlapati             addPCIeFunctionProperties(aResp->res, pcieFunctionId,
564*727a046cSLakshmi Yadlapati                                       pcieDevProperties);
5657e860f15SJohn Edward Broadbent             });
566*727a046cSLakshmi Yadlapati         });
567*727a046cSLakshmi Yadlapati }
568*727a046cSLakshmi Yadlapati 
569*727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
570*727a046cSLakshmi Yadlapati {
571*727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
572*727a046cSLakshmi Yadlapati         app,
573*727a046cSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
574*727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
575*727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
576*727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
577f5c9f8bdSJason M. Bills }
578f5c9f8bdSJason M. Bills 
579f5c9f8bdSJason M. Bills } // namespace redfish
580