xref: /openbmc/bmcweb/features/redfish/lib/pcie.hpp (revision c49c329d2ccf45859030844eb205a8476148fb25)
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"
213ccb3adbSEd Tanous #include "query.hpp"
223ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
23b38fa2abSLakshmi Yadlapati #include "utils/collection.hpp"
243ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
25*c49c329dSLakshmi Yadlapati #include "utils/pcie_util.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,
41ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
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, {},
58ac106bf6SEd Tanous             [pcieDevicePath, asyncResp,
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;
64ac106bf6SEd Tanous                 messages::internalError(asyncResp->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";
73ac106bf6SEd Tanous     messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
74543f9a75SLakshmi Yadlapati }
75543f9a75SLakshmi Yadlapati 
76543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath(
77543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId,
78ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
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,
84ac106bf6SEd Tanous         [pcieDeviceId, asyncResp,
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;
91ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
92543f9a75SLakshmi Yadlapati             return;
93543f9a75SLakshmi Yadlapati         }
94ac106bf6SEd Tanous         handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
95ac106bf6SEd Tanous                              callback);
96543f9a75SLakshmi Yadlapati         return;
97543f9a75SLakshmi Yadlapati         });
98543f9a75SLakshmi Yadlapati }
99543f9a75SLakshmi Yadlapati 
100b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet(
101b38fa2abSLakshmi Yadlapati     crow::App& app, const crow::Request& req,
102ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
103b38fa2abSLakshmi Yadlapati     const std::string& systemName)
104b38fa2abSLakshmi Yadlapati {
105ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
106b38fa2abSLakshmi Yadlapati     {
107b38fa2abSLakshmi Yadlapati         return;
108b38fa2abSLakshmi Yadlapati     }
109b38fa2abSLakshmi Yadlapati     if (systemName != "system")
110b38fa2abSLakshmi Yadlapati     {
111ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
112ac106bf6SEd Tanous                                    systemName);
113b38fa2abSLakshmi Yadlapati         return;
114b38fa2abSLakshmi Yadlapati     }
115543f9a75SLakshmi Yadlapati 
116ac106bf6SEd Tanous     asyncResp->res.addHeader(boost::beast::http::field::link,
117b38fa2abSLakshmi Yadlapati                              "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
118b38fa2abSLakshmi Yadlapati                              "PCIeDeviceCollection.json>; rel=describedby");
119ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
120b38fa2abSLakshmi Yadlapati         "#PCIeDeviceCollection.PCIeDeviceCollection";
121ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
122b38fa2abSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices";
123ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
124ac106bf6SEd Tanous     asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
125ac106bf6SEd Tanous     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
126ac106bf6SEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = 0;
127b38fa2abSLakshmi Yadlapati 
128b38fa2abSLakshmi Yadlapati     collection_util::getCollectionMembers(
129ac106bf6SEd Tanous         asyncResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"),
13094c3a10bSLakshmi Yadlapati         pcieDeviceInterface);
131b38fa2abSLakshmi Yadlapati }
132b38fa2abSLakshmi Yadlapati 
1337e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app)
134adbe192aSJason M. Bills {
135adbe192aSJason M. Bills     /**
136adbe192aSJason M. Bills      * Functions triggers appropriate requests on DBus
137adbe192aSJason M. Bills      */
13822d268cbSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
139ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeDeviceCollection)
1407e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
141b38fa2abSLakshmi Yadlapati             std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
142f5c9f8bdSJason M. Bills }
143f5c9f8bdSJason M. Bills 
144ac106bf6SEd Tanous inline void
145ac106bf6SEd Tanous     getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
146c6bb3285SLakshmi Yadlapati                        const std::string& pcieDevicePath,
147c6bb3285SLakshmi Yadlapati                        const std::string& service)
148c6bb3285SLakshmi Yadlapati {
149c6bb3285SLakshmi Yadlapati     sdbusplus::asio::getProperty<bool>(
150c6bb3285SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
151c6bb3285SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item", "Present",
152ac106bf6SEd Tanous         [asyncResp](const boost::system::error_code& ec, const bool value) {
153c6bb3285SLakshmi Yadlapati         if (ec)
154c6bb3285SLakshmi Yadlapati         {
155c6bb3285SLakshmi Yadlapati             if (ec.value() != EBADR)
156c6bb3285SLakshmi Yadlapati             {
157c6bb3285SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for State";
158ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
159c6bb3285SLakshmi Yadlapati             }
160c6bb3285SLakshmi Yadlapati             return;
161c6bb3285SLakshmi Yadlapati         }
162c6bb3285SLakshmi Yadlapati 
163c6bb3285SLakshmi Yadlapati         if (!value)
164c6bb3285SLakshmi Yadlapati         {
165ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Absent";
166c6bb3285SLakshmi Yadlapati         }
167c6bb3285SLakshmi Yadlapati         });
168c6bb3285SLakshmi Yadlapati }
169c6bb3285SLakshmi Yadlapati 
170ac106bf6SEd Tanous inline void
171ac106bf6SEd Tanous     getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
172913e7732SSunnySrivastava1984                        const std::string& pcieDevicePath,
173913e7732SSunnySrivastava1984                        const std::string& service)
174913e7732SSunnySrivastava1984 {
175913e7732SSunnySrivastava1984     sdbusplus::asio::getAllProperties(
176913e7732SSunnySrivastava1984         *crow::connections::systemBus, service, pcieDevicePath,
177913e7732SSunnySrivastava1984         "xyz.openbmc_project.Inventory.Decorator.Asset",
178ac106bf6SEd Tanous         [pcieDevicePath, asyncResp{asyncResp}](
179ac106bf6SEd Tanous             const boost::system::error_code& ec,
180913e7732SSunnySrivastava1984             const dbus::utility::DBusPropertiesMap& assetList) {
181913e7732SSunnySrivastava1984         if (ec)
182913e7732SSunnySrivastava1984         {
183913e7732SSunnySrivastava1984             if (ec.value() != EBADR)
184913e7732SSunnySrivastava1984             {
185913e7732SSunnySrivastava1984                 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
186913e7732SSunnySrivastava1984                                  << ec.value();
187ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
188913e7732SSunnySrivastava1984             }
189913e7732SSunnySrivastava1984             return;
190913e7732SSunnySrivastava1984         }
191913e7732SSunnySrivastava1984 
192913e7732SSunnySrivastava1984         const std::string* manufacturer = nullptr;
193913e7732SSunnySrivastava1984         const std::string* model = nullptr;
194913e7732SSunnySrivastava1984         const std::string* partNumber = nullptr;
195913e7732SSunnySrivastava1984         const std::string* serialNumber = nullptr;
196913e7732SSunnySrivastava1984         const std::string* sparePartNumber = nullptr;
197913e7732SSunnySrivastava1984 
198913e7732SSunnySrivastava1984         const bool success = sdbusplus::unpackPropertiesNoThrow(
199913e7732SSunnySrivastava1984             dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
200913e7732SSunnySrivastava1984             manufacturer, "Model", model, "PartNumber", partNumber,
201913e7732SSunnySrivastava1984             "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
202913e7732SSunnySrivastava1984 
203913e7732SSunnySrivastava1984         if (!success)
204913e7732SSunnySrivastava1984         {
205ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
206913e7732SSunnySrivastava1984             return;
207913e7732SSunnySrivastava1984         }
208913e7732SSunnySrivastava1984 
209913e7732SSunnySrivastava1984         if (manufacturer != nullptr)
210913e7732SSunnySrivastava1984         {
211ac106bf6SEd Tanous             asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
212913e7732SSunnySrivastava1984         }
213913e7732SSunnySrivastava1984         if (model != nullptr)
214913e7732SSunnySrivastava1984         {
215ac106bf6SEd Tanous             asyncResp->res.jsonValue["Model"] = *model;
216913e7732SSunnySrivastava1984         }
217913e7732SSunnySrivastava1984 
218913e7732SSunnySrivastava1984         if (partNumber != nullptr)
219913e7732SSunnySrivastava1984         {
220ac106bf6SEd Tanous             asyncResp->res.jsonValue["PartNumber"] = *partNumber;
221913e7732SSunnySrivastava1984         }
222913e7732SSunnySrivastava1984 
223913e7732SSunnySrivastava1984         if (serialNumber != nullptr)
224913e7732SSunnySrivastava1984         {
225ac106bf6SEd Tanous             asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
226913e7732SSunnySrivastava1984         }
227913e7732SSunnySrivastava1984 
228913e7732SSunnySrivastava1984         if (sparePartNumber != nullptr && !sparePartNumber->empty())
229913e7732SSunnySrivastava1984         {
230ac106bf6SEd Tanous             asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
231913e7732SSunnySrivastava1984         }
232913e7732SSunnySrivastava1984         });
233913e7732SSunnySrivastava1984 }
234913e7732SSunnySrivastava1984 
235543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties(
23635ad613dSLakshmi Yadlapati     crow::Response& resp, const std::string& pcieDeviceId,
237543f9a75SLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
238f5c9f8bdSJason M. Bills {
239d1bde9e5SKrzysztof Grobelny     const std::string* deviceType = nullptr;
240d1bde9e5SKrzysztof Grobelny     const std::string* generationInUse = nullptr;
241543f9a75SLakshmi Yadlapati     const int64_t* lanesInUse = nullptr;
242d1bde9e5SKrzysztof Grobelny 
243d1bde9e5SKrzysztof Grobelny     const bool success = sdbusplus::unpackPropertiesNoThrow(
244543f9a75SLakshmi Yadlapati         dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
245543f9a75SLakshmi Yadlapati         deviceType, "GenerationInUse", generationInUse, "LanesInUse",
246bad2c4a9SLakshmi Yadlapati         lanesInUse);
247d1bde9e5SKrzysztof Grobelny 
248d1bde9e5SKrzysztof Grobelny     if (!success)
249d1bde9e5SKrzysztof Grobelny     {
250543f9a75SLakshmi Yadlapati         messages::internalError(resp);
251d1bde9e5SKrzysztof Grobelny         return;
252d1bde9e5SKrzysztof Grobelny     }
253d1bde9e5SKrzysztof Grobelny 
254543f9a75SLakshmi Yadlapati     if (deviceType != nullptr && !deviceType->empty())
255703f6741SMyung Bae     {
256543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
257703f6741SMyung Bae     }
258703f6741SMyung Bae 
259d1bde9e5SKrzysztof Grobelny     if (generationInUse != nullptr)
260d1bde9e5SKrzysztof Grobelny     {
2610ec8b83dSEd Tanous         std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
262*c49c329dSLakshmi Yadlapati             pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
263543f9a75SLakshmi Yadlapati 
264d1bde9e5SKrzysztof Grobelny         if (!redfishGenerationInUse)
265d1bde9e5SKrzysztof Grobelny         {
266543f9a75SLakshmi Yadlapati             messages::internalError(resp);
267d1bde9e5SKrzysztof Grobelny             return;
268d1bde9e5SKrzysztof Grobelny         }
2690ec8b83dSEd Tanous         if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid)
270d1bde9e5SKrzysztof Grobelny         {
271543f9a75SLakshmi Yadlapati             resp.jsonValue["PCIeInterface"]["PCIeType"] =
272d1bde9e5SKrzysztof Grobelny                 *redfishGenerationInUse;
273d1bde9e5SKrzysztof Grobelny         }
274a9f68bb5STony Lee     }
275d1bde9e5SKrzysztof Grobelny 
276543f9a75SLakshmi Yadlapati     // The default value of LanesInUse is 0, and the field will be
277543f9a75SLakshmi Yadlapati     // left as off if it is a default value.
278543f9a75SLakshmi Yadlapati     if (lanesInUse != nullptr && *lanesInUse != 0)
279543f9a75SLakshmi Yadlapati     {
280543f9a75SLakshmi Yadlapati         resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
281543f9a75SLakshmi Yadlapati     }
282543f9a75SLakshmi Yadlapati 
283ef4c65b7SEd Tanous     resp.jsonValue["PCIeFunctions"]["@odata.id"] = boost::urls::format(
284ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
285ef4c65b7SEd Tanous         pcieDeviceId);
286d1bde9e5SKrzysztof Grobelny }
287d1bde9e5SKrzysztof Grobelny 
288543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties(
289ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
290543f9a75SLakshmi Yadlapati     const std::string& pcieDevicePath, const std::string& service,
291543f9a75SLakshmi Yadlapati     const std::function<void(
292543f9a75SLakshmi Yadlapati         const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
293d1bde9e5SKrzysztof Grobelny {
294543f9a75SLakshmi Yadlapati     sdbusplus::asio::getAllProperties(
295543f9a75SLakshmi Yadlapati         *crow::connections::systemBus, service, pcieDevicePath,
296543f9a75SLakshmi Yadlapati         "xyz.openbmc_project.Inventory.Item.PCIeDevice",
297ac106bf6SEd Tanous         [asyncResp,
298543f9a75SLakshmi Yadlapati          callback](const boost::system::error_code& ec,
299543f9a75SLakshmi Yadlapati                    const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
300543f9a75SLakshmi Yadlapati         if (ec)
301543f9a75SLakshmi Yadlapati         {
302543f9a75SLakshmi Yadlapati             if (ec.value() != EBADR)
303543f9a75SLakshmi Yadlapati             {
304543f9a75SLakshmi Yadlapati                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
305ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
306543f9a75SLakshmi Yadlapati             }
307543f9a75SLakshmi Yadlapati             return;
308543f9a75SLakshmi Yadlapati         }
309543f9a75SLakshmi Yadlapati         callback(pcieDevProperties);
310543f9a75SLakshmi Yadlapati         });
311d1bde9e5SKrzysztof Grobelny }
312d1bde9e5SKrzysztof Grobelny 
313543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties(
314ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
315543f9a75SLakshmi Yadlapati     const std::string& pcieDeviceId)
316543f9a75SLakshmi Yadlapati {
317ac106bf6SEd Tanous     asyncResp->res.addHeader(
318543f9a75SLakshmi Yadlapati         boost::beast::http::field::link,
319543f9a75SLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
320ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
321ac106bf6SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
322ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
323ac106bf6SEd Tanous     asyncResp->res.jsonValue["Name"] = "PCIe Device";
324ac106bf6SEd Tanous     asyncResp->res.jsonValue["Id"] = pcieDeviceId;
325ac106bf6SEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
326543f9a75SLakshmi Yadlapati }
3271476687dSEd Tanous 
328ac106bf6SEd Tanous inline void
329ac106bf6SEd Tanous     handlePCIeDeviceGet(App& app, const crow::Request& req,
330ac106bf6SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
331543f9a75SLakshmi Yadlapati                         const std::string& systemName,
332543f9a75SLakshmi Yadlapati                         const std::string& pcieDeviceId)
333543f9a75SLakshmi Yadlapati {
334ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
335543f9a75SLakshmi Yadlapati     {
336543f9a75SLakshmi Yadlapati         return;
337543f9a75SLakshmi Yadlapati     }
338543f9a75SLakshmi Yadlapati     if (systemName != "system")
339543f9a75SLakshmi Yadlapati     {
340ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
341ac106bf6SEd Tanous                                    systemName);
342543f9a75SLakshmi Yadlapati         return;
343543f9a75SLakshmi Yadlapati     }
344543f9a75SLakshmi Yadlapati 
345543f9a75SLakshmi Yadlapati     getValidPCIeDevicePath(
346ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
347ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
348543f9a75SLakshmi Yadlapati                                   const std::string& service) {
349ac106bf6SEd Tanous         addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
350ac106bf6SEd Tanous         getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
351ac106bf6SEd Tanous         getPCIeDeviceState(asyncResp, pcieDevicePath, service);
352543f9a75SLakshmi Yadlapati         getPCIeDeviceProperties(
353ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
354ac106bf6SEd Tanous             [asyncResp, pcieDeviceId](
35535ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
356ac106bf6SEd Tanous             addPCIeDeviceProperties(asyncResp->res, pcieDeviceId,
35735ad613dSLakshmi Yadlapati                                     pcieDevProperties);
3587e860f15SJohn Edward Broadbent             });
359543f9a75SLakshmi Yadlapati         });
360543f9a75SLakshmi Yadlapati }
361543f9a75SLakshmi Yadlapati 
362543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app)
363543f9a75SLakshmi Yadlapati {
364543f9a75SLakshmi Yadlapati     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
365543f9a75SLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeDevice)
366543f9a75SLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
367543f9a75SLakshmi Yadlapati             std::bind_front(handlePCIeDeviceGet, std::ref(app)));
368dede6a98SJason M. Bills }
369dede6a98SJason M. Bills 
37035ad613dSLakshmi Yadlapati inline void addPCIeFunctionList(
37135ad613dSLakshmi Yadlapati     crow::Response& res, const std::string& pcieDeviceId,
37235ad613dSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
37335ad613dSLakshmi Yadlapati {
37435ad613dSLakshmi Yadlapati     nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
37535ad613dSLakshmi Yadlapati     pcieFunctionList = nlohmann::json::array();
37635ad613dSLakshmi Yadlapati     static constexpr const int maxPciFunctionNum = 8;
37735ad613dSLakshmi Yadlapati 
37835ad613dSLakshmi Yadlapati     for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
37935ad613dSLakshmi Yadlapati     {
38035ad613dSLakshmi Yadlapati         // Check if this function exists by
38135ad613dSLakshmi Yadlapati         // looking for a device ID
38289492a15SPatrick Williams         std::string devIDProperty = "Function" + std::to_string(functionNum) +
38389492a15SPatrick Williams                                     "DeviceId";
38435ad613dSLakshmi Yadlapati         const std::string* property = nullptr;
38535ad613dSLakshmi Yadlapati         for (const auto& propEntry : pcieDevProperties)
38635ad613dSLakshmi Yadlapati         {
38735ad613dSLakshmi Yadlapati             if (propEntry.first == devIDProperty)
38835ad613dSLakshmi Yadlapati             {
38935ad613dSLakshmi Yadlapati                 property = std::get_if<std::string>(&propEntry.second);
39035ad613dSLakshmi Yadlapati                 break;
39135ad613dSLakshmi Yadlapati             }
39235ad613dSLakshmi Yadlapati         }
39335ad613dSLakshmi Yadlapati         if (property == nullptr || property->empty())
39435ad613dSLakshmi Yadlapati         {
39535ad613dSLakshmi Yadlapati             continue;
39635ad613dSLakshmi Yadlapati         }
39735ad613dSLakshmi Yadlapati 
39835ad613dSLakshmi Yadlapati         nlohmann::json::object_t pcieFunction;
399ef4c65b7SEd Tanous         pcieFunction["@odata.id"] = boost::urls::format(
400ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
401ef4c65b7SEd Tanous             pcieDeviceId, std::to_string(functionNum));
402b2ba3072SPatrick Williams         pcieFunctionList.emplace_back(std::move(pcieFunction));
40335ad613dSLakshmi Yadlapati     }
40435ad613dSLakshmi Yadlapati     res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
40535ad613dSLakshmi Yadlapati }
40635ad613dSLakshmi Yadlapati 
40735ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet(
40835ad613dSLakshmi Yadlapati     App& app, const crow::Request& req,
409ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
41035ad613dSLakshmi Yadlapati     const std::string& pcieDeviceId)
41135ad613dSLakshmi Yadlapati {
412ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
41335ad613dSLakshmi Yadlapati     {
41435ad613dSLakshmi Yadlapati         return;
41535ad613dSLakshmi Yadlapati     }
41635ad613dSLakshmi Yadlapati 
41735ad613dSLakshmi Yadlapati     getValidPCIeDevicePath(
418ac106bf6SEd Tanous         pcieDeviceId, asyncResp,
419ac106bf6SEd Tanous         [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
42035ad613dSLakshmi Yadlapati                                   const std::string& service) {
421ac106bf6SEd Tanous         asyncResp->res.addHeader(
42235ad613dSLakshmi Yadlapati             boost::beast::http::field::link,
42335ad613dSLakshmi Yadlapati             "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
424ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
42535ad613dSLakshmi Yadlapati             "#PCIeFunctionCollection.PCIeFunctionCollection";
426ac106bf6SEd Tanous         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
427ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
428ef4c65b7SEd Tanous             pcieDeviceId);
429ac106bf6SEd Tanous         asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
430ac106bf6SEd Tanous         asyncResp->res.jsonValue["Description"] =
43135ad613dSLakshmi Yadlapati             "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
43235ad613dSLakshmi Yadlapati         getPCIeDeviceProperties(
433ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
434ac106bf6SEd Tanous             [asyncResp, pcieDeviceId](
43535ad613dSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
436ac106bf6SEd Tanous             addPCIeFunctionList(asyncResp->res, pcieDeviceId,
437ac106bf6SEd Tanous                                 pcieDevProperties);
43835ad613dSLakshmi Yadlapati             });
43935ad613dSLakshmi Yadlapati         });
44035ad613dSLakshmi Yadlapati }
44135ad613dSLakshmi Yadlapati 
4427e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app)
4437e860f15SJohn Edward Broadbent {
444dede6a98SJason M. Bills     /**
445dede6a98SJason M. Bills      * Functions triggers appropriate requests on DBus
446dede6a98SJason M. Bills      */
4477e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
4487e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
449ed398213SEd Tanous         .privileges(redfish::privileges::getPCIeFunctionCollection)
450002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
45135ad613dSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
4527e860f15SJohn Edward Broadbent }
4537e860f15SJohn Edward Broadbent 
454727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId(
455d5e74b80SMyung Bae     uint64_t pcieFunctionId,
456727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
4577e860f15SJohn Edward Broadbent {
458d5e74b80SMyung Bae     std::string functionName = "Function" + std::to_string(pcieFunctionId);
459b9d36b47SEd Tanous     std::string devIDProperty = functionName + "DeviceId";
460b9d36b47SEd Tanous 
461b9d36b47SEd Tanous     const std::string* devIdProperty = nullptr;
462b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
463b9d36b47SEd Tanous     {
464b9d36b47SEd Tanous         if (property.first == devIDProperty)
465b9d36b47SEd Tanous         {
466002d39b4SEd Tanous             devIdProperty = std::get_if<std::string>(&property.second);
467727a046cSLakshmi Yadlapati             break;
468b9d36b47SEd Tanous         }
469b9d36b47SEd Tanous     }
470727a046cSLakshmi Yadlapati     return (devIdProperty != nullptr && !devIdProperty->empty());
471727a046cSLakshmi Yadlapati }
472727a046cSLakshmi Yadlapati 
473727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties(
474e14742caSEd Tanous     crow::Response& resp, uint64_t pcieFunctionId,
475727a046cSLakshmi Yadlapati     const dbus::utility::DBusPropertiesMap& pcieDevProperties)
476f5c9f8bdSJason M. Bills {
477e14742caSEd Tanous     std::string functionName = "Function" + std::to_string(pcieFunctionId);
478b9d36b47SEd Tanous     for (const auto& property : pcieDevProperties)
479f5c9f8bdSJason M. Bills     {
480b9d36b47SEd Tanous         const std::string* strProperty =
481b9d36b47SEd Tanous             std::get_if<std::string>(&property.second);
482727a046cSLakshmi Yadlapati 
483b9d36b47SEd Tanous         if (property.first == functionName + "DeviceId")
484f5c9f8bdSJason M. Bills         {
485727a046cSLakshmi Yadlapati             resp.jsonValue["DeviceId"] = *strProperty;
486f5c9f8bdSJason M. Bills         }
487b9d36b47SEd Tanous         if (property.first == functionName + "VendorId")
488f5c9f8bdSJason M. Bills         {
489727a046cSLakshmi Yadlapati             resp.jsonValue["VendorId"] = *strProperty;
490f5c9f8bdSJason M. Bills         }
491727a046cSLakshmi Yadlapati         // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
492727a046cSLakshmi Yadlapati         // property strings should be mapped correctly to ensure these
493727a046cSLakshmi Yadlapati         // strings are Redfish enum values. For now just check for empty.
494b9d36b47SEd Tanous         if (property.first == functionName + "FunctionType")
495f5c9f8bdSJason M. Bills         {
496727a046cSLakshmi Yadlapati             if (!strProperty->empty())
497727a046cSLakshmi Yadlapati             {
498727a046cSLakshmi Yadlapati                 resp.jsonValue["FunctionType"] = *strProperty;
499727a046cSLakshmi Yadlapati             }
500f5c9f8bdSJason M. Bills         }
501b9d36b47SEd Tanous         if (property.first == functionName + "DeviceClass")
502f5c9f8bdSJason M. Bills         {
503727a046cSLakshmi Yadlapati             if (!strProperty->empty())
504727a046cSLakshmi Yadlapati             {
505727a046cSLakshmi Yadlapati                 resp.jsonValue["DeviceClass"] = *strProperty;
506727a046cSLakshmi Yadlapati             }
507f5c9f8bdSJason M. Bills         }
508b9d36b47SEd Tanous         if (property.first == functionName + "ClassCode")
509f5c9f8bdSJason M. Bills         {
510727a046cSLakshmi Yadlapati             resp.jsonValue["ClassCode"] = *strProperty;
511f5c9f8bdSJason M. Bills         }
512b9d36b47SEd Tanous         if (property.first == functionName + "RevisionId")
513f5c9f8bdSJason M. Bills         {
514727a046cSLakshmi Yadlapati             resp.jsonValue["RevisionId"] = *strProperty;
515f5c9f8bdSJason M. Bills         }
516b9d36b47SEd Tanous         if (property.first == functionName + "SubsystemId")
517b9d36b47SEd Tanous         {
518727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemId"] = *strProperty;
519b9d36b47SEd Tanous         }
520002d39b4SEd Tanous         if (property.first == functionName + "SubsystemVendorId")
521f5c9f8bdSJason M. Bills         {
522727a046cSLakshmi Yadlapati             resp.jsonValue["SubsystemVendorId"] = *strProperty;
523b9d36b47SEd Tanous         }
524f5c9f8bdSJason M. Bills     }
525727a046cSLakshmi Yadlapati }
526727a046cSLakshmi Yadlapati 
527727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp,
528727a046cSLakshmi Yadlapati                                             const std::string& pcieDeviceId,
529e14742caSEd Tanous                                             uint64_t pcieFunctionId)
530727a046cSLakshmi Yadlapati {
531727a046cSLakshmi Yadlapati     resp.addHeader(
532727a046cSLakshmi Yadlapati         boost::beast::http::field::link,
533727a046cSLakshmi Yadlapati         "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
534727a046cSLakshmi Yadlapati     resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
535ef4c65b7SEd Tanous     resp.jsonValue["@odata.id"] = boost::urls::format(
536ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
537ef4c65b7SEd Tanous         pcieDeviceId, pcieFunctionId);
538727a046cSLakshmi Yadlapati     resp.jsonValue["Name"] = "PCIe Function";
539e14742caSEd Tanous     resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
540e14742caSEd Tanous     resp.jsonValue["FunctionId"] = pcieFunctionId;
541ef4c65b7SEd Tanous     resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
542ef4c65b7SEd Tanous         "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
543727a046cSLakshmi Yadlapati }
544727a046cSLakshmi Yadlapati 
545727a046cSLakshmi Yadlapati inline void
546727a046cSLakshmi Yadlapati     handlePCIeFunctionGet(App& app, const crow::Request& req,
547ac106bf6SEd Tanous                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
548727a046cSLakshmi Yadlapati                           const std::string& pcieDeviceId,
549e14742caSEd Tanous                           const std::string& pcieFunctionIdStr)
550727a046cSLakshmi Yadlapati {
551ac106bf6SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
552727a046cSLakshmi Yadlapati     {
553727a046cSLakshmi Yadlapati         return;
554727a046cSLakshmi Yadlapati     }
555e14742caSEd Tanous     uint64_t pcieFunctionId = 0;
556e14742caSEd Tanous     std::from_chars_result result = std::from_chars(
557e14742caSEd Tanous         &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
558e14742caSEd Tanous     if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
559e14742caSEd Tanous     {
560ac106bf6SEd Tanous         messages::resourceNotFound(asyncResp->res, "PCIeFunction",
561e14742caSEd Tanous                                    pcieFunctionIdStr);
562e14742caSEd Tanous         return;
563e14742caSEd Tanous     }
564727a046cSLakshmi Yadlapati 
565ac106bf6SEd Tanous     getValidPCIeDevicePath(pcieDeviceId, asyncResp,
566ac106bf6SEd Tanous                            [asyncResp, pcieDeviceId,
567ac106bf6SEd Tanous                             pcieFunctionId](const std::string& pcieDevicePath,
568727a046cSLakshmi Yadlapati                                             const std::string& service) {
569727a046cSLakshmi Yadlapati         getPCIeDeviceProperties(
570ac106bf6SEd Tanous             asyncResp, pcieDevicePath, service,
571ac106bf6SEd Tanous             [asyncResp, pcieDeviceId, pcieFunctionId](
572727a046cSLakshmi Yadlapati                 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
573ac106bf6SEd Tanous             addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
574727a046cSLakshmi Yadlapati                                             pcieFunctionId);
575ac106bf6SEd Tanous             addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
576727a046cSLakshmi Yadlapati                                       pcieDevProperties);
5777e860f15SJohn Edward Broadbent             });
578727a046cSLakshmi Yadlapati     });
579727a046cSLakshmi Yadlapati }
580727a046cSLakshmi Yadlapati 
581727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app)
582727a046cSLakshmi Yadlapati {
583727a046cSLakshmi Yadlapati     BMCWEB_ROUTE(
584727a046cSLakshmi Yadlapati         app,
585727a046cSLakshmi Yadlapati         "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
586727a046cSLakshmi Yadlapati         .privileges(redfish::privileges::getPCIeFunction)
587727a046cSLakshmi Yadlapati         .methods(boost::beast::http::verb::get)(
588727a046cSLakshmi Yadlapati             std::bind_front(handlePCIeFunctionGet, std::ref(app)));
589f5c9f8bdSJason M. Bills }
590f5c9f8bdSJason M. Bills 
591f5c9f8bdSJason M. Bills } // namespace redfish
592