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 3489492a15SPatrick Williams static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory"; 3594c3a10bSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> pcieDeviceInterface = { 3694c3a10bSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 37f5c9f8bdSJason M. Bills 38543f9a75SLakshmi Yadlapati static inline void handlePCIeDevicePath( 39543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 40543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 41543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths, 42543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 43543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 44543f9a75SLakshmi Yadlapati 45543f9a75SLakshmi Yadlapati { 46543f9a75SLakshmi Yadlapati for (const std::string& pcieDevicePath : pcieDevicePaths) 47543f9a75SLakshmi Yadlapati { 48543f9a75SLakshmi Yadlapati std::string pciecDeviceName = 49543f9a75SLakshmi Yadlapati sdbusplus::message::object_path(pcieDevicePath).filename(); 50543f9a75SLakshmi Yadlapati if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId) 51543f9a75SLakshmi Yadlapati { 52543f9a75SLakshmi Yadlapati continue; 53543f9a75SLakshmi Yadlapati } 54543f9a75SLakshmi Yadlapati 55543f9a75SLakshmi Yadlapati dbus::utility::getDbusObject( 56543f9a75SLakshmi Yadlapati pcieDevicePath, {}, 57543f9a75SLakshmi Yadlapati [pcieDevicePath, aResp, 58543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 59543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetObject& object) { 60543f9a75SLakshmi Yadlapati if (ec || object.empty()) 61543f9a75SLakshmi Yadlapati { 62543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error " << ec; 63543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 64543f9a75SLakshmi Yadlapati return; 65543f9a75SLakshmi Yadlapati } 66543f9a75SLakshmi Yadlapati callback(pcieDevicePath, object.begin()->first); 67543f9a75SLakshmi Yadlapati }); 68543f9a75SLakshmi Yadlapati return; 69543f9a75SLakshmi Yadlapati } 70543f9a75SLakshmi Yadlapati 71543f9a75SLakshmi Yadlapati BMCWEB_LOG_WARNING << "PCIe Device not found"; 72543f9a75SLakshmi Yadlapati messages::resourceNotFound(aResp->res, "PCIeDevice", pcieDeviceId); 73543f9a75SLakshmi Yadlapati } 74543f9a75SLakshmi Yadlapati 75543f9a75SLakshmi Yadlapati static inline void getValidPCIeDevicePath( 76543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId, 77543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 78543f9a75SLakshmi Yadlapati const std::function<void(const std::string& pcieDevicePath, 79543f9a75SLakshmi Yadlapati const std::string& service)>& callback) 80543f9a75SLakshmi Yadlapati { 81543f9a75SLakshmi Yadlapati dbus::utility::getSubTreePaths( 8294c3a10bSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 83543f9a75SLakshmi Yadlapati [pcieDeviceId, aResp, 84543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 85543f9a75SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& 86543f9a75SLakshmi Yadlapati pcieDevicePaths) { 87543f9a75SLakshmi Yadlapati if (ec) 88543f9a75SLakshmi Yadlapati { 89543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec; 90543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 91543f9a75SLakshmi Yadlapati return; 92543f9a75SLakshmi Yadlapati } 93543f9a75SLakshmi Yadlapati handlePCIeDevicePath(pcieDeviceId, aResp, pcieDevicePaths, callback); 94543f9a75SLakshmi Yadlapati return; 95543f9a75SLakshmi Yadlapati }); 96543f9a75SLakshmi Yadlapati } 97543f9a75SLakshmi Yadlapati 98b5a76932SEd Tanous static inline void 998d1b46d7Szhanghch05 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 100adbe192aSJason M. Bills const std::string& name) 101f5c9f8bdSJason M. Bills { 1027a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 10338e3d67dSLakshmi Yadlapati inventoryPath, 0, pcieDeviceInterface, 1047a1dbc48SGeorge Liu [asyncResp, name](const boost::system::error_code& ec, 105b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& 106b9d36b47SEd Tanous pcieDevicePaths) { 107f5c9f8bdSJason M. Bills if (ec) 108f5c9f8bdSJason M. Bills { 109a2730f01SAndrew Geissler BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: " 110f5c9f8bdSJason M. Bills << ec.message(); 111a2730f01SAndrew Geissler // Not an error, system just doesn't have PCIe info 112f5c9f8bdSJason M. Bills return; 113f5c9f8bdSJason M. Bills } 114adbe192aSJason M. Bills nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name]; 115f5c9f8bdSJason M. Bills pcieDeviceList = nlohmann::json::array(); 116f5c9f8bdSJason M. Bills for (const std::string& pcieDevicePath : pcieDevicePaths) 117f5c9f8bdSJason M. Bills { 1183174e4dfSEd Tanous size_t devStart = pcieDevicePath.rfind('/'); 119f5c9f8bdSJason M. Bills if (devStart == std::string::npos) 120f5c9f8bdSJason M. Bills { 121f5c9f8bdSJason M. Bills continue; 122f5c9f8bdSJason M. Bills } 123f5c9f8bdSJason M. Bills 124f5c9f8bdSJason M. Bills std::string devName = pcieDevicePath.substr(devStart + 1); 125f5c9f8bdSJason M. Bills if (devName.empty()) 126f5c9f8bdSJason M. Bills { 127f5c9f8bdSJason M. Bills continue; 128f5c9f8bdSJason M. Bills } 1291476687dSEd Tanous nlohmann::json::object_t pcieDevice; 130eddfc437SWilly Tu pcieDevice["@odata.id"] = crow::utility::urlFromPieces( 131eddfc437SWilly Tu "redfish", "v1", "Systems", "system", "PCIeDevices", devName); 132b2ba3072SPatrick Williams pcieDeviceList.emplace_back(std::move(pcieDevice)); 133f5c9f8bdSJason M. Bills } 134002d39b4SEd Tanous asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size(); 1357a1dbc48SGeorge Liu }); 136f5c9f8bdSJason M. Bills } 137f5c9f8bdSJason M. Bills 138b38fa2abSLakshmi Yadlapati static inline void handlePCIeDeviceCollectionGet( 139b38fa2abSLakshmi Yadlapati crow::App& app, const crow::Request& req, 140b38fa2abSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 141b38fa2abSLakshmi Yadlapati const std::string& systemName) 142b38fa2abSLakshmi Yadlapati { 143b38fa2abSLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 144b38fa2abSLakshmi Yadlapati { 145b38fa2abSLakshmi Yadlapati return; 146b38fa2abSLakshmi Yadlapati } 147b38fa2abSLakshmi Yadlapati if (systemName != "system") 148b38fa2abSLakshmi Yadlapati { 149b38fa2abSLakshmi Yadlapati messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 150b38fa2abSLakshmi Yadlapati return; 151b38fa2abSLakshmi Yadlapati } 152543f9a75SLakshmi Yadlapati 153b38fa2abSLakshmi Yadlapati aResp->res.addHeader(boost::beast::http::field::link, 154b38fa2abSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDeviceCollection/" 155b38fa2abSLakshmi Yadlapati "PCIeDeviceCollection.json>; rel=describedby"); 156b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = 157b38fa2abSLakshmi Yadlapati "#PCIeDeviceCollection.PCIeDeviceCollection"; 158b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = 159b38fa2abSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices"; 160b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Device Collection"; 161b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Description"] = "Collection of PCIe Devices"; 162b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Members"] = nlohmann::json::array(); 163b38fa2abSLakshmi Yadlapati aResp->res.jsonValue["Members@odata.count"] = 0; 164b38fa2abSLakshmi Yadlapati 165b38fa2abSLakshmi Yadlapati collection_util::getCollectionMembers( 166b38fa2abSLakshmi Yadlapati aResp, boost::urls::url("/redfish/v1/Systems/system/PCIeDevices"), 16794c3a10bSLakshmi Yadlapati pcieDeviceInterface); 168b38fa2abSLakshmi Yadlapati } 169b38fa2abSLakshmi Yadlapati 1707e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeDeviceCollection(App& app) 171adbe192aSJason M. Bills { 172adbe192aSJason M. Bills /** 173adbe192aSJason M. Bills * Functions triggers appropriate requests on DBus 174adbe192aSJason M. Bills */ 17522d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/") 176ed398213SEd Tanous .privileges(redfish::privileges::getPCIeDeviceCollection) 1777e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 178b38fa2abSLakshmi Yadlapati std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app))); 179f5c9f8bdSJason M. Bills } 180f5c9f8bdSJason M. Bills 1810ec8b83dSEd Tanous inline std::optional<pcie_device::PCIeTypes> 18262cd45afSSpencer Ku redfishPcieGenerationFromDbus(const std::string& generationInUse) 18362cd45afSSpencer Ku { 18462cd45afSSpencer Ku if (generationInUse == 18562cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1") 18662cd45afSSpencer Ku { 1870ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen1; 18862cd45afSSpencer Ku } 18962cd45afSSpencer Ku if (generationInUse == 19062cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2") 19162cd45afSSpencer Ku { 1920ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen2; 19362cd45afSSpencer Ku } 19462cd45afSSpencer Ku if (generationInUse == 19562cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3") 19662cd45afSSpencer Ku { 1970ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen3; 19862cd45afSSpencer Ku } 19962cd45afSSpencer Ku if (generationInUse == 20062cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4") 20162cd45afSSpencer Ku { 2020ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen4; 20362cd45afSSpencer Ku } 20462cd45afSSpencer Ku if (generationInUse == 20562cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5") 20662cd45afSSpencer Ku { 2070ec8b83dSEd Tanous return pcie_device::PCIeTypes::Gen5; 20862cd45afSSpencer Ku } 209e825cbc8SEd Tanous if (generationInUse.empty() || 210e825cbc8SEd Tanous generationInUse == 21162cd45afSSpencer Ku "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown") 21262cd45afSSpencer Ku { 2130ec8b83dSEd Tanous return pcie_device::PCIeTypes::Invalid; 21462cd45afSSpencer Ku } 21562cd45afSSpencer Ku 21662cd45afSSpencer Ku // The value is not unknown or Gen1-5, need return an internal error. 21762cd45afSSpencer Ku return std::nullopt; 21862cd45afSSpencer Ku } 21962cd45afSSpencer Ku 220*c6bb3285SLakshmi Yadlapati inline void getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 221*c6bb3285SLakshmi Yadlapati const std::string& pcieDevicePath, 222*c6bb3285SLakshmi Yadlapati const std::string& service) 223*c6bb3285SLakshmi Yadlapati { 224*c6bb3285SLakshmi Yadlapati sdbusplus::asio::getProperty<bool>( 225*c6bb3285SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 226*c6bb3285SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item", "Present", 227*c6bb3285SLakshmi Yadlapati [aResp](const boost::system::error_code& ec, const bool value) { 228*c6bb3285SLakshmi Yadlapati if (ec) 229*c6bb3285SLakshmi Yadlapati { 230*c6bb3285SLakshmi Yadlapati if (ec.value() != EBADR) 231*c6bb3285SLakshmi Yadlapati { 232*c6bb3285SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for State"; 233*c6bb3285SLakshmi Yadlapati messages::internalError(aResp->res); 234*c6bb3285SLakshmi Yadlapati } 235*c6bb3285SLakshmi Yadlapati return; 236*c6bb3285SLakshmi Yadlapati } 237*c6bb3285SLakshmi Yadlapati 238*c6bb3285SLakshmi Yadlapati if (!value) 239*c6bb3285SLakshmi Yadlapati { 240*c6bb3285SLakshmi Yadlapati aResp->res.jsonValue["Status"]["State"] = "Absent"; 241*c6bb3285SLakshmi Yadlapati } 242*c6bb3285SLakshmi Yadlapati }); 243*c6bb3285SLakshmi Yadlapati } 244*c6bb3285SLakshmi Yadlapati 245913e7732SSunnySrivastava1984 inline void getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 246913e7732SSunnySrivastava1984 const std::string& pcieDevicePath, 247913e7732SSunnySrivastava1984 const std::string& service) 248913e7732SSunnySrivastava1984 { 249913e7732SSunnySrivastava1984 sdbusplus::asio::getAllProperties( 250913e7732SSunnySrivastava1984 *crow::connections::systemBus, service, pcieDevicePath, 251913e7732SSunnySrivastava1984 "xyz.openbmc_project.Inventory.Decorator.Asset", 252913e7732SSunnySrivastava1984 [pcieDevicePath, 253913e7732SSunnySrivastava1984 aResp{aResp}](const boost::system::error_code& ec, 254913e7732SSunnySrivastava1984 const dbus::utility::DBusPropertiesMap& assetList) { 255913e7732SSunnySrivastava1984 if (ec) 256913e7732SSunnySrivastava1984 { 257913e7732SSunnySrivastava1984 if (ec.value() != EBADR) 258913e7732SSunnySrivastava1984 { 259913e7732SSunnySrivastava1984 BMCWEB_LOG_ERROR << "DBUS response error for Properties" 260913e7732SSunnySrivastava1984 << ec.value(); 261913e7732SSunnySrivastava1984 messages::internalError(aResp->res); 262913e7732SSunnySrivastava1984 } 263913e7732SSunnySrivastava1984 return; 264913e7732SSunnySrivastava1984 } 265913e7732SSunnySrivastava1984 266913e7732SSunnySrivastava1984 const std::string* manufacturer = nullptr; 267913e7732SSunnySrivastava1984 const std::string* model = nullptr; 268913e7732SSunnySrivastava1984 const std::string* partNumber = nullptr; 269913e7732SSunnySrivastava1984 const std::string* serialNumber = nullptr; 270913e7732SSunnySrivastava1984 const std::string* sparePartNumber = nullptr; 271913e7732SSunnySrivastava1984 272913e7732SSunnySrivastava1984 const bool success = sdbusplus::unpackPropertiesNoThrow( 273913e7732SSunnySrivastava1984 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer", 274913e7732SSunnySrivastava1984 manufacturer, "Model", model, "PartNumber", partNumber, 275913e7732SSunnySrivastava1984 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber); 276913e7732SSunnySrivastava1984 277913e7732SSunnySrivastava1984 if (!success) 278913e7732SSunnySrivastava1984 { 279913e7732SSunnySrivastava1984 messages::internalError(aResp->res); 280913e7732SSunnySrivastava1984 return; 281913e7732SSunnySrivastava1984 } 282913e7732SSunnySrivastava1984 283913e7732SSunnySrivastava1984 if (manufacturer != nullptr) 284913e7732SSunnySrivastava1984 { 285913e7732SSunnySrivastava1984 aResp->res.jsonValue["Manufacturer"] = *manufacturer; 286913e7732SSunnySrivastava1984 } 287913e7732SSunnySrivastava1984 if (model != nullptr) 288913e7732SSunnySrivastava1984 { 289913e7732SSunnySrivastava1984 aResp->res.jsonValue["Model"] = *model; 290913e7732SSunnySrivastava1984 } 291913e7732SSunnySrivastava1984 292913e7732SSunnySrivastava1984 if (partNumber != nullptr) 293913e7732SSunnySrivastava1984 { 294913e7732SSunnySrivastava1984 aResp->res.jsonValue["PartNumber"] = *partNumber; 295913e7732SSunnySrivastava1984 } 296913e7732SSunnySrivastava1984 297913e7732SSunnySrivastava1984 if (serialNumber != nullptr) 298913e7732SSunnySrivastava1984 { 299913e7732SSunnySrivastava1984 aResp->res.jsonValue["SerialNumber"] = *serialNumber; 300913e7732SSunnySrivastava1984 } 301913e7732SSunnySrivastava1984 302913e7732SSunnySrivastava1984 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 303913e7732SSunnySrivastava1984 { 304913e7732SSunnySrivastava1984 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 305913e7732SSunnySrivastava1984 } 306913e7732SSunnySrivastava1984 }); 307913e7732SSunnySrivastava1984 } 308913e7732SSunnySrivastava1984 309543f9a75SLakshmi Yadlapati inline void addPCIeDeviceProperties( 31035ad613dSLakshmi Yadlapati crow::Response& resp, const std::string& pcieDeviceId, 311543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 312f5c9f8bdSJason M. Bills { 313d1bde9e5SKrzysztof Grobelny const std::string* deviceType = nullptr; 314d1bde9e5SKrzysztof Grobelny const std::string* generationInUse = nullptr; 315543f9a75SLakshmi Yadlapati const int64_t* lanesInUse = nullptr; 316d1bde9e5SKrzysztof Grobelny 317d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 318543f9a75SLakshmi Yadlapati dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType", 319543f9a75SLakshmi Yadlapati deviceType, "GenerationInUse", generationInUse, "LanesInUse", 320bad2c4a9SLakshmi Yadlapati lanesInUse); 321d1bde9e5SKrzysztof Grobelny 322d1bde9e5SKrzysztof Grobelny if (!success) 323d1bde9e5SKrzysztof Grobelny { 324543f9a75SLakshmi Yadlapati messages::internalError(resp); 325d1bde9e5SKrzysztof Grobelny return; 326d1bde9e5SKrzysztof Grobelny } 327d1bde9e5SKrzysztof Grobelny 328543f9a75SLakshmi Yadlapati if (deviceType != nullptr && !deviceType->empty()) 329703f6741SMyung Bae { 330543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType; 331703f6741SMyung Bae } 332703f6741SMyung Bae 333d1bde9e5SKrzysztof Grobelny if (generationInUse != nullptr) 334d1bde9e5SKrzysztof Grobelny { 3350ec8b83dSEd Tanous std::optional<pcie_device::PCIeTypes> redfishGenerationInUse = 336d1bde9e5SKrzysztof Grobelny redfishPcieGenerationFromDbus(*generationInUse); 337543f9a75SLakshmi Yadlapati 338d1bde9e5SKrzysztof Grobelny if (!redfishGenerationInUse) 339d1bde9e5SKrzysztof Grobelny { 340543f9a75SLakshmi Yadlapati messages::internalError(resp); 341d1bde9e5SKrzysztof Grobelny return; 342d1bde9e5SKrzysztof Grobelny } 3430ec8b83dSEd Tanous if (*redfishGenerationInUse != pcie_device::PCIeTypes::Invalid) 344d1bde9e5SKrzysztof Grobelny { 345543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["PCIeType"] = 346d1bde9e5SKrzysztof Grobelny *redfishGenerationInUse; 347d1bde9e5SKrzysztof Grobelny } 348a9f68bb5STony Lee } 349d1bde9e5SKrzysztof Grobelny 350543f9a75SLakshmi Yadlapati // The default value of LanesInUse is 0, and the field will be 351543f9a75SLakshmi Yadlapati // left as off if it is a default value. 352543f9a75SLakshmi Yadlapati if (lanesInUse != nullptr && *lanesInUse != 0) 353543f9a75SLakshmi Yadlapati { 354543f9a75SLakshmi Yadlapati resp.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse; 355543f9a75SLakshmi Yadlapati } 356543f9a75SLakshmi Yadlapati 35735ad613dSLakshmi Yadlapati resp.jsonValue["PCIeFunctions"]["@odata.id"] = crow::utility::urlFromPieces( 35835ad613dSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 35935ad613dSLakshmi Yadlapati "PCIeFunctions"); 360d1bde9e5SKrzysztof Grobelny } 361d1bde9e5SKrzysztof Grobelny 362543f9a75SLakshmi Yadlapati inline void getPCIeDeviceProperties( 363543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 364543f9a75SLakshmi Yadlapati const std::string& pcieDevicePath, const std::string& service, 365543f9a75SLakshmi Yadlapati const std::function<void( 366543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback) 367d1bde9e5SKrzysztof Grobelny { 368543f9a75SLakshmi Yadlapati sdbusplus::asio::getAllProperties( 369543f9a75SLakshmi Yadlapati *crow::connections::systemBus, service, pcieDevicePath, 370543f9a75SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PCIeDevice", 371543f9a75SLakshmi Yadlapati [aResp, 372543f9a75SLakshmi Yadlapati callback](const boost::system::error_code& ec, 373543f9a75SLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 374543f9a75SLakshmi Yadlapati if (ec) 375543f9a75SLakshmi Yadlapati { 376543f9a75SLakshmi Yadlapati if (ec.value() != EBADR) 377543f9a75SLakshmi Yadlapati { 378543f9a75SLakshmi Yadlapati BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 379543f9a75SLakshmi Yadlapati messages::internalError(aResp->res); 380543f9a75SLakshmi Yadlapati } 381543f9a75SLakshmi Yadlapati return; 382543f9a75SLakshmi Yadlapati } 383543f9a75SLakshmi Yadlapati callback(pcieDevProperties); 384543f9a75SLakshmi Yadlapati }); 385d1bde9e5SKrzysztof Grobelny } 386d1bde9e5SKrzysztof Grobelny 387543f9a75SLakshmi Yadlapati inline void addPCIeDeviceCommonProperties( 388543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 389543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 390543f9a75SLakshmi Yadlapati { 391543f9a75SLakshmi Yadlapati aResp->res.addHeader( 392543f9a75SLakshmi Yadlapati boost::beast::http::field::link, 393543f9a75SLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby"); 394543f9a75SLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice"; 395543f9a75SLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 396543f9a75SLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId); 397543f9a75SLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Device"; 398543f9a75SLakshmi Yadlapati aResp->res.jsonValue["Id"] = pcieDeviceId; 399*c6bb3285SLakshmi Yadlapati aResp->res.jsonValue["Status"]["State"] = "Enabled"; 400543f9a75SLakshmi Yadlapati } 4011476687dSEd Tanous 402543f9a75SLakshmi Yadlapati inline void handlePCIeDeviceGet(App& app, const crow::Request& req, 403543f9a75SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 404543f9a75SLakshmi Yadlapati const std::string& systemName, 405543f9a75SLakshmi Yadlapati const std::string& pcieDeviceId) 406543f9a75SLakshmi Yadlapati { 407543f9a75SLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 408543f9a75SLakshmi Yadlapati { 409543f9a75SLakshmi Yadlapati return; 410543f9a75SLakshmi Yadlapati } 411543f9a75SLakshmi Yadlapati if (systemName != "system") 412543f9a75SLakshmi Yadlapati { 413543f9a75SLakshmi Yadlapati messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 414543f9a75SLakshmi Yadlapati return; 415543f9a75SLakshmi Yadlapati } 416543f9a75SLakshmi Yadlapati 417543f9a75SLakshmi Yadlapati getValidPCIeDevicePath( 418543f9a75SLakshmi Yadlapati pcieDeviceId, aResp, 419543f9a75SLakshmi Yadlapati [aResp, pcieDeviceId](const std::string& pcieDevicePath, 420543f9a75SLakshmi Yadlapati const std::string& service) { 421543f9a75SLakshmi Yadlapati addPCIeDeviceCommonProperties(aResp, pcieDeviceId); 422913e7732SSunnySrivastava1984 getPCIeDeviceAsset(aResp, pcieDevicePath, service); 423*c6bb3285SLakshmi Yadlapati getPCIeDeviceState(aResp, pcieDevicePath, service); 424543f9a75SLakshmi Yadlapati getPCIeDeviceProperties( 425543f9a75SLakshmi Yadlapati aResp, pcieDevicePath, service, 42635ad613dSLakshmi Yadlapati [aResp, pcieDeviceId]( 42735ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 42835ad613dSLakshmi Yadlapati addPCIeDeviceProperties(aResp->res, pcieDeviceId, 42935ad613dSLakshmi Yadlapati pcieDevProperties); 4307e860f15SJohn Edward Broadbent }); 431543f9a75SLakshmi Yadlapati }); 432543f9a75SLakshmi Yadlapati } 433543f9a75SLakshmi Yadlapati 434543f9a75SLakshmi Yadlapati inline void requestRoutesSystemPCIeDevice(App& app) 435543f9a75SLakshmi Yadlapati { 436543f9a75SLakshmi Yadlapati BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/") 437543f9a75SLakshmi Yadlapati .privileges(redfish::privileges::getPCIeDevice) 438543f9a75SLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 439543f9a75SLakshmi Yadlapati std::bind_front(handlePCIeDeviceGet, std::ref(app))); 440dede6a98SJason M. Bills } 441dede6a98SJason M. Bills 44235ad613dSLakshmi Yadlapati inline void addPCIeFunctionList( 44335ad613dSLakshmi Yadlapati crow::Response& res, const std::string& pcieDeviceId, 44435ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 44535ad613dSLakshmi Yadlapati { 44635ad613dSLakshmi Yadlapati nlohmann::json& pcieFunctionList = res.jsonValue["Members"]; 44735ad613dSLakshmi Yadlapati pcieFunctionList = nlohmann::json::array(); 44835ad613dSLakshmi Yadlapati static constexpr const int maxPciFunctionNum = 8; 44935ad613dSLakshmi Yadlapati 45035ad613dSLakshmi Yadlapati for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++) 45135ad613dSLakshmi Yadlapati { 45235ad613dSLakshmi Yadlapati // Check if this function exists by 45335ad613dSLakshmi Yadlapati // looking for a device ID 45489492a15SPatrick Williams std::string devIDProperty = "Function" + std::to_string(functionNum) + 45589492a15SPatrick Williams "DeviceId"; 45635ad613dSLakshmi Yadlapati const std::string* property = nullptr; 45735ad613dSLakshmi Yadlapati for (const auto& propEntry : pcieDevProperties) 45835ad613dSLakshmi Yadlapati { 45935ad613dSLakshmi Yadlapati if (propEntry.first == devIDProperty) 46035ad613dSLakshmi Yadlapati { 46135ad613dSLakshmi Yadlapati property = std::get_if<std::string>(&propEntry.second); 46235ad613dSLakshmi Yadlapati break; 46335ad613dSLakshmi Yadlapati } 46435ad613dSLakshmi Yadlapati } 46535ad613dSLakshmi Yadlapati if (property == nullptr || property->empty()) 46635ad613dSLakshmi Yadlapati { 46735ad613dSLakshmi Yadlapati continue; 46835ad613dSLakshmi Yadlapati } 46935ad613dSLakshmi Yadlapati 47035ad613dSLakshmi Yadlapati nlohmann::json::object_t pcieFunction; 47135ad613dSLakshmi Yadlapati pcieFunction["@odata.id"] = crow::utility::urlFromPieces( 47235ad613dSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 47335ad613dSLakshmi Yadlapati "PCIeFunctions", std::to_string(functionNum)); 474b2ba3072SPatrick Williams pcieFunctionList.emplace_back(std::move(pcieFunction)); 47535ad613dSLakshmi Yadlapati } 47635ad613dSLakshmi Yadlapati res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size(); 47735ad613dSLakshmi Yadlapati } 47835ad613dSLakshmi Yadlapati 47935ad613dSLakshmi Yadlapati inline void handlePCIeFunctionCollectionGet( 48035ad613dSLakshmi Yadlapati App& app, const crow::Request& req, 48135ad613dSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 48235ad613dSLakshmi Yadlapati const std::string& pcieDeviceId) 48335ad613dSLakshmi Yadlapati { 48435ad613dSLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 48535ad613dSLakshmi Yadlapati { 48635ad613dSLakshmi Yadlapati return; 48735ad613dSLakshmi Yadlapati } 48835ad613dSLakshmi Yadlapati 48935ad613dSLakshmi Yadlapati getValidPCIeDevicePath( 49035ad613dSLakshmi Yadlapati pcieDeviceId, aResp, 49135ad613dSLakshmi Yadlapati [aResp, pcieDeviceId](const std::string& pcieDevicePath, 49235ad613dSLakshmi Yadlapati const std::string& service) { 49335ad613dSLakshmi Yadlapati aResp->res.addHeader( 49435ad613dSLakshmi Yadlapati boost::beast::http::field::link, 49535ad613dSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby"); 49635ad613dSLakshmi Yadlapati aResp->res.jsonValue["@odata.type"] = 49735ad613dSLakshmi Yadlapati "#PCIeFunctionCollection.PCIeFunctionCollection"; 49835ad613dSLakshmi Yadlapati aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 49935ad613dSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 50035ad613dSLakshmi Yadlapati "PCIeFunctions"); 50135ad613dSLakshmi Yadlapati aResp->res.jsonValue["Name"] = "PCIe Function Collection"; 50235ad613dSLakshmi Yadlapati aResp->res.jsonValue["Description"] = 50335ad613dSLakshmi Yadlapati "Collection of PCIe Functions for PCIe Device " + pcieDeviceId; 50435ad613dSLakshmi Yadlapati getPCIeDeviceProperties( 50535ad613dSLakshmi Yadlapati aResp, pcieDevicePath, service, 50635ad613dSLakshmi Yadlapati [aResp, pcieDeviceId]( 50735ad613dSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 50835ad613dSLakshmi Yadlapati addPCIeFunctionList(aResp->res, pcieDeviceId, pcieDevProperties); 50935ad613dSLakshmi Yadlapati }); 51035ad613dSLakshmi Yadlapati }); 51135ad613dSLakshmi Yadlapati } 51235ad613dSLakshmi Yadlapati 5137e860f15SJohn Edward Broadbent inline void requestRoutesSystemPCIeFunctionCollection(App& app) 5147e860f15SJohn Edward Broadbent { 515dede6a98SJason M. Bills /** 516dede6a98SJason M. Bills * Functions triggers appropriate requests on DBus 517dede6a98SJason M. Bills */ 5187e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 5197e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/") 520ed398213SEd Tanous .privileges(redfish::privileges::getPCIeFunctionCollection) 521002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 52235ad613dSLakshmi Yadlapati std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app))); 5237e860f15SJohn Edward Broadbent } 5247e860f15SJohn Edward Broadbent 525727a046cSLakshmi Yadlapati inline bool validatePCIeFunctionId( 526727a046cSLakshmi Yadlapati const std::string& pcieFunctionId, 527727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 5287e860f15SJohn Edward Broadbent { 529727a046cSLakshmi Yadlapati std::string functionName = "Function" + pcieFunctionId; 530b9d36b47SEd Tanous std::string devIDProperty = functionName + "DeviceId"; 531b9d36b47SEd Tanous 532b9d36b47SEd Tanous const std::string* devIdProperty = nullptr; 533b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 534b9d36b47SEd Tanous { 535b9d36b47SEd Tanous if (property.first == devIDProperty) 536b9d36b47SEd Tanous { 537002d39b4SEd Tanous devIdProperty = std::get_if<std::string>(&property.second); 538727a046cSLakshmi Yadlapati break; 539b9d36b47SEd Tanous } 540b9d36b47SEd Tanous } 541727a046cSLakshmi Yadlapati return (devIdProperty != nullptr && !devIdProperty->empty()); 542727a046cSLakshmi Yadlapati } 543727a046cSLakshmi Yadlapati 544727a046cSLakshmi Yadlapati inline void addPCIeFunctionProperties( 545727a046cSLakshmi Yadlapati crow::Response& resp, const std::string& pcieFunctionId, 546727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) 547f5c9f8bdSJason M. Bills { 548727a046cSLakshmi Yadlapati std::string functionName = "Function" + pcieFunctionId; 549727a046cSLakshmi Yadlapati if (!validatePCIeFunctionId(pcieFunctionId, pcieDevProperties)) 550727a046cSLakshmi Yadlapati { 551727a046cSLakshmi Yadlapati messages::resourceNotFound(resp, "PCIeFunction", pcieFunctionId); 552f5c9f8bdSJason M. Bills return; 553f5c9f8bdSJason M. Bills } 554b9d36b47SEd Tanous for (const auto& property : pcieDevProperties) 555f5c9f8bdSJason M. Bills { 556b9d36b47SEd Tanous const std::string* strProperty = 557b9d36b47SEd Tanous std::get_if<std::string>(&property.second); 558727a046cSLakshmi Yadlapati 559b9d36b47SEd Tanous if (property.first == functionName + "DeviceId") 560f5c9f8bdSJason M. Bills { 561727a046cSLakshmi Yadlapati resp.jsonValue["DeviceId"] = *strProperty; 562f5c9f8bdSJason M. Bills } 563b9d36b47SEd Tanous if (property.first == functionName + "VendorId") 564f5c9f8bdSJason M. Bills { 565727a046cSLakshmi Yadlapati resp.jsonValue["VendorId"] = *strProperty; 566f5c9f8bdSJason M. Bills } 567727a046cSLakshmi Yadlapati // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus 568727a046cSLakshmi Yadlapati // property strings should be mapped correctly to ensure these 569727a046cSLakshmi Yadlapati // strings are Redfish enum values. For now just check for empty. 570b9d36b47SEd Tanous if (property.first == functionName + "FunctionType") 571f5c9f8bdSJason M. Bills { 572727a046cSLakshmi Yadlapati if (!strProperty->empty()) 573727a046cSLakshmi Yadlapati { 574727a046cSLakshmi Yadlapati resp.jsonValue["FunctionType"] = *strProperty; 575727a046cSLakshmi Yadlapati } 576f5c9f8bdSJason M. Bills } 577b9d36b47SEd Tanous if (property.first == functionName + "DeviceClass") 578f5c9f8bdSJason M. Bills { 579727a046cSLakshmi Yadlapati if (!strProperty->empty()) 580727a046cSLakshmi Yadlapati { 581727a046cSLakshmi Yadlapati resp.jsonValue["DeviceClass"] = *strProperty; 582727a046cSLakshmi Yadlapati } 583f5c9f8bdSJason M. Bills } 584b9d36b47SEd Tanous if (property.first == functionName + "ClassCode") 585f5c9f8bdSJason M. Bills { 586727a046cSLakshmi Yadlapati resp.jsonValue["ClassCode"] = *strProperty; 587f5c9f8bdSJason M. Bills } 588b9d36b47SEd Tanous if (property.first == functionName + "RevisionId") 589f5c9f8bdSJason M. Bills { 590727a046cSLakshmi Yadlapati resp.jsonValue["RevisionId"] = *strProperty; 591f5c9f8bdSJason M. Bills } 592b9d36b47SEd Tanous if (property.first == functionName + "SubsystemId") 593b9d36b47SEd Tanous { 594727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemId"] = *strProperty; 595b9d36b47SEd Tanous } 596002d39b4SEd Tanous if (property.first == functionName + "SubsystemVendorId") 597f5c9f8bdSJason M. Bills { 598727a046cSLakshmi Yadlapati resp.jsonValue["SubsystemVendorId"] = *strProperty; 599b9d36b47SEd Tanous } 600f5c9f8bdSJason M. Bills } 601727a046cSLakshmi Yadlapati } 602727a046cSLakshmi Yadlapati 603727a046cSLakshmi Yadlapati inline void addPCIeFunctionCommonProperties(crow::Response& resp, 604727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 605727a046cSLakshmi Yadlapati const std::string& pcieFunctionId) 606727a046cSLakshmi Yadlapati { 607727a046cSLakshmi Yadlapati resp.addHeader( 608727a046cSLakshmi Yadlapati boost::beast::http::field::link, 609727a046cSLakshmi Yadlapati "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby"); 610727a046cSLakshmi Yadlapati resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction"; 611727a046cSLakshmi Yadlapati resp.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 612727a046cSLakshmi Yadlapati "redfish", "v1", "Systems", "system", "PCIeDevices", pcieDeviceId, 613727a046cSLakshmi Yadlapati "PCIeFunctions", pcieFunctionId); 614727a046cSLakshmi Yadlapati resp.jsonValue["Name"] = "PCIe Function"; 615727a046cSLakshmi Yadlapati resp.jsonValue["Id"] = pcieFunctionId; 616727a046cSLakshmi Yadlapati resp.jsonValue["FunctionId"] = std::stoi(pcieFunctionId); 617727a046cSLakshmi Yadlapati resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = 618727a046cSLakshmi Yadlapati crow::utility::urlFromPieces("redfish", "v1", "Systems", "system", 619727a046cSLakshmi Yadlapati "PCIeDevices", pcieDeviceId); 620727a046cSLakshmi Yadlapati } 621727a046cSLakshmi Yadlapati 622727a046cSLakshmi Yadlapati inline void 623727a046cSLakshmi Yadlapati handlePCIeFunctionGet(App& app, const crow::Request& req, 624727a046cSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& aResp, 625727a046cSLakshmi Yadlapati const std::string& pcieDeviceId, 626727a046cSLakshmi Yadlapati const std::string& pcieFunctionId) 627727a046cSLakshmi Yadlapati { 628727a046cSLakshmi Yadlapati if (!redfish::setUpRedfishRoute(app, req, aResp)) 629727a046cSLakshmi Yadlapati { 630727a046cSLakshmi Yadlapati return; 631727a046cSLakshmi Yadlapati } 632727a046cSLakshmi Yadlapati 633727a046cSLakshmi Yadlapati getValidPCIeDevicePath( 634727a046cSLakshmi Yadlapati pcieDeviceId, aResp, 635727a046cSLakshmi Yadlapati [aResp, pcieDeviceId, pcieFunctionId](const std::string& pcieDevicePath, 636727a046cSLakshmi Yadlapati const std::string& service) { 637727a046cSLakshmi Yadlapati getPCIeDeviceProperties( 638727a046cSLakshmi Yadlapati aResp, pcieDevicePath, service, 639727a046cSLakshmi Yadlapati [aResp, pcieDeviceId, pcieFunctionId]( 640727a046cSLakshmi Yadlapati const dbus::utility::DBusPropertiesMap& pcieDevProperties) { 641727a046cSLakshmi Yadlapati addPCIeFunctionCommonProperties(aResp->res, pcieDeviceId, 642727a046cSLakshmi Yadlapati pcieFunctionId); 643727a046cSLakshmi Yadlapati addPCIeFunctionProperties(aResp->res, pcieFunctionId, 644727a046cSLakshmi Yadlapati pcieDevProperties); 6457e860f15SJohn Edward Broadbent }); 646727a046cSLakshmi Yadlapati }); 647727a046cSLakshmi Yadlapati } 648727a046cSLakshmi Yadlapati 649727a046cSLakshmi Yadlapati inline void requestRoutesSystemPCIeFunction(App& app) 650727a046cSLakshmi Yadlapati { 651727a046cSLakshmi Yadlapati BMCWEB_ROUTE( 652727a046cSLakshmi Yadlapati app, 653727a046cSLakshmi Yadlapati "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/") 654727a046cSLakshmi Yadlapati .privileges(redfish::privileges::getPCIeFunction) 655727a046cSLakshmi Yadlapati .methods(boost::beast::http::verb::get)( 656727a046cSLakshmi Yadlapati std::bind_front(handlePCIeFunctionGet, std::ref(app))); 657f5c9f8bdSJason M. Bills } 658f5c9f8bdSJason M. Bills 659f5c9f8bdSJason M. Bills } // namespace redfish 660