1ac6a4445SGunnar Mills /* 2ac6a4445SGunnar Mills // Copyright (c) 2018 Intel Corporation 3ac6a4445SGunnar Mills // 4ac6a4445SGunnar Mills // Licensed under the Apache License, Version 2.0 (the "License"); 5ac6a4445SGunnar Mills // you may not use this file except in compliance with the License. 6ac6a4445SGunnar Mills // You may obtain a copy of the License at 7ac6a4445SGunnar Mills // 8ac6a4445SGunnar Mills // http://www.apache.org/licenses/LICENSE-2.0 9ac6a4445SGunnar Mills // 10ac6a4445SGunnar Mills // Unless required by applicable law or agreed to in writing, software 11ac6a4445SGunnar Mills // distributed under the License is distributed on an "AS IS" BASIS, 12ac6a4445SGunnar Mills // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ac6a4445SGunnar Mills // See the License for the specific language governing permissions and 14ac6a4445SGunnar Mills // limitations under the License. 15ac6a4445SGunnar Mills */ 16ac6a4445SGunnar Mills #pragma once 17ac6a4445SGunnar Mills 183ccb3adbSEd Tanous #include "app.hpp" 191e1e598dSJonathan Doman #include "dbus_singleton.hpp" 207a1dbc48SGeorge Liu #include "dbus_utility.hpp" 211e1e598dSJonathan Doman #include "error_messages.hpp" 22*dfbf7de5SChris Cain #include "generated/enums/processor.hpp" 23ac6a4445SGunnar Mills #include "health.hpp" 243ccb3adbSEd Tanous #include "query.hpp" 253ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 263ccb3adbSEd Tanous #include "utils/collection.hpp" 273ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 283ccb3adbSEd Tanous #include "utils/json_utils.hpp" 29ac6a4445SGunnar Mills 30ac6a4445SGunnar Mills #include <boost/container/flat_map.hpp> 31e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 32ef4c65b7SEd Tanous #include <boost/url/format.hpp> 331e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 34dba0c291SJonathan Doman #include <sdbusplus/message/native_types.hpp> 35351053f2SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 36dba0c291SJonathan Doman #include <sdbusplus/utility/dedup_variant.hpp> 37ac6a4445SGunnar Mills 387a1dbc48SGeorge Liu #include <array> 39b9d679d1SMichael Shen #include <limits> 407a1dbc48SGeorge Liu #include <string_view> 417a1dbc48SGeorge Liu 42ac6a4445SGunnar Mills namespace redfish 43ac6a4445SGunnar Mills { 44ac6a4445SGunnar Mills 45c951448aSJonathan Doman // Interfaces which imply a D-Bus object represents a Processor 467a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> processorInterfaces = { 47c951448aSJonathan Doman "xyz.openbmc_project.Inventory.Item.Cpu", 48c951448aSJonathan Doman "xyz.openbmc_project.Inventory.Item.Accelerator"}; 492bab9831SJonathan Doman 5071b82f26SSharad Yadav /** 5171b82f26SSharad Yadav * @brief Fill out uuid info of a processor by 5271b82f26SSharad Yadav * requesting data from the given D-Bus object. 5371b82f26SSharad Yadav * 5471b82f26SSharad Yadav * @param[in,out] aResp Async HTTP response. 5571b82f26SSharad Yadav * @param[in] service D-Bus service to query. 5671b82f26SSharad Yadav * @param[in] objPath D-Bus object to query. 5771b82f26SSharad Yadav */ 5871b82f26SSharad Yadav inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp, 5971b82f26SSharad Yadav const std::string& service, 6071b82f26SSharad Yadav const std::string& objPath) 6171b82f26SSharad Yadav { 6271b82f26SSharad Yadav BMCWEB_LOG_DEBUG << "Get Processor UUID"; 631e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 641e1e598dSJonathan Doman *crow::connections::systemBus, service, objPath, 651e1e598dSJonathan Doman "xyz.openbmc_project.Common.UUID", "UUID", 665e7e2dc5SEd Tanous [objPath, aResp{std::move(aResp)}](const boost::system::error_code& ec, 671e1e598dSJonathan Doman const std::string& property) { 6871b82f26SSharad Yadav if (ec) 6971b82f26SSharad Yadav { 7071b82f26SSharad Yadav BMCWEB_LOG_DEBUG << "DBUS response error"; 7171b82f26SSharad Yadav messages::internalError(aResp->res); 7271b82f26SSharad Yadav return; 7371b82f26SSharad Yadav } 741e1e598dSJonathan Doman aResp->res.jsonValue["UUID"] = property; 751e1e598dSJonathan Doman }); 7671b82f26SSharad Yadav } 7771b82f26SSharad Yadav 78711ac7a9SEd Tanous inline void getCpuDataByInterface( 79711ac7a9SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& aResp, 80711ac7a9SEd Tanous const dbus::utility::DBusInteracesMap& cpuInterfacesProperties) 81ac6a4445SGunnar Mills { 82ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get CPU resources by interface."; 83ac6a4445SGunnar Mills 84a1649ec6SChicago Duan // Set the default value of state 85a1649ec6SChicago Duan aResp->res.jsonValue["Status"]["State"] = "Enabled"; 86a1649ec6SChicago Duan aResp->res.jsonValue["Status"]["Health"] = "OK"; 87ac6a4445SGunnar Mills 88ac6a4445SGunnar Mills for (const auto& interface : cpuInterfacesProperties) 89ac6a4445SGunnar Mills { 90ac6a4445SGunnar Mills for (const auto& property : interface.second) 91ac6a4445SGunnar Mills { 92a1649ec6SChicago Duan if (property.first == "Present") 93ac6a4445SGunnar Mills { 94a1649ec6SChicago Duan const bool* cpuPresent = std::get_if<bool>(&property.second); 95a1649ec6SChicago Duan if (cpuPresent == nullptr) 96ac6a4445SGunnar Mills { 97ac6a4445SGunnar Mills // Important property not in desired type 98ac6a4445SGunnar Mills messages::internalError(aResp->res); 99ac6a4445SGunnar Mills return; 100ac6a4445SGunnar Mills } 101e05aec50SEd Tanous if (!*cpuPresent) 102ac6a4445SGunnar Mills { 103a1649ec6SChicago Duan // Slot is not populated 104ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Absent"; 105a1649ec6SChicago Duan } 106a1649ec6SChicago Duan } 107a1649ec6SChicago Duan else if (property.first == "Functional") 108a1649ec6SChicago Duan { 109a1649ec6SChicago Duan const bool* cpuFunctional = std::get_if<bool>(&property.second); 110a1649ec6SChicago Duan if (cpuFunctional == nullptr) 111a1649ec6SChicago Duan { 112a1649ec6SChicago Duan messages::internalError(aResp->res); 113ac6a4445SGunnar Mills return; 114ac6a4445SGunnar Mills } 115e05aec50SEd Tanous if (!*cpuFunctional) 116a1649ec6SChicago Duan { 117a1649ec6SChicago Duan aResp->res.jsonValue["Status"]["Health"] = "Critical"; 118a1649ec6SChicago Duan } 119a1649ec6SChicago Duan } 120a1649ec6SChicago Duan else if (property.first == "CoreCount") 121a1649ec6SChicago Duan { 122a1649ec6SChicago Duan const uint16_t* coresCount = 123a1649ec6SChicago Duan std::get_if<uint16_t>(&property.second); 124a1649ec6SChicago Duan if (coresCount == nullptr) 125a1649ec6SChicago Duan { 126a1649ec6SChicago Duan messages::internalError(aResp->res); 127a1649ec6SChicago Duan return; 128a1649ec6SChicago Duan } 129ac6a4445SGunnar Mills aResp->res.jsonValue["TotalCores"] = *coresCount; 130ac6a4445SGunnar Mills } 131dc3fa667SJonathan Doman else if (property.first == "MaxSpeedInMhz") 132dc3fa667SJonathan Doman { 133dc3fa667SJonathan Doman const uint32_t* value = std::get_if<uint32_t>(&property.second); 134dc3fa667SJonathan Doman if (value != nullptr) 135dc3fa667SJonathan Doman { 136dc3fa667SJonathan Doman aResp->res.jsonValue["MaxSpeedMHz"] = *value; 137dc3fa667SJonathan Doman } 138dc3fa667SJonathan Doman } 139ac6a4445SGunnar Mills else if (property.first == "Socket") 140ac6a4445SGunnar Mills { 141ac6a4445SGunnar Mills const std::string* value = 142ac6a4445SGunnar Mills std::get_if<std::string>(&property.second); 143ac6a4445SGunnar Mills if (value != nullptr) 144ac6a4445SGunnar Mills { 145ac6a4445SGunnar Mills aResp->res.jsonValue["Socket"] = *value; 146ac6a4445SGunnar Mills } 147ac6a4445SGunnar Mills } 148ac6a4445SGunnar Mills else if (property.first == "ThreadCount") 149ac6a4445SGunnar Mills { 150dc3fa667SJonathan Doman const uint16_t* value = std::get_if<uint16_t>(&property.second); 151ac6a4445SGunnar Mills if (value != nullptr) 152ac6a4445SGunnar Mills { 153ac6a4445SGunnar Mills aResp->res.jsonValue["TotalThreads"] = *value; 154ac6a4445SGunnar Mills } 155ac6a4445SGunnar Mills } 1561930fbd4SBrandon Kim else if (property.first == "EffectiveFamily") 157ac6a4445SGunnar Mills { 1581930fbd4SBrandon Kim const uint16_t* value = std::get_if<uint16_t>(&property.second); 1596169de2cSBrad Bishop if (value != nullptr && *value != 2) 160ac6a4445SGunnar Mills { 161ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] = 162866e4862SEd Tanous "0x" + intToHexString(*value, 4); 163ac6a4445SGunnar Mills } 164ac6a4445SGunnar Mills } 1651930fbd4SBrandon Kim else if (property.first == "EffectiveModel") 1661930fbd4SBrandon Kim { 1671930fbd4SBrandon Kim const uint16_t* value = std::get_if<uint16_t>(&property.second); 1681930fbd4SBrandon Kim if (value == nullptr) 1691930fbd4SBrandon Kim { 1701930fbd4SBrandon Kim messages::internalError(aResp->res); 1711930fbd4SBrandon Kim return; 1721930fbd4SBrandon Kim } 1736169de2cSBrad Bishop if (*value != 0) 1746169de2cSBrad Bishop { 1751930fbd4SBrandon Kim aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] = 176866e4862SEd Tanous "0x" + intToHexString(*value, 4); 1771930fbd4SBrandon Kim } 1786169de2cSBrad Bishop } 179ac6a4445SGunnar Mills else if (property.first == "Id") 180ac6a4445SGunnar Mills { 181ac6a4445SGunnar Mills const uint64_t* value = std::get_if<uint64_t>(&property.second); 182ac6a4445SGunnar Mills if (value != nullptr && *value != 0) 183ac6a4445SGunnar Mills { 184ac6a4445SGunnar Mills aResp->res 185ac6a4445SGunnar Mills .jsonValue["ProcessorId"]["IdentificationRegisters"] = 186866e4862SEd Tanous "0x" + intToHexString(*value, 16); 187ac6a4445SGunnar Mills } 188ac6a4445SGunnar Mills } 1891930fbd4SBrandon Kim else if (property.first == "Microcode") 1901930fbd4SBrandon Kim { 1911930fbd4SBrandon Kim const uint32_t* value = std::get_if<uint32_t>(&property.second); 1921930fbd4SBrandon Kim if (value == nullptr) 1931930fbd4SBrandon Kim { 1941930fbd4SBrandon Kim messages::internalError(aResp->res); 1951930fbd4SBrandon Kim return; 1961930fbd4SBrandon Kim } 1976169de2cSBrad Bishop if (*value != 0) 1986169de2cSBrad Bishop { 1991930fbd4SBrandon Kim aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] = 200866e4862SEd Tanous "0x" + intToHexString(*value, 8); 2011930fbd4SBrandon Kim } 2026169de2cSBrad Bishop } 2031930fbd4SBrandon Kim else if (property.first == "Step") 2041930fbd4SBrandon Kim { 2051930fbd4SBrandon Kim const uint16_t* value = std::get_if<uint16_t>(&property.second); 2061930fbd4SBrandon Kim if (value == nullptr) 2071930fbd4SBrandon Kim { 2081930fbd4SBrandon Kim messages::internalError(aResp->res); 2091930fbd4SBrandon Kim return; 2101930fbd4SBrandon Kim } 211b9d679d1SMichael Shen if (*value != std::numeric_limits<uint16_t>::max()) 2126169de2cSBrad Bishop { 2131930fbd4SBrandon Kim aResp->res.jsonValue["ProcessorId"]["Step"] = 214866e4862SEd Tanous "0x" + intToHexString(*value, 4); 2151930fbd4SBrandon Kim } 216ac6a4445SGunnar Mills } 217ac6a4445SGunnar Mills } 218ac6a4445SGunnar Mills } 2196169de2cSBrad Bishop } 220ac6a4445SGunnar Mills 2218d1b46d7Szhanghch05 inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp, 222ac6a4445SGunnar Mills const std::string& cpuId, 223ac6a4445SGunnar Mills const std::string& service, 224ac6a4445SGunnar Mills const std::string& objPath) 225ac6a4445SGunnar Mills { 226ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get available system cpu resources by service."; 227ac6a4445SGunnar Mills 228ac6a4445SGunnar Mills crow::connections::systemBus->async_method_call( 229ac6a4445SGunnar Mills [cpuId, service, objPath, aResp{std::move(aResp)}]( 2305e7e2dc5SEd Tanous const boost::system::error_code& ec, 231ac6a4445SGunnar Mills const dbus::utility::ManagedObjectType& dbusData) { 232ac6a4445SGunnar Mills if (ec) 233ac6a4445SGunnar Mills { 234ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 235ac6a4445SGunnar Mills messages::internalError(aResp->res); 236ac6a4445SGunnar Mills return; 237ac6a4445SGunnar Mills } 238ac6a4445SGunnar Mills aResp->res.jsonValue["Id"] = cpuId; 239ac6a4445SGunnar Mills aResp->res.jsonValue["Name"] = "Processor"; 240ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorType"] = "CPU"; 241ac6a4445SGunnar Mills 242ac6a4445SGunnar Mills bool slotPresent = false; 243ac6a4445SGunnar Mills std::string corePath = objPath + "/core"; 244ac6a4445SGunnar Mills size_t totalCores = 0; 245ac6a4445SGunnar Mills for (const auto& object : dbusData) 246ac6a4445SGunnar Mills { 247ac6a4445SGunnar Mills if (object.first.str == objPath) 248ac6a4445SGunnar Mills { 249ac6a4445SGunnar Mills getCpuDataByInterface(aResp, object.second); 250ac6a4445SGunnar Mills } 25111ba3979SEd Tanous else if (object.first.str.starts_with(corePath)) 252ac6a4445SGunnar Mills { 253ac6a4445SGunnar Mills for (const auto& interface : object.second) 254ac6a4445SGunnar Mills { 255002d39b4SEd Tanous if (interface.first == "xyz.openbmc_project.Inventory.Item") 256ac6a4445SGunnar Mills { 257ac6a4445SGunnar Mills for (const auto& property : interface.second) 258ac6a4445SGunnar Mills { 259ac6a4445SGunnar Mills if (property.first == "Present") 260ac6a4445SGunnar Mills { 261ac6a4445SGunnar Mills const bool* present = 262ac6a4445SGunnar Mills std::get_if<bool>(&property.second); 263ac6a4445SGunnar Mills if (present != nullptr) 264ac6a4445SGunnar Mills { 265e05aec50SEd Tanous if (*present) 266ac6a4445SGunnar Mills { 267ac6a4445SGunnar Mills slotPresent = true; 268ac6a4445SGunnar Mills totalCores++; 269ac6a4445SGunnar Mills } 270ac6a4445SGunnar Mills } 271ac6a4445SGunnar Mills } 272ac6a4445SGunnar Mills } 273ac6a4445SGunnar Mills } 274ac6a4445SGunnar Mills } 275ac6a4445SGunnar Mills } 276ac6a4445SGunnar Mills } 277ac6a4445SGunnar Mills // In getCpuDataByInterface(), state and health are set 278ac6a4445SGunnar Mills // based on the present and functional status. If core 279ac6a4445SGunnar Mills // count is zero, then it has a higher precedence. 280ac6a4445SGunnar Mills if (slotPresent) 281ac6a4445SGunnar Mills { 282ac6a4445SGunnar Mills if (totalCores == 0) 283ac6a4445SGunnar Mills { 284ac6a4445SGunnar Mills // Slot is not populated, set status end return 285ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Absent"; 286ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["Health"] = "OK"; 287ac6a4445SGunnar Mills } 288ac6a4445SGunnar Mills aResp->res.jsonValue["TotalCores"] = totalCores; 289ac6a4445SGunnar Mills } 290ac6a4445SGunnar Mills return; 291ac6a4445SGunnar Mills }, 292ac6a4445SGunnar Mills service, "/xyz/openbmc_project/inventory", 293ac6a4445SGunnar Mills "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 294ac6a4445SGunnar Mills } 295ac6a4445SGunnar Mills 296*dfbf7de5SChris Cain /** 297*dfbf7de5SChris Cain * @brief Translates throttle cause DBUS property to redfish. 298*dfbf7de5SChris Cain * 299*dfbf7de5SChris Cain * @param[in] dbusSource The throttle cause from DBUS 300*dfbf7de5SChris Cain * 301*dfbf7de5SChris Cain * @return Returns as a string, the throttle cause in Redfish terms. If 302*dfbf7de5SChris Cain * translation cannot be done, returns "Unknown" throttle reason. 303*dfbf7de5SChris Cain */ 304*dfbf7de5SChris Cain inline processor::ThrottleCause 305*dfbf7de5SChris Cain dbusToRfThrottleCause(const std::string& dbusSource) 306*dfbf7de5SChris Cain { 307*dfbf7de5SChris Cain if (dbusSource == 308*dfbf7de5SChris Cain "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.ClockLimit") 309*dfbf7de5SChris Cain { 310*dfbf7de5SChris Cain return processor::ThrottleCause::ClockLimit; 311*dfbf7de5SChris Cain } 312*dfbf7de5SChris Cain if (dbusSource == 313*dfbf7de5SChris Cain "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.ManagementDetectedFault") 314*dfbf7de5SChris Cain { 315*dfbf7de5SChris Cain return processor::ThrottleCause::ManagementDetectedFault; 316*dfbf7de5SChris Cain } 317*dfbf7de5SChris Cain if (dbusSource == 318*dfbf7de5SChris Cain "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.PowerLimit") 319*dfbf7de5SChris Cain { 320*dfbf7de5SChris Cain return processor::ThrottleCause::PowerLimit; 321*dfbf7de5SChris Cain } 322*dfbf7de5SChris Cain if (dbusSource == 323*dfbf7de5SChris Cain "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.ThermalLimit") 324*dfbf7de5SChris Cain { 325*dfbf7de5SChris Cain return processor::ThrottleCause::ThermalLimit; 326*dfbf7de5SChris Cain } 327*dfbf7de5SChris Cain if (dbusSource == 328*dfbf7de5SChris Cain "xyz.openbmc_project.Control.Power.Throttle.ThrottleReasons.Unknown") 329*dfbf7de5SChris Cain { 330*dfbf7de5SChris Cain return processor::ThrottleCause::Unknown; 331*dfbf7de5SChris Cain } 332*dfbf7de5SChris Cain return processor::ThrottleCause::Invalid; 333*dfbf7de5SChris Cain } 334*dfbf7de5SChris Cain 335*dfbf7de5SChris Cain inline void 336*dfbf7de5SChris Cain readThrottleProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 337*dfbf7de5SChris Cain const boost::system::error_code& ec, 338*dfbf7de5SChris Cain const dbus::utility::DBusPropertiesMap& properties) 339*dfbf7de5SChris Cain { 340*dfbf7de5SChris Cain if (ec) 341*dfbf7de5SChris Cain { 342*dfbf7de5SChris Cain BMCWEB_LOG_ERROR << "Processor Throttle getAllProperties error " << ec; 343*dfbf7de5SChris Cain messages::internalError(aResp->res); 344*dfbf7de5SChris Cain return; 345*dfbf7de5SChris Cain } 346*dfbf7de5SChris Cain 347*dfbf7de5SChris Cain const bool* status = nullptr; 348*dfbf7de5SChris Cain const std::vector<std::string>* causes = nullptr; 349*dfbf7de5SChris Cain 350*dfbf7de5SChris Cain if (!sdbusplus::unpackPropertiesNoThrow(dbus_utils::UnpackErrorPrinter(), 351*dfbf7de5SChris Cain properties, "Throttled", status, 352*dfbf7de5SChris Cain "ThrottleCauses", causes)) 353*dfbf7de5SChris Cain { 354*dfbf7de5SChris Cain messages::internalError(aResp->res); 355*dfbf7de5SChris Cain return; 356*dfbf7de5SChris Cain } 357*dfbf7de5SChris Cain 358*dfbf7de5SChris Cain aResp->res.jsonValue["Throttled"] = *status; 359*dfbf7de5SChris Cain nlohmann::json::array_t rCauses; 360*dfbf7de5SChris Cain for (const std::string& cause : *causes) 361*dfbf7de5SChris Cain { 362*dfbf7de5SChris Cain processor::ThrottleCause rfCause = dbusToRfThrottleCause(cause); 363*dfbf7de5SChris Cain if (rfCause == processor::ThrottleCause::Invalid) 364*dfbf7de5SChris Cain { 365*dfbf7de5SChris Cain messages::internalError(aResp->res); 366*dfbf7de5SChris Cain return; 367*dfbf7de5SChris Cain } 368*dfbf7de5SChris Cain 369*dfbf7de5SChris Cain rCauses.emplace_back(rfCause); 370*dfbf7de5SChris Cain } 371*dfbf7de5SChris Cain aResp->res.jsonValue["ThrottleCauses"] = std::move(rCauses); 372*dfbf7de5SChris Cain } 373*dfbf7de5SChris Cain 374*dfbf7de5SChris Cain inline void 375*dfbf7de5SChris Cain getThrottleProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 376*dfbf7de5SChris Cain const std::string& service, 377*dfbf7de5SChris Cain const std::string& objectPath) 378*dfbf7de5SChris Cain { 379*dfbf7de5SChris Cain BMCWEB_LOG_DEBUG << "Get processor throttle resources"; 380*dfbf7de5SChris Cain 381*dfbf7de5SChris Cain sdbusplus::asio::getAllProperties( 382*dfbf7de5SChris Cain *crow::connections::systemBus, service, objectPath, 383*dfbf7de5SChris Cain "xyz.openbmc_project.Control.Power.Throttle", 384*dfbf7de5SChris Cain [aResp](const boost::system::error_code& ec, 385*dfbf7de5SChris Cain const dbus::utility::DBusPropertiesMap& properties) { 386*dfbf7de5SChris Cain readThrottleProperties(aResp, ec, properties); 387*dfbf7de5SChris Cain }); 388*dfbf7de5SChris Cain } 389*dfbf7de5SChris Cain 3908d1b46d7Szhanghch05 inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp, 391ac6a4445SGunnar Mills const std::string& service, 392ac6a4445SGunnar Mills const std::string& objPath) 393ac6a4445SGunnar Mills { 394ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get Cpu Asset Data"; 395351053f2SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 396351053f2SKrzysztof Grobelny *crow::connections::systemBus, service, objPath, 397351053f2SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 398ac6a4445SGunnar Mills [objPath, aResp{std::move(aResp)}]( 3995e7e2dc5SEd Tanous const boost::system::error_code& ec, 400351053f2SKrzysztof Grobelny const dbus::utility::DBusPropertiesMap& properties) { 401ac6a4445SGunnar Mills if (ec) 402ac6a4445SGunnar Mills { 403ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 404ac6a4445SGunnar Mills messages::internalError(aResp->res); 405ac6a4445SGunnar Mills return; 406ac6a4445SGunnar Mills } 407ac6a4445SGunnar Mills 408351053f2SKrzysztof Grobelny const std::string* serialNumber = nullptr; 409351053f2SKrzysztof Grobelny const std::string* model = nullptr; 410351053f2SKrzysztof Grobelny const std::string* manufacturer = nullptr; 411351053f2SKrzysztof Grobelny const std::string* partNumber = nullptr; 412351053f2SKrzysztof Grobelny const std::string* sparePartNumber = nullptr; 413351053f2SKrzysztof Grobelny 414351053f2SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 415351053f2SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "SerialNumber", 416351053f2SKrzysztof Grobelny serialNumber, "Model", model, "Manufacturer", manufacturer, 417351053f2SKrzysztof Grobelny "PartNumber", partNumber, "SparePartNumber", sparePartNumber); 418351053f2SKrzysztof Grobelny 419351053f2SKrzysztof Grobelny if (!success) 420ac6a4445SGunnar Mills { 421351053f2SKrzysztof Grobelny messages::internalError(aResp->res); 422351053f2SKrzysztof Grobelny return; 423ac6a4445SGunnar Mills } 424351053f2SKrzysztof Grobelny 425351053f2SKrzysztof Grobelny if (serialNumber != nullptr && !serialNumber->empty()) 426ac6a4445SGunnar Mills { 427351053f2SKrzysztof Grobelny aResp->res.jsonValue["SerialNumber"] = *serialNumber; 428351053f2SKrzysztof Grobelny } 429351053f2SKrzysztof Grobelny 430351053f2SKrzysztof Grobelny if ((model != nullptr) && !model->empty()) 431ac6a4445SGunnar Mills { 432ac6a4445SGunnar Mills aResp->res.jsonValue["Model"] = *model; 433ac6a4445SGunnar Mills } 434ac6a4445SGunnar Mills 435351053f2SKrzysztof Grobelny if (manufacturer != nullptr) 436ac6a4445SGunnar Mills { 437351053f2SKrzysztof Grobelny aResp->res.jsonValue["Manufacturer"] = *manufacturer; 438ac6a4445SGunnar Mills 439ac6a4445SGunnar Mills // Otherwise would be unexpected. 440351053f2SKrzysztof Grobelny if (manufacturer->find("Intel") != std::string::npos) 441ac6a4445SGunnar Mills { 442002d39b4SEd Tanous aResp->res.jsonValue["ProcessorArchitecture"] = "x86"; 443ac6a4445SGunnar Mills aResp->res.jsonValue["InstructionSet"] = "x86-64"; 444ac6a4445SGunnar Mills } 445351053f2SKrzysztof Grobelny else if (manufacturer->find("IBM") != std::string::npos) 446ac6a4445SGunnar Mills { 447002d39b4SEd Tanous aResp->res.jsonValue["ProcessorArchitecture"] = "Power"; 448ac6a4445SGunnar Mills aResp->res.jsonValue["InstructionSet"] = "PowerISA"; 449ac6a4445SGunnar Mills } 450ac6a4445SGunnar Mills } 451cba4f448SSunnySrivastava1984 452351053f2SKrzysztof Grobelny if (partNumber != nullptr) 453cba4f448SSunnySrivastava1984 { 454cba4f448SSunnySrivastava1984 aResp->res.jsonValue["PartNumber"] = *partNumber; 455cba4f448SSunnySrivastava1984 } 456cba4f448SSunnySrivastava1984 4576169de2cSBrad Bishop if (sparePartNumber != nullptr && !sparePartNumber->empty()) 458cba4f448SSunnySrivastava1984 { 459cba4f448SSunnySrivastava1984 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 460cba4f448SSunnySrivastava1984 } 461351053f2SKrzysztof Grobelny }); 462ac6a4445SGunnar Mills } 463ac6a4445SGunnar Mills 4648d1b46d7Szhanghch05 inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp, 465ac6a4445SGunnar Mills const std::string& service, 466ac6a4445SGunnar Mills const std::string& objPath) 467ac6a4445SGunnar Mills { 468ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get Cpu Revision Data"; 469351053f2SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 470351053f2SKrzysztof Grobelny *crow::connections::systemBus, service, objPath, 471351053f2SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Revision", 472ac6a4445SGunnar Mills [objPath, aResp{std::move(aResp)}]( 4735e7e2dc5SEd Tanous const boost::system::error_code& ec, 474351053f2SKrzysztof Grobelny const dbus::utility::DBusPropertiesMap& properties) { 475ac6a4445SGunnar Mills if (ec) 476ac6a4445SGunnar Mills { 477ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 478ac6a4445SGunnar Mills messages::internalError(aResp->res); 479ac6a4445SGunnar Mills return; 480ac6a4445SGunnar Mills } 481ac6a4445SGunnar Mills 482351053f2SKrzysztof Grobelny const std::string* version = nullptr; 483351053f2SKrzysztof Grobelny 484351053f2SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 485351053f2SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "Version", version); 486351053f2SKrzysztof Grobelny 487351053f2SKrzysztof Grobelny if (!success) 488ac6a4445SGunnar Mills { 489351053f2SKrzysztof Grobelny messages::internalError(aResp->res); 490351053f2SKrzysztof Grobelny return; 491351053f2SKrzysztof Grobelny } 492351053f2SKrzysztof Grobelny 493351053f2SKrzysztof Grobelny if (version != nullptr) 494ac6a4445SGunnar Mills { 495351053f2SKrzysztof Grobelny aResp->res.jsonValue["Version"] = *version; 496ac6a4445SGunnar Mills } 497351053f2SKrzysztof Grobelny }); 498ac6a4445SGunnar Mills } 499ac6a4445SGunnar Mills 5008d1b46d7Szhanghch05 inline void getAcceleratorDataByService( 5018d1b46d7Szhanghch05 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId, 5028d1b46d7Szhanghch05 const std::string& service, const std::string& objPath) 503ac6a4445SGunnar Mills { 504ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG 505ac6a4445SGunnar Mills << "Get available system Accelerator resources by service."; 506351053f2SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 507351053f2SKrzysztof Grobelny *crow::connections::systemBus, service, objPath, "", 508ac6a4445SGunnar Mills [acclrtrId, aResp{std::move(aResp)}]( 5095e7e2dc5SEd Tanous const boost::system::error_code& ec, 510351053f2SKrzysztof Grobelny const dbus::utility::DBusPropertiesMap& properties) { 511ac6a4445SGunnar Mills if (ec) 512ac6a4445SGunnar Mills { 513ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 514ac6a4445SGunnar Mills messages::internalError(aResp->res); 515ac6a4445SGunnar Mills return; 516ac6a4445SGunnar Mills } 517ac6a4445SGunnar Mills 518351053f2SKrzysztof Grobelny const bool* functional = nullptr; 519351053f2SKrzysztof Grobelny const bool* present = nullptr; 520351053f2SKrzysztof Grobelny 521351053f2SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 522351053f2SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "Functional", 523351053f2SKrzysztof Grobelny functional, "Present", present); 524351053f2SKrzysztof Grobelny 525351053f2SKrzysztof Grobelny if (!success) 526ac6a4445SGunnar Mills { 527351053f2SKrzysztof Grobelny messages::internalError(aResp->res); 528351053f2SKrzysztof Grobelny return; 529ac6a4445SGunnar Mills } 530ac6a4445SGunnar Mills 531ac6a4445SGunnar Mills std::string state = "Enabled"; 532ac6a4445SGunnar Mills std::string health = "OK"; 533ac6a4445SGunnar Mills 534351053f2SKrzysztof Grobelny if (present != nullptr && !*present) 535ac6a4445SGunnar Mills { 536ac6a4445SGunnar Mills state = "Absent"; 537ac6a4445SGunnar Mills } 538ac6a4445SGunnar Mills 539351053f2SKrzysztof Grobelny if (functional != nullptr && !*functional) 540ac6a4445SGunnar Mills { 541ac6a4445SGunnar Mills if (state == "Enabled") 542ac6a4445SGunnar Mills { 543ac6a4445SGunnar Mills health = "Critical"; 544ac6a4445SGunnar Mills } 545ac6a4445SGunnar Mills } 546ac6a4445SGunnar Mills 547351053f2SKrzysztof Grobelny aResp->res.jsonValue["Id"] = acclrtrId; 548351053f2SKrzysztof Grobelny aResp->res.jsonValue["Name"] = "Processor"; 549ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = state; 550ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["Health"] = health; 551ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorType"] = "Accelerator"; 552351053f2SKrzysztof Grobelny }); 553ac6a4445SGunnar Mills } 554ac6a4445SGunnar Mills 555dba0c291SJonathan Doman // OperatingConfig D-Bus Types 556dba0c291SJonathan Doman using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>; 557dba0c291SJonathan Doman using BaseSpeedPrioritySettingsProperty = 558dba0c291SJonathan Doman std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>; 559dba0c291SJonathan Doman // uint32_t and size_t may or may not be the same type, requiring a dedup'd 560dba0c291SJonathan Doman // variant 561dba0c291SJonathan Doman 562dba0c291SJonathan Doman /** 563dba0c291SJonathan Doman * Fill out the HighSpeedCoreIDs in a Processor resource from the given 564dba0c291SJonathan Doman * OperatingConfig D-Bus property. 565dba0c291SJonathan Doman * 566dba0c291SJonathan Doman * @param[in,out] aResp Async HTTP response. 567dba0c291SJonathan Doman * @param[in] baseSpeedSettings Full list of base speed priority groups, 568dba0c291SJonathan Doman * to use to determine the list of high 569dba0c291SJonathan Doman * speed cores. 570dba0c291SJonathan Doman */ 571dba0c291SJonathan Doman inline void highSpeedCoreIdsHandler( 5728d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 573dba0c291SJonathan Doman const BaseSpeedPrioritySettingsProperty& baseSpeedSettings) 574dba0c291SJonathan Doman { 575dba0c291SJonathan Doman // The D-Bus property does not indicate which bucket is the "high 576dba0c291SJonathan Doman // priority" group, so let's discern that by looking for the one with 577dba0c291SJonathan Doman // highest base frequency. 578dba0c291SJonathan Doman auto highPriorityGroup = baseSpeedSettings.cend(); 579dba0c291SJonathan Doman uint32_t highestBaseSpeed = 0; 580dba0c291SJonathan Doman for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend(); 581dba0c291SJonathan Doman ++it) 582dba0c291SJonathan Doman { 583dba0c291SJonathan Doman const uint32_t baseFreq = std::get<uint32_t>(*it); 584dba0c291SJonathan Doman if (baseFreq > highestBaseSpeed) 585dba0c291SJonathan Doman { 586dba0c291SJonathan Doman highestBaseSpeed = baseFreq; 587dba0c291SJonathan Doman highPriorityGroup = it; 588dba0c291SJonathan Doman } 589dba0c291SJonathan Doman } 590dba0c291SJonathan Doman 591dba0c291SJonathan Doman nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"]; 592dba0c291SJonathan Doman jsonCoreIds = nlohmann::json::array(); 593dba0c291SJonathan Doman 594dba0c291SJonathan Doman // There may not be any entries in the D-Bus property, so only populate 595dba0c291SJonathan Doman // if there was actually something there. 596dba0c291SJonathan Doman if (highPriorityGroup != baseSpeedSettings.cend()) 597dba0c291SJonathan Doman { 598dba0c291SJonathan Doman jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup); 599dba0c291SJonathan Doman } 600dba0c291SJonathan Doman } 601dba0c291SJonathan Doman 602dba0c291SJonathan Doman /** 603dba0c291SJonathan Doman * Fill out OperatingConfig related items in a Processor resource by requesting 604dba0c291SJonathan Doman * data from the given D-Bus object. 605dba0c291SJonathan Doman * 606dba0c291SJonathan Doman * @param[in,out] aResp Async HTTP response. 607dba0c291SJonathan Doman * @param[in] cpuId CPU D-Bus name. 608dba0c291SJonathan Doman * @param[in] service D-Bus service to query. 609dba0c291SJonathan Doman * @param[in] objPath D-Bus object to query. 610dba0c291SJonathan Doman */ 6118d1b46d7Szhanghch05 inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 612dba0c291SJonathan Doman const std::string& cpuId, 613dba0c291SJonathan Doman const std::string& service, 614dba0c291SJonathan Doman const std::string& objPath) 615dba0c291SJonathan Doman { 616dba0c291SJonathan Doman BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId; 617dba0c291SJonathan Doman 618dba0c291SJonathan Doman // First, GetAll CurrentOperatingConfig properties on the object 619351053f2SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 620351053f2SKrzysztof Grobelny *crow::connections::systemBus, service, objPath, 621351053f2SKrzysztof Grobelny "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig", 622351053f2SKrzysztof Grobelny [aResp, cpuId, 6235e7e2dc5SEd Tanous service](const boost::system::error_code& ec, 624351053f2SKrzysztof Grobelny const dbus::utility::DBusPropertiesMap& properties) { 625dba0c291SJonathan Doman if (ec) 626dba0c291SJonathan Doman { 627002d39b4SEd Tanous BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message(); 628dba0c291SJonathan Doman messages::internalError(aResp->res); 629dba0c291SJonathan Doman return; 630dba0c291SJonathan Doman } 631dba0c291SJonathan Doman 632dba0c291SJonathan Doman nlohmann::json& json = aResp->res.jsonValue; 633dba0c291SJonathan Doman 634351053f2SKrzysztof Grobelny const sdbusplus::message::object_path* appliedConfig = nullptr; 635351053f2SKrzysztof Grobelny const bool* baseSpeedPriorityEnabled = nullptr; 636351053f2SKrzysztof Grobelny 637351053f2SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 638351053f2SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "AppliedConfig", 639351053f2SKrzysztof Grobelny appliedConfig, "BaseSpeedPriorityEnabled", 640351053f2SKrzysztof Grobelny baseSpeedPriorityEnabled); 641351053f2SKrzysztof Grobelny 642351053f2SKrzysztof Grobelny if (!success) 643dba0c291SJonathan Doman { 644351053f2SKrzysztof Grobelny messages::internalError(aResp->res); 645351053f2SKrzysztof Grobelny return; 646dba0c291SJonathan Doman } 647dba0c291SJonathan Doman 648351053f2SKrzysztof Grobelny if (appliedConfig != nullptr) 649351053f2SKrzysztof Grobelny { 650351053f2SKrzysztof Grobelny const std::string& dbusPath = appliedConfig->str; 6511476687dSEd Tanous nlohmann::json::object_t operatingConfig; 652ef4c65b7SEd Tanous operatingConfig["@odata.id"] = boost::urls::format( 653ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Processors/{}/OperatingConfigs", 654ef4c65b7SEd Tanous cpuId); 6551476687dSEd Tanous json["OperatingConfigs"] = std::move(operatingConfig); 656dba0c291SJonathan Doman 657dba0c291SJonathan Doman // Reuse the D-Bus config object name for the Redfish 658dba0c291SJonathan Doman // URI 659dba0c291SJonathan Doman size_t baseNamePos = dbusPath.rfind('/'); 660dba0c291SJonathan Doman if (baseNamePos == std::string::npos || 661dba0c291SJonathan Doman baseNamePos == (dbusPath.size() - 1)) 662dba0c291SJonathan Doman { 663dba0c291SJonathan Doman // If the AppliedConfig was somehow not a valid path, 664dba0c291SJonathan Doman // skip adding any more properties, since everything 665dba0c291SJonathan Doman // else is tied to this applied config. 666dba0c291SJonathan Doman messages::internalError(aResp->res); 667351053f2SKrzysztof Grobelny return; 668dba0c291SJonathan Doman } 6691476687dSEd Tanous nlohmann::json::object_t appliedOperatingConfig; 670ef4c65b7SEd Tanous appliedOperatingConfig["@odata.id"] = boost::urls::format( 671ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Processors/{}/OperatingConfigs/{}", 672ef4c65b7SEd Tanous cpuId, dbusPath.substr(baseNamePos + 1)); 673351053f2SKrzysztof Grobelny json["AppliedOperatingConfig"] = std::move(appliedOperatingConfig); 674dba0c291SJonathan Doman 675dba0c291SJonathan Doman // Once we found the current applied config, queue another 676dba0c291SJonathan Doman // request to read the base freq core ids out of that 677dba0c291SJonathan Doman // config. 678002d39b4SEd Tanous sdbusplus::asio::getProperty<BaseSpeedPrioritySettingsProperty>( 6791e1e598dSJonathan Doman *crow::connections::systemBus, service, dbusPath, 6801e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Item.Cpu." 6811e1e598dSJonathan Doman "OperatingConfig", 6821e1e598dSJonathan Doman "BaseSpeedPrioritySettings", 683351053f2SKrzysztof Grobelny [aResp]( 6845e7e2dc5SEd Tanous const boost::system::error_code& ec2, 685351053f2SKrzysztof Grobelny const BaseSpeedPrioritySettingsProperty& baseSpeedList) { 6868a592810SEd Tanous if (ec2) 687dba0c291SJonathan Doman { 688351053f2SKrzysztof Grobelny BMCWEB_LOG_WARNING << "D-Bus Property Get error: " << ec2; 689dba0c291SJonathan Doman messages::internalError(aResp->res); 690dba0c291SJonathan Doman return; 691dba0c291SJonathan Doman } 6921e1e598dSJonathan Doman 6931e1e598dSJonathan Doman highSpeedCoreIdsHandler(aResp, baseSpeedList); 6941e1e598dSJonathan Doman }); 695dba0c291SJonathan Doman } 696351053f2SKrzysztof Grobelny 697351053f2SKrzysztof Grobelny if (baseSpeedPriorityEnabled != nullptr) 698dba0c291SJonathan Doman { 699dba0c291SJonathan Doman json["BaseSpeedPriorityState"] = 700351053f2SKrzysztof Grobelny *baseSpeedPriorityEnabled ? "Enabled" : "Disabled"; 701dba0c291SJonathan Doman } 702351053f2SKrzysztof Grobelny }); 703dba0c291SJonathan Doman } 704dba0c291SJonathan Doman 705cba4f448SSunnySrivastava1984 /** 706cba4f448SSunnySrivastava1984 * @brief Fill out location info of a processor by 707cba4f448SSunnySrivastava1984 * requesting data from the given D-Bus object. 708cba4f448SSunnySrivastava1984 * 709cba4f448SSunnySrivastava1984 * @param[in,out] aResp Async HTTP response. 710cba4f448SSunnySrivastava1984 * @param[in] service D-Bus service to query. 711cba4f448SSunnySrivastava1984 * @param[in] objPath D-Bus object to query. 712cba4f448SSunnySrivastava1984 */ 7138d1b46d7Szhanghch05 inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp, 714cba4f448SSunnySrivastava1984 const std::string& service, 715cba4f448SSunnySrivastava1984 const std::string& objPath) 716cba4f448SSunnySrivastava1984 { 717cba4f448SSunnySrivastava1984 BMCWEB_LOG_DEBUG << "Get Cpu Location Data"; 7181e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 7191e1e598dSJonathan Doman *crow::connections::systemBus, service, objPath, 7201e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 7215e7e2dc5SEd Tanous [objPath, aResp{std::move(aResp)}](const boost::system::error_code& ec, 7221e1e598dSJonathan Doman const std::string& property) { 723cba4f448SSunnySrivastava1984 if (ec) 724cba4f448SSunnySrivastava1984 { 725cba4f448SSunnySrivastava1984 BMCWEB_LOG_DEBUG << "DBUS response error"; 726cba4f448SSunnySrivastava1984 messages::internalError(aResp->res); 727cba4f448SSunnySrivastava1984 return; 728cba4f448SSunnySrivastava1984 } 729cba4f448SSunnySrivastava1984 730cba4f448SSunnySrivastava1984 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 7311e1e598dSJonathan Doman property; 7321e1e598dSJonathan Doman }); 733cba4f448SSunnySrivastava1984 } 734cba4f448SSunnySrivastava1984 735c951448aSJonathan Doman /** 73649e429caSJonathan Doman * Populate the unique identifier in a Processor resource by requesting data 73749e429caSJonathan Doman * from the given D-Bus object. 73849e429caSJonathan Doman * 73949e429caSJonathan Doman * @param[in,out] aResp Async HTTP response. 74049e429caSJonathan Doman * @param[in] service D-Bus service to query. 74149e429caSJonathan Doman * @param[in] objPath D-Bus object to query. 74249e429caSJonathan Doman */ 74349e429caSJonathan Doman inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 74449e429caSJonathan Doman const std::string& service, 74549e429caSJonathan Doman const std::string& objectPath) 74649e429caSJonathan Doman { 74749e429caSJonathan Doman BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier"; 7481e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 7491e1e598dSJonathan Doman *crow::connections::systemBus, service, objectPath, 7501e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier", 7511e1e598dSJonathan Doman "UniqueIdentifier", 7525e7e2dc5SEd Tanous [aResp](const boost::system::error_code& ec, const std::string& id) { 7531e1e598dSJonathan Doman if (ec) 75449e429caSJonathan Doman { 75549e429caSJonathan Doman BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec; 75649e429caSJonathan Doman messages::internalError(aResp->res); 75749e429caSJonathan Doman return; 75849e429caSJonathan Doman } 759002d39b4SEd Tanous aResp->res.jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] = 760002d39b4SEd Tanous id; 7611e1e598dSJonathan Doman }); 76249e429caSJonathan Doman } 76349e429caSJonathan Doman 76449e429caSJonathan Doman /** 765c951448aSJonathan Doman * Find the D-Bus object representing the requested Processor, and call the 766c951448aSJonathan Doman * handler with the results. If matching object is not found, add 404 error to 767c951448aSJonathan Doman * response and don't call the handler. 768c951448aSJonathan Doman * 769c951448aSJonathan Doman * @param[in,out] resp Async HTTP response. 770c951448aSJonathan Doman * @param[in] processorId Redfish Processor Id. 771c951448aSJonathan Doman * @param[in] handler Callback to continue processing request upon 772c951448aSJonathan Doman * successfully finding object. 773c951448aSJonathan Doman */ 774c951448aSJonathan Doman template <typename Handler> 7758d1b46d7Szhanghch05 inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp, 776c951448aSJonathan Doman const std::string& processorId, 777c951448aSJonathan Doman Handler&& handler) 778ac6a4445SGunnar Mills { 779ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get available system processor resources."; 780ac6a4445SGunnar Mills 781c951448aSJonathan Doman // GetSubTree on all interfaces which provide info about a Processor 782*dfbf7de5SChris Cain constexpr std::array<std::string_view, 9> interfaces = { 783e99073f5SGeorge Liu "xyz.openbmc_project.Common.UUID", 784e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.Asset", 785e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.Revision", 786e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Item.Cpu", 787e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode", 788e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Item.Accelerator", 789e99073f5SGeorge Liu "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig", 790*dfbf7de5SChris Cain "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier", 791*dfbf7de5SChris Cain "xyz.openbmc_project.Control.Power.Throttle"}; 792e99073f5SGeorge Liu dbus::utility::getSubTree( 793e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 794c951448aSJonathan Doman [resp, processorId, handler = std::forward<Handler>(handler)]( 795e99073f5SGeorge Liu const boost::system::error_code& ec, 796e99073f5SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) { 797ac6a4445SGunnar Mills if (ec) 798ac6a4445SGunnar Mills { 799c951448aSJonathan Doman BMCWEB_LOG_DEBUG << "DBUS response error: " << ec; 800c951448aSJonathan Doman messages::internalError(resp->res); 801ac6a4445SGunnar Mills return; 802ac6a4445SGunnar Mills } 8032bab9831SJonathan Doman for (const auto& [objectPath, serviceMap] : subtree) 804ac6a4445SGunnar Mills { 8052bab9831SJonathan Doman // Ignore any objects which don't end with our desired cpu name 80611ba3979SEd Tanous if (!objectPath.ends_with(processorId)) 807ac6a4445SGunnar Mills { 8082bab9831SJonathan Doman continue; 809ac6a4445SGunnar Mills } 8102bab9831SJonathan Doman 811c951448aSJonathan Doman bool found = false; 812c951448aSJonathan Doman // Filter out objects that don't have the CPU-specific 813c951448aSJonathan Doman // interfaces to make sure we can return 404 on non-CPUs 814c951448aSJonathan Doman // (e.g. /redfish/../Processors/dimm0) 8152bab9831SJonathan Doman for (const auto& [serviceName, interfaceList] : serviceMap) 816ac6a4445SGunnar Mills { 817c951448aSJonathan Doman if (std::find_first_of( 818c951448aSJonathan Doman interfaceList.begin(), interfaceList.end(), 819c951448aSJonathan Doman processorInterfaces.begin(), 820c951448aSJonathan Doman processorInterfaces.end()) != interfaceList.end()) 8212bab9831SJonathan Doman { 822c951448aSJonathan Doman found = true; 823c951448aSJonathan Doman break; 824c951448aSJonathan Doman } 825c951448aSJonathan Doman } 826c951448aSJonathan Doman 827c951448aSJonathan Doman if (!found) 8282bab9831SJonathan Doman { 829c951448aSJonathan Doman continue; 830ac6a4445SGunnar Mills } 831c951448aSJonathan Doman 832c951448aSJonathan Doman // Process the first object which does match our cpu name and 833c951448aSJonathan Doman // required interfaces, and potentially ignore any other 834c951448aSJonathan Doman // matching objects. Assume all interfaces we want to process 835c951448aSJonathan Doman // must be on the same object path. 836c951448aSJonathan Doman 8378a592810SEd Tanous handler(objectPath, serviceMap); 838ac6a4445SGunnar Mills return; 839ac6a4445SGunnar Mills } 840c951448aSJonathan Doman messages::resourceNotFound(resp->res, "Processor", processorId); 841e99073f5SGeorge Liu }); 842ac6a4445SGunnar Mills } 843ac6a4445SGunnar Mills 8448d1b46d7Szhanghch05 inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 845c951448aSJonathan Doman const std::string& processorId, 846c951448aSJonathan Doman const std::string& objectPath, 8475df6eda2SShantappa Teekappanavar const dbus::utility::MapperServiceMap& serviceMap) 848c951448aSJonathan Doman { 849c951448aSJonathan Doman for (const auto& [serviceName, interfaceList] : serviceMap) 850c951448aSJonathan Doman { 851c951448aSJonathan Doman for (const auto& interface : interfaceList) 852c951448aSJonathan Doman { 853c951448aSJonathan Doman if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset") 854c951448aSJonathan Doman { 855c951448aSJonathan Doman getCpuAssetData(aResp, serviceName, objectPath); 856c951448aSJonathan Doman } 8570fda0f12SGeorge Liu else if (interface == 8580fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.Revision") 859c951448aSJonathan Doman { 860c951448aSJonathan Doman getCpuRevisionData(aResp, serviceName, objectPath); 861c951448aSJonathan Doman } 862c951448aSJonathan Doman else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu") 863c951448aSJonathan Doman { 864c951448aSJonathan Doman getCpuDataByService(aResp, processorId, serviceName, 865c951448aSJonathan Doman objectPath); 866c951448aSJonathan Doman } 8670fda0f12SGeorge Liu else if (interface == 8680fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Accelerator") 869c951448aSJonathan Doman { 870c951448aSJonathan Doman getAcceleratorDataByService(aResp, processorId, serviceName, 871c951448aSJonathan Doman objectPath); 872c951448aSJonathan Doman } 8730fda0f12SGeorge Liu else if ( 8740fda0f12SGeorge Liu interface == 8750fda0f12SGeorge Liu "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig") 876c951448aSJonathan Doman { 877c951448aSJonathan Doman getCpuConfigData(aResp, processorId, serviceName, objectPath); 878c951448aSJonathan Doman } 8790fda0f12SGeorge Liu else if (interface == 8800fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 881c951448aSJonathan Doman { 882c951448aSJonathan Doman getCpuLocationCode(aResp, serviceName, objectPath); 883c951448aSJonathan Doman } 88471b82f26SSharad Yadav else if (interface == "xyz.openbmc_project.Common.UUID") 88571b82f26SSharad Yadav { 88671b82f26SSharad Yadav getProcessorUUID(aResp, serviceName, objectPath); 88771b82f26SSharad Yadav } 8880fda0f12SGeorge Liu else if (interface == 8890fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier") 89049e429caSJonathan Doman { 89149e429caSJonathan Doman getCpuUniqueId(aResp, serviceName, objectPath); 89249e429caSJonathan Doman } 893*dfbf7de5SChris Cain else if (interface == "xyz.openbmc_project.Control.Power.Throttle") 894*dfbf7de5SChris Cain { 895*dfbf7de5SChris Cain getThrottleProperties(aResp, serviceName, objectPath); 896*dfbf7de5SChris Cain } 897c951448aSJonathan Doman } 898c951448aSJonathan Doman } 899c951448aSJonathan Doman } 900c951448aSJonathan Doman 901dba0c291SJonathan Doman /** 902dba0c291SJonathan Doman * Request all the properties for the given D-Bus object and fill out the 903dba0c291SJonathan Doman * related entries in the Redfish OperatingConfig response. 904dba0c291SJonathan Doman * 905dba0c291SJonathan Doman * @param[in,out] aResp Async HTTP response. 906dba0c291SJonathan Doman * @param[in] service D-Bus service name to query. 907dba0c291SJonathan Doman * @param[in] objPath D-Bus object to query. 908dba0c291SJonathan Doman */ 9098d1b46d7Szhanghch05 inline void 9108d1b46d7Szhanghch05 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 911dba0c291SJonathan Doman const std::string& service, 912dba0c291SJonathan Doman const std::string& objPath) 913dba0c291SJonathan Doman { 914351053f2SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 915351053f2SKrzysztof Grobelny *crow::connections::systemBus, service, objPath, 916351053f2SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig", 9175e7e2dc5SEd Tanous [aResp](const boost::system::error_code& ec, 918351053f2SKrzysztof Grobelny const dbus::utility::DBusPropertiesMap& properties) { 919dba0c291SJonathan Doman if (ec) 920dba0c291SJonathan Doman { 921002d39b4SEd Tanous BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message(); 922dba0c291SJonathan Doman messages::internalError(aResp->res); 923dba0c291SJonathan Doman return; 924dba0c291SJonathan Doman } 925dba0c291SJonathan Doman 926351053f2SKrzysztof Grobelny const size_t* availableCoreCount = nullptr; 927351053f2SKrzysztof Grobelny const uint32_t* baseSpeed = nullptr; 928351053f2SKrzysztof Grobelny const uint32_t* maxJunctionTemperature = nullptr; 929351053f2SKrzysztof Grobelny const uint32_t* maxSpeed = nullptr; 930351053f2SKrzysztof Grobelny const uint32_t* powerLimit = nullptr; 931351053f2SKrzysztof Grobelny const TurboProfileProperty* turboProfile = nullptr; 932351053f2SKrzysztof Grobelny const BaseSpeedPrioritySettingsProperty* baseSpeedPrioritySettings = 933351053f2SKrzysztof Grobelny nullptr; 934351053f2SKrzysztof Grobelny 935351053f2SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 936351053f2SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "AvailableCoreCount", 937351053f2SKrzysztof Grobelny availableCoreCount, "BaseSpeed", baseSpeed, 938351053f2SKrzysztof Grobelny "MaxJunctionTemperature", maxJunctionTemperature, "MaxSpeed", 939351053f2SKrzysztof Grobelny maxSpeed, "PowerLimit", powerLimit, "TurboProfile", turboProfile, 940351053f2SKrzysztof Grobelny "BaseSpeedPrioritySettings", baseSpeedPrioritySettings); 941351053f2SKrzysztof Grobelny 942351053f2SKrzysztof Grobelny if (!success) 943dba0c291SJonathan Doman { 944351053f2SKrzysztof Grobelny messages::internalError(aResp->res); 945351053f2SKrzysztof Grobelny return; 946dba0c291SJonathan Doman } 947dba0c291SJonathan Doman 948351053f2SKrzysztof Grobelny nlohmann::json& json = aResp->res.jsonValue; 949351053f2SKrzysztof Grobelny 950351053f2SKrzysztof Grobelny if (availableCoreCount != nullptr) 951351053f2SKrzysztof Grobelny { 952351053f2SKrzysztof Grobelny json["TotalAvailableCoreCount"] = *availableCoreCount; 953351053f2SKrzysztof Grobelny } 954351053f2SKrzysztof Grobelny 955351053f2SKrzysztof Grobelny if (baseSpeed != nullptr) 956351053f2SKrzysztof Grobelny { 957351053f2SKrzysztof Grobelny json["BaseSpeedMHz"] = *baseSpeed; 958351053f2SKrzysztof Grobelny } 959351053f2SKrzysztof Grobelny 960351053f2SKrzysztof Grobelny if (maxJunctionTemperature != nullptr) 961351053f2SKrzysztof Grobelny { 962351053f2SKrzysztof Grobelny json["MaxJunctionTemperatureCelsius"] = *maxJunctionTemperature; 963351053f2SKrzysztof Grobelny } 964351053f2SKrzysztof Grobelny 965351053f2SKrzysztof Grobelny if (maxSpeed != nullptr) 966351053f2SKrzysztof Grobelny { 967351053f2SKrzysztof Grobelny json["MaxSpeedMHz"] = *maxSpeed; 968351053f2SKrzysztof Grobelny } 969351053f2SKrzysztof Grobelny 970351053f2SKrzysztof Grobelny if (powerLimit != nullptr) 971351053f2SKrzysztof Grobelny { 972351053f2SKrzysztof Grobelny json["TDPWatts"] = *powerLimit; 973351053f2SKrzysztof Grobelny } 974351053f2SKrzysztof Grobelny 975351053f2SKrzysztof Grobelny if (turboProfile != nullptr) 976351053f2SKrzysztof Grobelny { 977dba0c291SJonathan Doman nlohmann::json& turboArray = json["TurboProfile"]; 978dba0c291SJonathan Doman turboArray = nlohmann::json::array(); 979351053f2SKrzysztof Grobelny for (const auto& [turboSpeed, coreCount] : *turboProfile) 980dba0c291SJonathan Doman { 9811476687dSEd Tanous nlohmann::json::object_t turbo; 9821476687dSEd Tanous turbo["ActiveCoreCount"] = coreCount; 9831476687dSEd Tanous turbo["MaxSpeedMHz"] = turboSpeed; 984b2ba3072SPatrick Williams turboArray.emplace_back(std::move(turbo)); 985dba0c291SJonathan Doman } 986dba0c291SJonathan Doman } 987dba0c291SJonathan Doman 988351053f2SKrzysztof Grobelny if (baseSpeedPrioritySettings != nullptr) 989351053f2SKrzysztof Grobelny { 990351053f2SKrzysztof Grobelny nlohmann::json& baseSpeedArray = json["BaseSpeedPrioritySettings"]; 991dba0c291SJonathan Doman baseSpeedArray = nlohmann::json::array(); 992351053f2SKrzysztof Grobelny for (const auto& [baseSpeedMhz, coreList] : 993351053f2SKrzysztof Grobelny *baseSpeedPrioritySettings) 994dba0c291SJonathan Doman { 9951476687dSEd Tanous nlohmann::json::object_t speed; 9961476687dSEd Tanous speed["CoreCount"] = coreList.size(); 9971476687dSEd Tanous speed["CoreIDs"] = coreList; 998351053f2SKrzysztof Grobelny speed["BaseSpeedMHz"] = baseSpeedMhz; 999b2ba3072SPatrick Williams baseSpeedArray.emplace_back(std::move(speed)); 1000dba0c291SJonathan Doman } 1001dba0c291SJonathan Doman } 1002351053f2SKrzysztof Grobelny }); 1003dba0c291SJonathan Doman } 1004dba0c291SJonathan Doman 10053cde86f1SJonathan Doman /** 10063cde86f1SJonathan Doman * Handle the D-Bus response from attempting to set the CPU's AppliedConfig 10073cde86f1SJonathan Doman * property. Main task is to translate error messages into Redfish errors. 10083cde86f1SJonathan Doman * 10093cde86f1SJonathan Doman * @param[in,out] resp HTTP response. 10103cde86f1SJonathan Doman * @param[in] setPropVal Value which we attempted to set. 10113cde86f1SJonathan Doman * @param[in] ec D-Bus response error code. 10123cde86f1SJonathan Doman * @param[in] msg D-Bus response message. 10133cde86f1SJonathan Doman */ 10143cde86f1SJonathan Doman inline void 10153cde86f1SJonathan Doman handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp, 10163cde86f1SJonathan Doman const std::string& setPropVal, 10175e7e2dc5SEd Tanous const boost::system::error_code& ec, 101859d494eeSPatrick Williams const sdbusplus::message_t& msg) 10193cde86f1SJonathan Doman { 10203cde86f1SJonathan Doman if (!ec) 10213cde86f1SJonathan Doman { 10223cde86f1SJonathan Doman BMCWEB_LOG_DEBUG << "Set Property succeeded"; 10233cde86f1SJonathan Doman return; 10243cde86f1SJonathan Doman } 10253cde86f1SJonathan Doman 10263cde86f1SJonathan Doman BMCWEB_LOG_DEBUG << "Set Property failed: " << ec; 10273cde86f1SJonathan Doman 10283cde86f1SJonathan Doman const sd_bus_error* dbusError = msg.get_error(); 10293cde86f1SJonathan Doman if (dbusError == nullptr) 10303cde86f1SJonathan Doman { 10313cde86f1SJonathan Doman messages::internalError(resp->res); 10323cde86f1SJonathan Doman return; 10333cde86f1SJonathan Doman } 10343cde86f1SJonathan Doman 10353cde86f1SJonathan Doman // The asio error code doesn't know about our custom errors, so we have to 10363cde86f1SJonathan Doman // parse the error string. Some of these D-Bus -> Redfish translations are a 10373cde86f1SJonathan Doman // stretch, but it's good to try to communicate something vaguely useful. 10383cde86f1SJonathan Doman if (strcmp(dbusError->name, 10393cde86f1SJonathan Doman "xyz.openbmc_project.Common.Error.InvalidArgument") == 0) 10403cde86f1SJonathan Doman { 10413cde86f1SJonathan Doman // Service did not like the object_path we tried to set. 10423cde86f1SJonathan Doman messages::propertyValueIncorrect( 10433cde86f1SJonathan Doman resp->res, "AppliedOperatingConfig/@odata.id", setPropVal); 10443cde86f1SJonathan Doman } 10453cde86f1SJonathan Doman else if (strcmp(dbusError->name, 10463cde86f1SJonathan Doman "xyz.openbmc_project.Common.Error.NotAllowed") == 0) 10473cde86f1SJonathan Doman { 10483cde86f1SJonathan Doman // Service indicates we can never change the config for this processor. 10493cde86f1SJonathan Doman messages::propertyNotWritable(resp->res, "AppliedOperatingConfig"); 10503cde86f1SJonathan Doman } 10513cde86f1SJonathan Doman else if (strcmp(dbusError->name, 10523cde86f1SJonathan Doman "xyz.openbmc_project.Common.Error.Unavailable") == 0) 10533cde86f1SJonathan Doman { 10543cde86f1SJonathan Doman // Service indicates the config cannot be changed right now, but maybe 10553cde86f1SJonathan Doman // in a different system state. 10563cde86f1SJonathan Doman messages::resourceInStandby(resp->res); 10573cde86f1SJonathan Doman } 10583cde86f1SJonathan Doman else 10593cde86f1SJonathan Doman { 10603cde86f1SJonathan Doman messages::internalError(resp->res); 10613cde86f1SJonathan Doman } 10623cde86f1SJonathan Doman } 10633cde86f1SJonathan Doman 10643cde86f1SJonathan Doman /** 10653cde86f1SJonathan Doman * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic 10663cde86f1SJonathan Doman * validation of the input data, and then set the D-Bus property. 10673cde86f1SJonathan Doman * 10683cde86f1SJonathan Doman * @param[in,out] resp Async HTTP response. 10693cde86f1SJonathan Doman * @param[in] processorId Processor's Id. 10703cde86f1SJonathan Doman * @param[in] appliedConfigUri New property value to apply. 10713cde86f1SJonathan Doman * @param[in] cpuObjectPath Path of CPU object to modify. 10723cde86f1SJonathan Doman * @param[in] serviceMap Service map for CPU object. 10733cde86f1SJonathan Doman */ 10743cde86f1SJonathan Doman inline void patchAppliedOperatingConfig( 10753cde86f1SJonathan Doman const std::shared_ptr<bmcweb::AsyncResp>& resp, 10763cde86f1SJonathan Doman const std::string& processorId, const std::string& appliedConfigUri, 10775df6eda2SShantappa Teekappanavar const std::string& cpuObjectPath, 10785df6eda2SShantappa Teekappanavar const dbus::utility::MapperServiceMap& serviceMap) 10793cde86f1SJonathan Doman { 10803cde86f1SJonathan Doman // Check that the property even exists by checking for the interface 10813cde86f1SJonathan Doman const std::string* controlService = nullptr; 10823cde86f1SJonathan Doman for (const auto& [serviceName, interfaceList] : serviceMap) 10833cde86f1SJonathan Doman { 10843cde86f1SJonathan Doman if (std::find(interfaceList.begin(), interfaceList.end(), 10853cde86f1SJonathan Doman "xyz.openbmc_project.Control.Processor." 10863cde86f1SJonathan Doman "CurrentOperatingConfig") != interfaceList.end()) 10873cde86f1SJonathan Doman { 10883cde86f1SJonathan Doman controlService = &serviceName; 10893cde86f1SJonathan Doman break; 10903cde86f1SJonathan Doman } 10913cde86f1SJonathan Doman } 10923cde86f1SJonathan Doman 10933cde86f1SJonathan Doman if (controlService == nullptr) 10943cde86f1SJonathan Doman { 10953cde86f1SJonathan Doman messages::internalError(resp->res); 10963cde86f1SJonathan Doman return; 10973cde86f1SJonathan Doman } 10983cde86f1SJonathan Doman 10993cde86f1SJonathan Doman // Check that the config URI is a child of the cpu URI being patched. 11003cde86f1SJonathan Doman std::string expectedPrefix("/redfish/v1/Systems/system/Processors/"); 11013cde86f1SJonathan Doman expectedPrefix += processorId; 11023cde86f1SJonathan Doman expectedPrefix += "/OperatingConfigs/"; 110311ba3979SEd Tanous if (!appliedConfigUri.starts_with(expectedPrefix) || 11043cde86f1SJonathan Doman expectedPrefix.size() == appliedConfigUri.size()) 11053cde86f1SJonathan Doman { 11063cde86f1SJonathan Doman messages::propertyValueIncorrect( 11073cde86f1SJonathan Doman resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri); 11083cde86f1SJonathan Doman return; 11093cde86f1SJonathan Doman } 11103cde86f1SJonathan Doman 11113cde86f1SJonathan Doman // Generate the D-Bus path of the OperatingConfig object, by assuming it's a 11123cde86f1SJonathan Doman // direct child of the CPU object. 11133cde86f1SJonathan Doman // Strip the expectedPrefix from the config URI to get the "filename", and 11143cde86f1SJonathan Doman // append to the CPU's path. 11153cde86f1SJonathan Doman std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size()); 11163cde86f1SJonathan Doman sdbusplus::message::object_path configPath(cpuObjectPath); 11173cde86f1SJonathan Doman configPath /= configBaseName; 11183cde86f1SJonathan Doman 11193cde86f1SJonathan Doman BMCWEB_LOG_INFO << "Setting config to " << configPath.str; 11203cde86f1SJonathan Doman 11213cde86f1SJonathan Doman // Set the property, with handler to check error responses 11223cde86f1SJonathan Doman crow::connections::systemBus->async_method_call( 11235e7e2dc5SEd Tanous [resp, appliedConfigUri](const boost::system::error_code& ec, 112459d494eeSPatrick Williams const sdbusplus::message_t& msg) { 11253cde86f1SJonathan Doman handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg); 11263cde86f1SJonathan Doman }, 11273cde86f1SJonathan Doman *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties", 11283cde86f1SJonathan Doman "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig", 1129168e20c1SEd Tanous "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath))); 11303cde86f1SJonathan Doman } 11313cde86f1SJonathan Doman 113271a24ca4SNikhil Namjoshi inline void handleProcessorHead(crow::App& app, const crow::Request& req, 113371a24ca4SNikhil Namjoshi const std::shared_ptr<bmcweb::AsyncResp>& aResp, 113471a24ca4SNikhil Namjoshi const std::string& /* systemName */, 113571a24ca4SNikhil Namjoshi const std::string& /* processorId */) 113671a24ca4SNikhil Namjoshi { 113771a24ca4SNikhil Namjoshi if (!redfish::setUpRedfishRoute(app, req, aResp)) 113871a24ca4SNikhil Namjoshi { 113971a24ca4SNikhil Namjoshi return; 114071a24ca4SNikhil Namjoshi } 114171a24ca4SNikhil Namjoshi aResp->res.addHeader( 114271a24ca4SNikhil Namjoshi boost::beast::http::field::link, 114371a24ca4SNikhil Namjoshi "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby"); 114471a24ca4SNikhil Namjoshi } 114571a24ca4SNikhil Namjoshi 114671a24ca4SNikhil Namjoshi inline void handleProcessorCollectionHead( 114771a24ca4SNikhil Namjoshi crow::App& app, const crow::Request& req, 114871a24ca4SNikhil Namjoshi const std::shared_ptr<bmcweb::AsyncResp>& aResp, 114971a24ca4SNikhil Namjoshi const std::string& /* systemName */) 115071a24ca4SNikhil Namjoshi { 115171a24ca4SNikhil Namjoshi if (!redfish::setUpRedfishRoute(app, req, aResp)) 115271a24ca4SNikhil Namjoshi { 115371a24ca4SNikhil Namjoshi return; 115471a24ca4SNikhil Namjoshi } 115571a24ca4SNikhil Namjoshi aResp->res.addHeader( 115671a24ca4SNikhil Namjoshi boost::beast::http::field::link, 115771a24ca4SNikhil Namjoshi "</redfish/v1/JsonSchemas/ProcessorCollection/ProcessorCollection.json>; rel=describedby"); 115871a24ca4SNikhil Namjoshi } 115971a24ca4SNikhil Namjoshi 11607e860f15SJohn Edward Broadbent inline void requestRoutesOperatingConfigCollection(App& app) 1161dba0c291SJonathan Doman { 11627e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 11637e860f15SJohn Edward Broadbent app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/") 1164ed398213SEd Tanous .privileges(redfish::privileges::getOperatingConfigCollection) 1165002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1166002d39b4SEd Tanous [&app](const crow::Request& req, 116745ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 11687e860f15SJohn Edward Broadbent const std::string& cpuName) { 11693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117045ca1b86SEd Tanous { 117145ca1b86SEd Tanous return; 117245ca1b86SEd Tanous } 11738d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1174dba0c291SJonathan Doman "#OperatingConfigCollection.OperatingConfigCollection"; 1175ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1176ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Processors/{}/OperatingConfigs", 1177ef4c65b7SEd Tanous cpuName); 11780fda0f12SGeorge Liu asyncResp->res.jsonValue["Name"] = "Operating Config Collection"; 1179dba0c291SJonathan Doman 11807e860f15SJohn Edward Broadbent // First find the matching CPU object so we know how to 11817e860f15SJohn Edward Broadbent // constrain our search for related Config objects. 11827a1dbc48SGeorge Liu const std::array<std::string_view, 1> interfaces = { 11837a1dbc48SGeorge Liu "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"}; 11847a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 11857a1dbc48SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 1186002d39b4SEd Tanous [asyncResp, cpuName]( 11877a1dbc48SGeorge Liu const boost::system::error_code& ec, 1188002d39b4SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& objects) { 1189dba0c291SJonathan Doman if (ec) 1190dba0c291SJonathan Doman { 1191dba0c291SJonathan Doman BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " 1192dba0c291SJonathan Doman << ec.message(); 1193dba0c291SJonathan Doman messages::internalError(asyncResp->res); 1194dba0c291SJonathan Doman return; 1195dba0c291SJonathan Doman } 1196dba0c291SJonathan Doman 1197dba0c291SJonathan Doman for (const std::string& object : objects) 1198dba0c291SJonathan Doman { 119911ba3979SEd Tanous if (!object.ends_with(cpuName)) 1200dba0c291SJonathan Doman { 1201dba0c291SJonathan Doman continue; 1202dba0c291SJonathan Doman } 1203dba0c291SJonathan Doman 12047e860f15SJohn Edward Broadbent // Not expected that there will be multiple matching 12057e860f15SJohn Edward Broadbent // CPU objects, but if there are just use the first 12067e860f15SJohn Edward Broadbent // one. 1207dba0c291SJonathan Doman 12087e860f15SJohn Edward Broadbent // Use the common search routine to construct the 12097e860f15SJohn Edward Broadbent // Collection of all Config objects under this CPU. 12107a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interface { 12117a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig" 12127a1dbc48SGeorge Liu }; 1213dba0c291SJonathan Doman collection_util::getCollectionMembers( 1214dba0c291SJonathan Doman asyncResp, 1215ef4c65b7SEd Tanous boost::urls::format( 1216ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Processors/{}/OperatingConfigs", 1217ef4c65b7SEd Tanous cpuName), 12187a1dbc48SGeorge Liu interface, object.c_str()); 1219dba0c291SJonathan Doman return; 1220dba0c291SJonathan Doman } 12217a1dbc48SGeorge Liu }); 12227e860f15SJohn Edward Broadbent }); 1223dba0c291SJonathan Doman } 1224dba0c291SJonathan Doman 12257e860f15SJohn Edward Broadbent inline void requestRoutesOperatingConfig(App& app) 1226dba0c291SJonathan Doman { 12277e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 12287e860f15SJohn Edward Broadbent app, 12297e860f15SJohn Edward Broadbent "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/") 1230ed398213SEd Tanous .privileges(redfish::privileges::getOperatingConfig) 1231002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1232002d39b4SEd Tanous [&app](const crow::Request& req, 123345ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1234002d39b4SEd Tanous const std::string& cpuName, const std::string& configName) { 12353ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 123645ca1b86SEd Tanous { 123745ca1b86SEd Tanous return; 123845ca1b86SEd Tanous } 12397e860f15SJohn Edward Broadbent // Ask for all objects implementing OperatingConfig so we can search 12407e860f15SJohn Edward Broadbent // for one with a matching name 1241e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 1242e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"}; 1243e99073f5SGeorge Liu dbus::utility::getSubTree( 1244e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 124539662a3bSEd Tanous [asyncResp, cpuName, configName]( 1246e99073f5SGeorge Liu const boost::system::error_code& ec, 12475df6eda2SShantappa Teekappanavar const dbus::utility::MapperGetSubTreeResponse& subtree) { 1248dba0c291SJonathan Doman if (ec) 1249dba0c291SJonathan Doman { 1250dba0c291SJonathan Doman BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " 1251dba0c291SJonathan Doman << ec.message(); 1252dba0c291SJonathan Doman messages::internalError(asyncResp->res); 1253dba0c291SJonathan Doman return; 1254dba0c291SJonathan Doman } 1255002d39b4SEd Tanous const std::string expectedEnding = cpuName + '/' + configName; 1256dba0c291SJonathan Doman for (const auto& [objectPath, serviceMap] : subtree) 1257dba0c291SJonathan Doman { 1258dba0c291SJonathan Doman // Ignore any configs without matching cpuX/configY 125911ba3979SEd Tanous if (!objectPath.ends_with(expectedEnding) || serviceMap.empty()) 1260dba0c291SJonathan Doman { 1261dba0c291SJonathan Doman continue; 1262dba0c291SJonathan Doman } 1263dba0c291SJonathan Doman 1264dba0c291SJonathan Doman nlohmann::json& json = asyncResp->res.jsonValue; 1265002d39b4SEd Tanous json["@odata.type"] = "#OperatingConfig.v1_0_0.OperatingConfig"; 1266ef4c65b7SEd Tanous json["@odata.id"] = boost::urls::format( 1267ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Processors/{}/OperatingConfigs/{}", 1268ef4c65b7SEd Tanous cpuName, configName); 1269dba0c291SJonathan Doman json["Name"] = "Processor Profile"; 1270dba0c291SJonathan Doman json["Id"] = configName; 1271dba0c291SJonathan Doman 1272dba0c291SJonathan Doman // Just use the first implementation of the object - not 12737e860f15SJohn Edward Broadbent // expected that there would be multiple matching 12747e860f15SJohn Edward Broadbent // services 1275002d39b4SEd Tanous getOperatingConfigData(asyncResp, serviceMap.begin()->first, 1276002d39b4SEd Tanous objectPath); 1277dba0c291SJonathan Doman return; 1278dba0c291SJonathan Doman } 1279002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "OperatingConfig", 1280002d39b4SEd Tanous configName); 1281e99073f5SGeorge Liu }); 12827e860f15SJohn Edward Broadbent }); 1283ac6a4445SGunnar Mills } 1284ac6a4445SGunnar Mills 12857e860f15SJohn Edward Broadbent inline void requestRoutesProcessorCollection(App& app) 12867e860f15SJohn Edward Broadbent { 1287ac6a4445SGunnar Mills /** 1288ac6a4445SGunnar Mills * Functions triggers appropriate requests on DBus 1289ac6a4445SGunnar Mills */ 129022d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/") 129171a24ca4SNikhil Namjoshi .privileges(redfish::privileges::headProcessorCollection) 129271a24ca4SNikhil Namjoshi .methods(boost::beast::http::verb::head)( 129371a24ca4SNikhil Namjoshi std::bind_front(handleProcessorCollectionHead, std::ref(app))); 129471a24ca4SNikhil Namjoshi 129571a24ca4SNikhil Namjoshi BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/") 1296ed398213SEd Tanous .privileges(redfish::privileges::getProcessorCollection) 12977e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 129845ca1b86SEd Tanous [&app](const crow::Request& req, 129922d268cbSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 130022d268cbSEd Tanous const std::string& systemName) { 13013ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 130245ca1b86SEd Tanous { 130345ca1b86SEd Tanous return; 130445ca1b86SEd Tanous } 130522d268cbSEd Tanous if (systemName != "system") 130622d268cbSEd Tanous { 130722d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 130822d268cbSEd Tanous systemName); 130922d268cbSEd Tanous return; 131022d268cbSEd Tanous } 131122d268cbSEd Tanous 131271a24ca4SNikhil Namjoshi asyncResp->res.addHeader( 131371a24ca4SNikhil Namjoshi boost::beast::http::field::link, 131471a24ca4SNikhil Namjoshi "</redfish/v1/JsonSchemas/ProcessorCollection/ProcessorCollection.json>; rel=describedby"); 131571a24ca4SNikhil Namjoshi 13168d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1317ac6a4445SGunnar Mills "#ProcessorCollection.ProcessorCollection"; 13188d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Processor Collection"; 1319ac6a4445SGunnar Mills 13208d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = 13218d1b46d7Szhanghch05 "/redfish/v1/Systems/system/Processors"; 1322ac6a4445SGunnar Mills 132305030b8eSGunnar Mills collection_util::getCollectionMembers( 1324ae9031f0SWilly Tu asyncResp, 1325ae9031f0SWilly Tu boost::urls::url("/redfish/v1/Systems/system/Processors"), 13267a1dbc48SGeorge Liu processorInterfaces); 13277e860f15SJohn Edward Broadbent }); 1328ac6a4445SGunnar Mills } 1329ac6a4445SGunnar Mills 13307e860f15SJohn Edward Broadbent inline void requestRoutesProcessor(App& app) 13317e860f15SJohn Edward Broadbent { 1332ac6a4445SGunnar Mills /** 1333ac6a4445SGunnar Mills * Functions triggers appropriate requests on DBus 1334ac6a4445SGunnar Mills */ 13357e860f15SJohn Edward Broadbent 133622d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/") 133771a24ca4SNikhil Namjoshi .privileges(redfish::privileges::headProcessor) 133871a24ca4SNikhil Namjoshi .methods(boost::beast::http::verb::head)( 133971a24ca4SNikhil Namjoshi std::bind_front(handleProcessorHead, std::ref(app))); 134071a24ca4SNikhil Namjoshi 134171a24ca4SNikhil Namjoshi BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/") 1342ed398213SEd Tanous .privileges(redfish::privileges::getProcessor) 13437e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 134445ca1b86SEd Tanous [&app](const crow::Request& req, 13457e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 134622d268cbSEd Tanous const std::string& systemName, 13477e860f15SJohn Edward Broadbent const std::string& processorId) { 13483ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 134945ca1b86SEd Tanous { 135045ca1b86SEd Tanous return; 135145ca1b86SEd Tanous } 135222d268cbSEd Tanous if (systemName != "system") 135322d268cbSEd Tanous { 135422d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 135522d268cbSEd Tanous systemName); 135622d268cbSEd Tanous return; 135722d268cbSEd Tanous } 135822d268cbSEd Tanous 135971a24ca4SNikhil Namjoshi asyncResp->res.addHeader( 136071a24ca4SNikhil Namjoshi boost::beast::http::field::link, 136171a24ca4SNikhil Namjoshi "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby"); 13628d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1363*dfbf7de5SChris Cain "#Processor.v1_18_0.Processor"; 1364ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1365ef4c65b7SEd Tanous "/redfish/v1/Systems/system/Processors/{}", processorId); 1366ac6a4445SGunnar Mills 13678a592810SEd Tanous getProcessorObject( 13688a592810SEd Tanous asyncResp, processorId, 13698a592810SEd Tanous std::bind_front(getProcessorData, asyncResp, processorId)); 13707e860f15SJohn Edward Broadbent }); 13713cde86f1SJonathan Doman 137222d268cbSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/") 1373ed398213SEd Tanous .privileges(redfish::privileges::patchProcessor) 13747e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 137545ca1b86SEd Tanous [&app](const crow::Request& req, 13767e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 137722d268cbSEd Tanous const std::string& systemName, 13787e860f15SJohn Edward Broadbent const std::string& processorId) { 13793ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 138045ca1b86SEd Tanous { 138145ca1b86SEd Tanous return; 138245ca1b86SEd Tanous } 138322d268cbSEd Tanous if (systemName != "system") 138422d268cbSEd Tanous { 138522d268cbSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem", 138622d268cbSEd Tanous systemName); 138722d268cbSEd Tanous return; 138822d268cbSEd Tanous } 138922d268cbSEd Tanous 13903cde86f1SJonathan Doman std::optional<nlohmann::json> appliedConfigJson; 139115ed6780SWilly Tu if (!json_util::readJsonPatch(req, asyncResp->res, 13927e860f15SJohn Edward Broadbent "AppliedOperatingConfig", 13933cde86f1SJonathan Doman appliedConfigJson)) 13943cde86f1SJonathan Doman { 13953cde86f1SJonathan Doman return; 13963cde86f1SJonathan Doman } 13973cde86f1SJonathan Doman 13983cde86f1SJonathan Doman if (appliedConfigJson) 13993cde86f1SJonathan Doman { 1400f8fe53e7SEd Tanous std::string appliedConfigUri; 14013cde86f1SJonathan Doman if (!json_util::readJson(*appliedConfigJson, asyncResp->res, 14023cde86f1SJonathan Doman "@odata.id", appliedConfigUri)) 14033cde86f1SJonathan Doman { 14043cde86f1SJonathan Doman return; 14053cde86f1SJonathan Doman } 14067e860f15SJohn Edward Broadbent // Check for 404 and find matching D-Bus object, then run 14077e860f15SJohn Edward Broadbent // property patch handlers if that all succeeds. 14088a592810SEd Tanous getProcessorObject(asyncResp, processorId, 14098a592810SEd Tanous std::bind_front(patchAppliedOperatingConfig, 14107e860f15SJohn Edward Broadbent asyncResp, processorId, 14118a592810SEd Tanous appliedConfigUri)); 14123cde86f1SJonathan Doman } 14137e860f15SJohn Edward Broadbent }); 14143cde86f1SJonathan Doman } 1415ac6a4445SGunnar Mills 1416ac6a4445SGunnar Mills } // namespace redfish 1417