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 18ac6a4445SGunnar Mills #include "health.hpp" 19ac6a4445SGunnar Mills 20ac6a4445SGunnar Mills #include <boost/container/flat_map.hpp> 21ac6a4445SGunnar Mills #include <node.hpp> 22*dba0c291SJonathan Doman #include <sdbusplus/message/native_types.hpp> 23*dba0c291SJonathan Doman #include <sdbusplus/utility/dedup_variant.hpp> 24ac6a4445SGunnar Mills #include <utils/collection.hpp> 25ac6a4445SGunnar Mills #include <utils/json_utils.hpp> 26ac6a4445SGunnar Mills 27ac6a4445SGunnar Mills namespace redfish 28ac6a4445SGunnar Mills { 29ac6a4445SGunnar Mills 30ac6a4445SGunnar Mills using InterfacesProperties = boost::container::flat_map< 31ac6a4445SGunnar Mills std::string, 32ac6a4445SGunnar Mills boost::container::flat_map<std::string, dbus::utility::DbusVariantType>>; 33ac6a4445SGunnar Mills 342bab9831SJonathan Doman using MapperGetSubTreeResponse = std::vector< 352bab9831SJonathan Doman std::pair<std::string, 362bab9831SJonathan Doman std::vector<std::pair<std::string, std::vector<std::string>>>>>; 372bab9831SJonathan Doman 38ac6a4445SGunnar Mills inline void 39ac6a4445SGunnar Mills getCpuDataByInterface(const std::shared_ptr<AsyncResp>& aResp, 40ac6a4445SGunnar Mills const InterfacesProperties& cpuInterfacesProperties) 41ac6a4445SGunnar Mills { 42ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get CPU resources by interface."; 43ac6a4445SGunnar Mills 44ac6a4445SGunnar Mills // Added for future purpose. Once present and functional attributes added 45ac6a4445SGunnar Mills // in busctl call, need to add actual logic to fetch original values. 46ac6a4445SGunnar Mills bool present = false; 47ac6a4445SGunnar Mills const bool functional = true; 48ac6a4445SGunnar Mills auto health = std::make_shared<HealthPopulate>(aResp); 49ac6a4445SGunnar Mills health->populate(); 50ac6a4445SGunnar Mills 51ac6a4445SGunnar Mills for (const auto& interface : cpuInterfacesProperties) 52ac6a4445SGunnar Mills { 53ac6a4445SGunnar Mills for (const auto& property : interface.second) 54ac6a4445SGunnar Mills { 55ac6a4445SGunnar Mills if (property.first == "CoreCount") 56ac6a4445SGunnar Mills { 57ac6a4445SGunnar Mills const uint16_t* coresCount = 58ac6a4445SGunnar Mills std::get_if<uint16_t>(&property.second); 59ac6a4445SGunnar Mills if (coresCount == nullptr) 60ac6a4445SGunnar Mills { 61ac6a4445SGunnar Mills // Important property not in desired type 62ac6a4445SGunnar Mills messages::internalError(aResp->res); 63ac6a4445SGunnar Mills return; 64ac6a4445SGunnar Mills } 65ac6a4445SGunnar Mills if (*coresCount == 0) 66ac6a4445SGunnar Mills { 67ac6a4445SGunnar Mills // Slot is not populated, set status end return 68ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Absent"; 69ac6a4445SGunnar Mills // HTTP Code will be set up automatically, just return 70ac6a4445SGunnar Mills return; 71ac6a4445SGunnar Mills } 72ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Enabled"; 73ac6a4445SGunnar Mills present = true; 74ac6a4445SGunnar Mills aResp->res.jsonValue["TotalCores"] = *coresCount; 75ac6a4445SGunnar Mills } 76dc3fa667SJonathan Doman else if (property.first == "MaxSpeedInMhz") 77dc3fa667SJonathan Doman { 78dc3fa667SJonathan Doman const uint32_t* value = std::get_if<uint32_t>(&property.second); 79dc3fa667SJonathan Doman if (value != nullptr) 80dc3fa667SJonathan Doman { 81dc3fa667SJonathan Doman aResp->res.jsonValue["MaxSpeedMHz"] = *value; 82dc3fa667SJonathan Doman } 83dc3fa667SJonathan Doman } 84ac6a4445SGunnar Mills else if (property.first == "Socket") 85ac6a4445SGunnar Mills { 86ac6a4445SGunnar Mills const std::string* value = 87ac6a4445SGunnar Mills std::get_if<std::string>(&property.second); 88ac6a4445SGunnar Mills if (value != nullptr) 89ac6a4445SGunnar Mills { 90ac6a4445SGunnar Mills aResp->res.jsonValue["Socket"] = *value; 91ac6a4445SGunnar Mills } 92ac6a4445SGunnar Mills } 93ac6a4445SGunnar Mills else if (property.first == "ThreadCount") 94ac6a4445SGunnar Mills { 95dc3fa667SJonathan Doman const uint16_t* value = std::get_if<uint16_t>(&property.second); 96ac6a4445SGunnar Mills if (value != nullptr) 97ac6a4445SGunnar Mills { 98ac6a4445SGunnar Mills aResp->res.jsonValue["TotalThreads"] = *value; 99ac6a4445SGunnar Mills } 100ac6a4445SGunnar Mills } 101ac6a4445SGunnar Mills else if (property.first == "Family") 102ac6a4445SGunnar Mills { 103ac6a4445SGunnar Mills const std::string* value = 104ac6a4445SGunnar Mills std::get_if<std::string>(&property.second); 105ac6a4445SGunnar Mills if (value != nullptr) 106ac6a4445SGunnar Mills { 107ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] = 108ac6a4445SGunnar Mills *value; 109ac6a4445SGunnar Mills } 110ac6a4445SGunnar Mills } 111ac6a4445SGunnar Mills else if (property.first == "Id") 112ac6a4445SGunnar Mills { 113ac6a4445SGunnar Mills const uint64_t* value = std::get_if<uint64_t>(&property.second); 114ac6a4445SGunnar Mills if (value != nullptr && *value != 0) 115ac6a4445SGunnar Mills { 116ac6a4445SGunnar Mills present = true; 117ac6a4445SGunnar Mills aResp->res 118ac6a4445SGunnar Mills .jsonValue["ProcessorId"]["IdentificationRegisters"] = 119ac6a4445SGunnar Mills boost::lexical_cast<std::string>(*value); 120ac6a4445SGunnar Mills } 121ac6a4445SGunnar Mills } 122ac6a4445SGunnar Mills } 123ac6a4445SGunnar Mills } 124ac6a4445SGunnar Mills 125ac6a4445SGunnar Mills if (present == false) 126ac6a4445SGunnar Mills { 127ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Absent"; 128ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["Health"] = "OK"; 129ac6a4445SGunnar Mills } 130ac6a4445SGunnar Mills else 131ac6a4445SGunnar Mills { 132ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Enabled"; 133ac6a4445SGunnar Mills if (functional) 134ac6a4445SGunnar Mills { 135ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["Health"] = "OK"; 136ac6a4445SGunnar Mills } 137ac6a4445SGunnar Mills else 138ac6a4445SGunnar Mills { 139ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["Health"] = "Critical"; 140ac6a4445SGunnar Mills } 141ac6a4445SGunnar Mills } 142ac6a4445SGunnar Mills 143ac6a4445SGunnar Mills return; 144ac6a4445SGunnar Mills } 145ac6a4445SGunnar Mills 146ac6a4445SGunnar Mills inline void getCpuDataByService(std::shared_ptr<AsyncResp> aResp, 147ac6a4445SGunnar Mills const std::string& cpuId, 148ac6a4445SGunnar Mills const std::string& service, 149ac6a4445SGunnar Mills const std::string& objPath) 150ac6a4445SGunnar Mills { 151ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get available system cpu resources by service."; 152ac6a4445SGunnar Mills 153ac6a4445SGunnar Mills crow::connections::systemBus->async_method_call( 154ac6a4445SGunnar Mills [cpuId, service, objPath, aResp{std::move(aResp)}]( 155ac6a4445SGunnar Mills const boost::system::error_code ec, 156ac6a4445SGunnar Mills const dbus::utility::ManagedObjectType& dbusData) { 157ac6a4445SGunnar Mills if (ec) 158ac6a4445SGunnar Mills { 159ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 160ac6a4445SGunnar Mills messages::internalError(aResp->res); 161ac6a4445SGunnar Mills return; 162ac6a4445SGunnar Mills } 163ac6a4445SGunnar Mills aResp->res.jsonValue["Id"] = cpuId; 164ac6a4445SGunnar Mills aResp->res.jsonValue["Name"] = "Processor"; 165ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorType"] = "CPU"; 166ac6a4445SGunnar Mills 167ac6a4445SGunnar Mills bool slotPresent = false; 168ac6a4445SGunnar Mills std::string corePath = objPath + "/core"; 169ac6a4445SGunnar Mills size_t totalCores = 0; 170ac6a4445SGunnar Mills for (const auto& object : dbusData) 171ac6a4445SGunnar Mills { 172ac6a4445SGunnar Mills if (object.first.str == objPath) 173ac6a4445SGunnar Mills { 174ac6a4445SGunnar Mills getCpuDataByInterface(aResp, object.second); 175ac6a4445SGunnar Mills } 176ac6a4445SGunnar Mills else if (boost::starts_with(object.first.str, corePath)) 177ac6a4445SGunnar Mills { 178ac6a4445SGunnar Mills for (const auto& interface : object.second) 179ac6a4445SGunnar Mills { 180ac6a4445SGunnar Mills if (interface.first == 181ac6a4445SGunnar Mills "xyz.openbmc_project.Inventory.Item") 182ac6a4445SGunnar Mills { 183ac6a4445SGunnar Mills for (const auto& property : interface.second) 184ac6a4445SGunnar Mills { 185ac6a4445SGunnar Mills if (property.first == "Present") 186ac6a4445SGunnar Mills { 187ac6a4445SGunnar Mills const bool* present = 188ac6a4445SGunnar Mills std::get_if<bool>(&property.second); 189ac6a4445SGunnar Mills if (present != nullptr) 190ac6a4445SGunnar Mills { 191ac6a4445SGunnar Mills if (*present == true) 192ac6a4445SGunnar Mills { 193ac6a4445SGunnar Mills slotPresent = true; 194ac6a4445SGunnar Mills totalCores++; 195ac6a4445SGunnar Mills } 196ac6a4445SGunnar Mills } 197ac6a4445SGunnar Mills } 198ac6a4445SGunnar Mills } 199ac6a4445SGunnar Mills } 200ac6a4445SGunnar Mills } 201ac6a4445SGunnar Mills } 202ac6a4445SGunnar Mills } 203ac6a4445SGunnar Mills // In getCpuDataByInterface(), state and health are set 204ac6a4445SGunnar Mills // based on the present and functional status. If core 205ac6a4445SGunnar Mills // count is zero, then it has a higher precedence. 206ac6a4445SGunnar Mills if (slotPresent) 207ac6a4445SGunnar Mills { 208ac6a4445SGunnar Mills if (totalCores == 0) 209ac6a4445SGunnar Mills { 210ac6a4445SGunnar Mills // Slot is not populated, set status end return 211ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Absent"; 212ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["Health"] = "OK"; 213ac6a4445SGunnar Mills } 214ac6a4445SGunnar Mills aResp->res.jsonValue["TotalCores"] = totalCores; 215ac6a4445SGunnar Mills } 216ac6a4445SGunnar Mills return; 217ac6a4445SGunnar Mills }, 218ac6a4445SGunnar Mills service, "/xyz/openbmc_project/inventory", 219ac6a4445SGunnar Mills "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 220ac6a4445SGunnar Mills } 221ac6a4445SGunnar Mills 222ac6a4445SGunnar Mills inline void getCpuAssetData(std::shared_ptr<AsyncResp> aResp, 223ac6a4445SGunnar Mills const std::string& service, 224ac6a4445SGunnar Mills const std::string& objPath) 225ac6a4445SGunnar Mills { 226ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get Cpu Asset Data"; 227ac6a4445SGunnar Mills crow::connections::systemBus->async_method_call( 228ac6a4445SGunnar Mills [objPath, aResp{std::move(aResp)}]( 229ac6a4445SGunnar Mills const boost::system::error_code ec, 230ac6a4445SGunnar Mills const boost::container::flat_map< 231ac6a4445SGunnar Mills std::string, std::variant<std::string, uint32_t, uint16_t, 232ac6a4445SGunnar Mills bool>>& properties) { 233ac6a4445SGunnar Mills if (ec) 234ac6a4445SGunnar Mills { 235ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 236ac6a4445SGunnar Mills messages::internalError(aResp->res); 237ac6a4445SGunnar Mills return; 238ac6a4445SGunnar Mills } 239ac6a4445SGunnar Mills 240ac6a4445SGunnar Mills for (const auto& property : properties) 241ac6a4445SGunnar Mills { 242ac6a4445SGunnar Mills if (property.first == "SerialNumber") 243ac6a4445SGunnar Mills { 244ac6a4445SGunnar Mills const std::string* sn = 245ac6a4445SGunnar Mills std::get_if<std::string>(&property.second); 246ac6a4445SGunnar Mills if (sn != nullptr && !sn->empty()) 247ac6a4445SGunnar Mills { 248ac6a4445SGunnar Mills aResp->res.jsonValue["SerialNumber"] = *sn; 249ac6a4445SGunnar Mills } 250ac6a4445SGunnar Mills } 251ac6a4445SGunnar Mills else if (property.first == "Model") 252ac6a4445SGunnar Mills { 253ac6a4445SGunnar Mills const std::string* model = 254ac6a4445SGunnar Mills std::get_if<std::string>(&property.second); 255ac6a4445SGunnar Mills if (model != nullptr && !model->empty()) 256ac6a4445SGunnar Mills { 257ac6a4445SGunnar Mills aResp->res.jsonValue["Model"] = *model; 258ac6a4445SGunnar Mills } 259ac6a4445SGunnar Mills } 260ac6a4445SGunnar Mills else if (property.first == "Manufacturer") 261ac6a4445SGunnar Mills { 262ac6a4445SGunnar Mills 263ac6a4445SGunnar Mills const std::string* mfg = 264ac6a4445SGunnar Mills std::get_if<std::string>(&property.second); 265ac6a4445SGunnar Mills if (mfg != nullptr) 266ac6a4445SGunnar Mills { 267ac6a4445SGunnar Mills aResp->res.jsonValue["Manufacturer"] = *mfg; 268ac6a4445SGunnar Mills 269ac6a4445SGunnar Mills // Otherwise would be unexpected. 270ac6a4445SGunnar Mills if (mfg->find("Intel") != std::string::npos) 271ac6a4445SGunnar Mills { 272ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorArchitecture"] = 273ac6a4445SGunnar Mills "x86"; 274ac6a4445SGunnar Mills aResp->res.jsonValue["InstructionSet"] = "x86-64"; 275ac6a4445SGunnar Mills } 276ac6a4445SGunnar Mills else if (mfg->find("IBM") != std::string::npos) 277ac6a4445SGunnar Mills { 278ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorArchitecture"] = 279ac6a4445SGunnar Mills "Power"; 280ac6a4445SGunnar Mills aResp->res.jsonValue["InstructionSet"] = "PowerISA"; 281ac6a4445SGunnar Mills } 282ac6a4445SGunnar Mills } 283ac6a4445SGunnar Mills } 284ac6a4445SGunnar Mills } 285ac6a4445SGunnar Mills }, 286ac6a4445SGunnar Mills service, objPath, "org.freedesktop.DBus.Properties", "GetAll", 287ac6a4445SGunnar Mills "xyz.openbmc_project.Inventory.Decorator.Asset"); 288ac6a4445SGunnar Mills } 289ac6a4445SGunnar Mills 290ac6a4445SGunnar Mills inline void getCpuRevisionData(std::shared_ptr<AsyncResp> aResp, 291ac6a4445SGunnar Mills const std::string& service, 292ac6a4445SGunnar Mills const std::string& objPath) 293ac6a4445SGunnar Mills { 294ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get Cpu Revision Data"; 295ac6a4445SGunnar Mills crow::connections::systemBus->async_method_call( 296ac6a4445SGunnar Mills [objPath, aResp{std::move(aResp)}]( 297ac6a4445SGunnar Mills const boost::system::error_code ec, 298ac6a4445SGunnar Mills const boost::container::flat_map< 299ac6a4445SGunnar Mills std::string, std::variant<std::string, uint32_t, uint16_t, 300ac6a4445SGunnar Mills bool>>& properties) { 301ac6a4445SGunnar Mills if (ec) 302ac6a4445SGunnar Mills { 303ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 304ac6a4445SGunnar Mills messages::internalError(aResp->res); 305ac6a4445SGunnar Mills return; 306ac6a4445SGunnar Mills } 307ac6a4445SGunnar Mills 308ac6a4445SGunnar Mills for (const auto& property : properties) 309ac6a4445SGunnar Mills { 310ac6a4445SGunnar Mills if (property.first == "Version") 311ac6a4445SGunnar Mills { 312ac6a4445SGunnar Mills const std::string* ver = 313ac6a4445SGunnar Mills std::get_if<std::string>(&property.second); 314ac6a4445SGunnar Mills if (ver != nullptr) 315ac6a4445SGunnar Mills { 316ac6a4445SGunnar Mills aResp->res.jsonValue["Version"] = *ver; 317ac6a4445SGunnar Mills } 318ac6a4445SGunnar Mills break; 319ac6a4445SGunnar Mills } 320ac6a4445SGunnar Mills } 321ac6a4445SGunnar Mills }, 322ac6a4445SGunnar Mills service, objPath, "org.freedesktop.DBus.Properties", "GetAll", 323ac6a4445SGunnar Mills "xyz.openbmc_project.Inventory.Decorator.Revision"); 324ac6a4445SGunnar Mills } 325ac6a4445SGunnar Mills 326ac6a4445SGunnar Mills inline void getAcceleratorDataByService(std::shared_ptr<AsyncResp> aResp, 327ac6a4445SGunnar Mills const std::string& acclrtrId, 328ac6a4445SGunnar Mills const std::string& service, 329ac6a4445SGunnar Mills const std::string& objPath) 330ac6a4445SGunnar Mills { 331ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG 332ac6a4445SGunnar Mills << "Get available system Accelerator resources by service."; 333ac6a4445SGunnar Mills crow::connections::systemBus->async_method_call( 334ac6a4445SGunnar Mills [acclrtrId, aResp{std::move(aResp)}]( 335ac6a4445SGunnar Mills const boost::system::error_code ec, 336ac6a4445SGunnar Mills const boost::container::flat_map< 337ac6a4445SGunnar Mills std::string, std::variant<std::string, uint32_t, uint16_t, 338ac6a4445SGunnar Mills bool>>& properties) { 339ac6a4445SGunnar Mills if (ec) 340ac6a4445SGunnar Mills { 341ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 342ac6a4445SGunnar Mills messages::internalError(aResp->res); 343ac6a4445SGunnar Mills return; 344ac6a4445SGunnar Mills } 345ac6a4445SGunnar Mills aResp->res.jsonValue["Id"] = acclrtrId; 346ac6a4445SGunnar Mills aResp->res.jsonValue["Name"] = "Processor"; 347ac6a4445SGunnar Mills const bool* accPresent = nullptr; 348ac6a4445SGunnar Mills const bool* accFunctional = nullptr; 349ac6a4445SGunnar Mills 350ac6a4445SGunnar Mills for (const auto& property : properties) 351ac6a4445SGunnar Mills { 352ac6a4445SGunnar Mills if (property.first == "Functional") 353ac6a4445SGunnar Mills { 354ac6a4445SGunnar Mills accFunctional = std::get_if<bool>(&property.second); 355ac6a4445SGunnar Mills } 356ac6a4445SGunnar Mills else if (property.first == "Present") 357ac6a4445SGunnar Mills { 358ac6a4445SGunnar Mills accPresent = std::get_if<bool>(&property.second); 359ac6a4445SGunnar Mills } 360ac6a4445SGunnar Mills } 361ac6a4445SGunnar Mills 362ac6a4445SGunnar Mills std::string state = "Enabled"; 363ac6a4445SGunnar Mills std::string health = "OK"; 364ac6a4445SGunnar Mills 365ac6a4445SGunnar Mills if (accPresent != nullptr && *accPresent == false) 366ac6a4445SGunnar Mills { 367ac6a4445SGunnar Mills state = "Absent"; 368ac6a4445SGunnar Mills } 369ac6a4445SGunnar Mills 370ac6a4445SGunnar Mills if ((accFunctional != nullptr) && (*accFunctional == false)) 371ac6a4445SGunnar Mills { 372ac6a4445SGunnar Mills if (state == "Enabled") 373ac6a4445SGunnar Mills { 374ac6a4445SGunnar Mills health = "Critical"; 375ac6a4445SGunnar Mills } 376ac6a4445SGunnar Mills } 377ac6a4445SGunnar Mills 378ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["State"] = state; 379ac6a4445SGunnar Mills aResp->res.jsonValue["Status"]["Health"] = health; 380ac6a4445SGunnar Mills aResp->res.jsonValue["ProcessorType"] = "Accelerator"; 381ac6a4445SGunnar Mills }, 382ac6a4445SGunnar Mills service, objPath, "org.freedesktop.DBus.Properties", "GetAll", ""); 383ac6a4445SGunnar Mills } 384ac6a4445SGunnar Mills 385*dba0c291SJonathan Doman // OperatingConfig D-Bus Types 386*dba0c291SJonathan Doman using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>; 387*dba0c291SJonathan Doman using BaseSpeedPrioritySettingsProperty = 388*dba0c291SJonathan Doman std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>; 389*dba0c291SJonathan Doman // uint32_t and size_t may or may not be the same type, requiring a dedup'd 390*dba0c291SJonathan Doman // variant 391*dba0c291SJonathan Doman using OperatingConfigProperties = std::vector<std::pair< 392*dba0c291SJonathan Doman std::string, 393*dba0c291SJonathan Doman sdbusplus::utility::dedup_variant<uint32_t, size_t, TurboProfileProperty, 394*dba0c291SJonathan Doman BaseSpeedPrioritySettingsProperty>>>; 395*dba0c291SJonathan Doman 396*dba0c291SJonathan Doman /** 397*dba0c291SJonathan Doman * Fill out the HighSpeedCoreIDs in a Processor resource from the given 398*dba0c291SJonathan Doman * OperatingConfig D-Bus property. 399*dba0c291SJonathan Doman * 400*dba0c291SJonathan Doman * @param[in,out] aResp Async HTTP response. 401*dba0c291SJonathan Doman * @param[in] baseSpeedSettings Full list of base speed priority groups, 402*dba0c291SJonathan Doman * to use to determine the list of high 403*dba0c291SJonathan Doman * speed cores. 404*dba0c291SJonathan Doman */ 405*dba0c291SJonathan Doman inline void highSpeedCoreIdsHandler( 406*dba0c291SJonathan Doman const std::shared_ptr<AsyncResp>& aResp, 407*dba0c291SJonathan Doman const BaseSpeedPrioritySettingsProperty& baseSpeedSettings) 408*dba0c291SJonathan Doman { 409*dba0c291SJonathan Doman // The D-Bus property does not indicate which bucket is the "high 410*dba0c291SJonathan Doman // priority" group, so let's discern that by looking for the one with 411*dba0c291SJonathan Doman // highest base frequency. 412*dba0c291SJonathan Doman auto highPriorityGroup = baseSpeedSettings.cend(); 413*dba0c291SJonathan Doman uint32_t highestBaseSpeed = 0; 414*dba0c291SJonathan Doman for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend(); 415*dba0c291SJonathan Doman ++it) 416*dba0c291SJonathan Doman { 417*dba0c291SJonathan Doman const uint32_t baseFreq = std::get<uint32_t>(*it); 418*dba0c291SJonathan Doman if (baseFreq > highestBaseSpeed) 419*dba0c291SJonathan Doman { 420*dba0c291SJonathan Doman highestBaseSpeed = baseFreq; 421*dba0c291SJonathan Doman highPriorityGroup = it; 422*dba0c291SJonathan Doman } 423*dba0c291SJonathan Doman } 424*dba0c291SJonathan Doman 425*dba0c291SJonathan Doman nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"]; 426*dba0c291SJonathan Doman jsonCoreIds = nlohmann::json::array(); 427*dba0c291SJonathan Doman 428*dba0c291SJonathan Doman // There may not be any entries in the D-Bus property, so only populate 429*dba0c291SJonathan Doman // if there was actually something there. 430*dba0c291SJonathan Doman if (highPriorityGroup != baseSpeedSettings.cend()) 431*dba0c291SJonathan Doman { 432*dba0c291SJonathan Doman jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup); 433*dba0c291SJonathan Doman } 434*dba0c291SJonathan Doman } 435*dba0c291SJonathan Doman 436*dba0c291SJonathan Doman /** 437*dba0c291SJonathan Doman * Fill out OperatingConfig related items in a Processor resource by requesting 438*dba0c291SJonathan Doman * data from the given D-Bus object. 439*dba0c291SJonathan Doman * 440*dba0c291SJonathan Doman * @param[in,out] aResp Async HTTP response. 441*dba0c291SJonathan Doman * @param[in] cpuId CPU D-Bus name. 442*dba0c291SJonathan Doman * @param[in] service D-Bus service to query. 443*dba0c291SJonathan Doman * @param[in] objPath D-Bus object to query. 444*dba0c291SJonathan Doman */ 445*dba0c291SJonathan Doman inline void getCpuConfigData(const std::shared_ptr<AsyncResp>& aResp, 446*dba0c291SJonathan Doman const std::string& cpuId, 447*dba0c291SJonathan Doman const std::string& service, 448*dba0c291SJonathan Doman const std::string& objPath) 449*dba0c291SJonathan Doman { 450*dba0c291SJonathan Doman BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId; 451*dba0c291SJonathan Doman 452*dba0c291SJonathan Doman // First, GetAll CurrentOperatingConfig properties on the object 453*dba0c291SJonathan Doman crow::connections::systemBus->async_method_call( 454*dba0c291SJonathan Doman [aResp, cpuId, service]( 455*dba0c291SJonathan Doman const boost::system::error_code ec, 456*dba0c291SJonathan Doman const std::vector< 457*dba0c291SJonathan Doman std::pair<std::string, 458*dba0c291SJonathan Doman std::variant<sdbusplus::message::object_path, bool>>>& 459*dba0c291SJonathan Doman properties) { 460*dba0c291SJonathan Doman if (ec) 461*dba0c291SJonathan Doman { 462*dba0c291SJonathan Doman BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " 463*dba0c291SJonathan Doman << ec.message(); 464*dba0c291SJonathan Doman messages::internalError(aResp->res); 465*dba0c291SJonathan Doman return; 466*dba0c291SJonathan Doman } 467*dba0c291SJonathan Doman 468*dba0c291SJonathan Doman nlohmann::json& json = aResp->res.jsonValue; 469*dba0c291SJonathan Doman 470*dba0c291SJonathan Doman for (const auto& [dbusPropName, variantVal] : properties) 471*dba0c291SJonathan Doman { 472*dba0c291SJonathan Doman if (dbusPropName == "AppliedConfig") 473*dba0c291SJonathan Doman { 474*dba0c291SJonathan Doman const sdbusplus::message::object_path* dbusPathWrapper = 475*dba0c291SJonathan Doman std::get_if<sdbusplus::message::object_path>( 476*dba0c291SJonathan Doman &variantVal); 477*dba0c291SJonathan Doman if (dbusPathWrapper == nullptr) 478*dba0c291SJonathan Doman { 479*dba0c291SJonathan Doman continue; 480*dba0c291SJonathan Doman } 481*dba0c291SJonathan Doman 482*dba0c291SJonathan Doman const std::string& dbusPath = dbusPathWrapper->str; 483*dba0c291SJonathan Doman std::string uri = "/redfish/v1/Systems/system/Processors/" + 484*dba0c291SJonathan Doman cpuId + "/OperatingConfigs"; 485*dba0c291SJonathan Doman json["OperatingConfigs"] = {{"@odata.id", uri}}; 486*dba0c291SJonathan Doman 487*dba0c291SJonathan Doman // Reuse the D-Bus config object name for the Redfish 488*dba0c291SJonathan Doman // URI 489*dba0c291SJonathan Doman size_t baseNamePos = dbusPath.rfind('/'); 490*dba0c291SJonathan Doman if (baseNamePos == std::string::npos || 491*dba0c291SJonathan Doman baseNamePos == (dbusPath.size() - 1)) 492*dba0c291SJonathan Doman { 493*dba0c291SJonathan Doman // If the AppliedConfig was somehow not a valid path, 494*dba0c291SJonathan Doman // skip adding any more properties, since everything 495*dba0c291SJonathan Doman // else is tied to this applied config. 496*dba0c291SJonathan Doman messages::internalError(aResp->res); 497*dba0c291SJonathan Doman break; 498*dba0c291SJonathan Doman } 499*dba0c291SJonathan Doman uri += '/'; 500*dba0c291SJonathan Doman uri += dbusPath.substr(baseNamePos + 1); 501*dba0c291SJonathan Doman json["AppliedOperatingConfig"] = {{"@odata.id", uri}}; 502*dba0c291SJonathan Doman 503*dba0c291SJonathan Doman // Once we found the current applied config, queue another 504*dba0c291SJonathan Doman // request to read the base freq core ids out of that 505*dba0c291SJonathan Doman // config. 506*dba0c291SJonathan Doman crow::connections::systemBus->async_method_call( 507*dba0c291SJonathan Doman [aResp]( 508*dba0c291SJonathan Doman const boost::system::error_code ec, 509*dba0c291SJonathan Doman const std::variant< 510*dba0c291SJonathan Doman BaseSpeedPrioritySettingsProperty>& property) { 511*dba0c291SJonathan Doman if (ec) 512*dba0c291SJonathan Doman { 513*dba0c291SJonathan Doman BMCWEB_LOG_WARNING 514*dba0c291SJonathan Doman << "D-Bus Property Get error: " << ec; 515*dba0c291SJonathan Doman messages::internalError(aResp->res); 516*dba0c291SJonathan Doman return; 517*dba0c291SJonathan Doman } 518*dba0c291SJonathan Doman auto baseSpeedList = 519*dba0c291SJonathan Doman std::get_if<BaseSpeedPrioritySettingsProperty>( 520*dba0c291SJonathan Doman &property); 521*dba0c291SJonathan Doman if (baseSpeedList != nullptr) 522*dba0c291SJonathan Doman { 523*dba0c291SJonathan Doman highSpeedCoreIdsHandler(aResp, *baseSpeedList); 524*dba0c291SJonathan Doman } 525*dba0c291SJonathan Doman }, 526*dba0c291SJonathan Doman service, dbusPath, "org.freedesktop.DBus.Properties", 527*dba0c291SJonathan Doman "Get", 528*dba0c291SJonathan Doman "xyz.openbmc_project.Inventory.Item.Cpu." 529*dba0c291SJonathan Doman "OperatingConfig", 530*dba0c291SJonathan Doman "BaseSpeedPrioritySettings"); 531*dba0c291SJonathan Doman } 532*dba0c291SJonathan Doman else if (dbusPropName == "BaseSpeedPriorityEnabled") 533*dba0c291SJonathan Doman { 534*dba0c291SJonathan Doman const bool* state = std::get_if<bool>(&variantVal); 535*dba0c291SJonathan Doman if (state != nullptr) 536*dba0c291SJonathan Doman { 537*dba0c291SJonathan Doman json["BaseSpeedPriorityState"] = 538*dba0c291SJonathan Doman *state ? "Enabled" : "Disabled"; 539*dba0c291SJonathan Doman } 540*dba0c291SJonathan Doman } 541*dba0c291SJonathan Doman } 542*dba0c291SJonathan Doman }, 543*dba0c291SJonathan Doman service, objPath, "org.freedesktop.DBus.Properties", "GetAll", 544*dba0c291SJonathan Doman "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"); 545*dba0c291SJonathan Doman } 546*dba0c291SJonathan Doman 547ac6a4445SGunnar Mills inline void getProcessorData(std::shared_ptr<AsyncResp> aResp, 5482bab9831SJonathan Doman const std::string& processorId) 549ac6a4445SGunnar Mills { 550ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "Get available system processor resources."; 551ac6a4445SGunnar Mills 552ac6a4445SGunnar Mills crow::connections::systemBus->async_method_call( 5532bab9831SJonathan Doman [processorId, 5542bab9831SJonathan Doman aResp{std::move(aResp)}](const boost::system::error_code ec, 5552bab9831SJonathan Doman const MapperGetSubTreeResponse& subtree) { 556ac6a4445SGunnar Mills if (ec) 557ac6a4445SGunnar Mills { 558ac6a4445SGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error"; 559ac6a4445SGunnar Mills messages::internalError(aResp->res); 560ac6a4445SGunnar Mills return; 561ac6a4445SGunnar Mills } 5622bab9831SJonathan Doman for (const auto& [objectPath, serviceMap] : subtree) 563ac6a4445SGunnar Mills { 5642bab9831SJonathan Doman // Ignore any objects which don't end with our desired cpu name 5652bab9831SJonathan Doman if (!boost::ends_with(objectPath, processorId)) 566ac6a4445SGunnar Mills { 5672bab9831SJonathan Doman continue; 568ac6a4445SGunnar Mills } 5692bab9831SJonathan Doman 5702bab9831SJonathan Doman // Process the first object which does match our cpu name 5712bab9831SJonathan Doman // suffix, and potentially ignore any other matching objects. 5722bab9831SJonathan Doman // Assume all interfaces we want to process must be on the same 5732bab9831SJonathan Doman // object. 5742bab9831SJonathan Doman 5752bab9831SJonathan Doman for (const auto& [serviceName, interfaceList] : serviceMap) 576ac6a4445SGunnar Mills { 5772bab9831SJonathan Doman for (const auto& interface : interfaceList) 5782bab9831SJonathan Doman { 5792bab9831SJonathan Doman if (interface == 5802bab9831SJonathan Doman "xyz.openbmc_project.Inventory.Decorator.Asset") 5812bab9831SJonathan Doman { 5822bab9831SJonathan Doman getCpuAssetData(aResp, serviceName, objectPath); 583ac6a4445SGunnar Mills } 5842bab9831SJonathan Doman else if (interface == "xyz.openbmc_project.Inventory." 5852bab9831SJonathan Doman "Decorator.Revision") 586ac6a4445SGunnar Mills { 5872bab9831SJonathan Doman getCpuRevisionData(aResp, serviceName, objectPath); 588ac6a4445SGunnar Mills } 5892bab9831SJonathan Doman else if (interface == 5902bab9831SJonathan Doman "xyz.openbmc_project.Inventory.Item.Cpu") 591ac6a4445SGunnar Mills { 5922bab9831SJonathan Doman getCpuDataByService(aResp, processorId, serviceName, 5932bab9831SJonathan Doman objectPath); 5942bab9831SJonathan Doman } 5952bab9831SJonathan Doman else if (interface == "xyz.openbmc_project.Inventory." 5962bab9831SJonathan Doman "Item.Accelerator") 5972bab9831SJonathan Doman { 5982bab9831SJonathan Doman getAcceleratorDataByService( 5992bab9831SJonathan Doman aResp, processorId, serviceName, objectPath); 600ac6a4445SGunnar Mills } 601*dba0c291SJonathan Doman else if (interface == 602*dba0c291SJonathan Doman "xyz.openbmc_project.Control.Processor." 603*dba0c291SJonathan Doman "CurrentOperatingConfig") 604*dba0c291SJonathan Doman { 605*dba0c291SJonathan Doman getCpuConfigData(aResp, processorId, serviceName, 606*dba0c291SJonathan Doman objectPath); 607*dba0c291SJonathan Doman } 608ac6a4445SGunnar Mills } 609ac6a4445SGunnar Mills } 610ac6a4445SGunnar Mills return; 611ac6a4445SGunnar Mills } 612ac6a4445SGunnar Mills // Object not found 613ac6a4445SGunnar Mills messages::resourceNotFound(aResp->res, "Processor", processorId); 614ac6a4445SGunnar Mills return; 615ac6a4445SGunnar Mills }, 616ac6a4445SGunnar Mills "xyz.openbmc_project.ObjectMapper", 617ac6a4445SGunnar Mills "/xyz/openbmc_project/object_mapper", 618ac6a4445SGunnar Mills "xyz.openbmc_project.ObjectMapper", "GetSubTree", 6192bab9831SJonathan Doman "/xyz/openbmc_project/inventory", 0, 620*dba0c291SJonathan Doman std::array<const char*, 5>{ 6212bab9831SJonathan Doman "xyz.openbmc_project.Inventory.Decorator.Asset", 6222bab9831SJonathan Doman "xyz.openbmc_project.Inventory.Decorator.Revision", 6232bab9831SJonathan Doman "xyz.openbmc_project.Inventory.Item.Cpu", 624*dba0c291SJonathan Doman "xyz.openbmc_project.Inventory.Item.Accelerator", 625*dba0c291SJonathan Doman "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"}); 626ac6a4445SGunnar Mills } 627ac6a4445SGunnar Mills 628*dba0c291SJonathan Doman /** 629*dba0c291SJonathan Doman * Request all the properties for the given D-Bus object and fill out the 630*dba0c291SJonathan Doman * related entries in the Redfish OperatingConfig response. 631*dba0c291SJonathan Doman * 632*dba0c291SJonathan Doman * @param[in,out] aResp Async HTTP response. 633*dba0c291SJonathan Doman * @param[in] service D-Bus service name to query. 634*dba0c291SJonathan Doman * @param[in] objPath D-Bus object to query. 635*dba0c291SJonathan Doman */ 636*dba0c291SJonathan Doman inline void getOperatingConfigData(const std::shared_ptr<AsyncResp>& aResp, 637*dba0c291SJonathan Doman const std::string& service, 638*dba0c291SJonathan Doman const std::string& objPath) 639*dba0c291SJonathan Doman { 640*dba0c291SJonathan Doman crow::connections::systemBus->async_method_call( 641*dba0c291SJonathan Doman [aResp](boost::system::error_code ec, 642*dba0c291SJonathan Doman const OperatingConfigProperties& properties) { 643*dba0c291SJonathan Doman if (ec) 644*dba0c291SJonathan Doman { 645*dba0c291SJonathan Doman BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " 646*dba0c291SJonathan Doman << ec.message(); 647*dba0c291SJonathan Doman messages::internalError(aResp->res); 648*dba0c291SJonathan Doman return; 649*dba0c291SJonathan Doman } 650*dba0c291SJonathan Doman 651*dba0c291SJonathan Doman nlohmann::json& json = aResp->res.jsonValue; 652*dba0c291SJonathan Doman for (const auto& [key, variant] : properties) 653*dba0c291SJonathan Doman { 654*dba0c291SJonathan Doman if (key == "AvailableCoreCount") 655*dba0c291SJonathan Doman { 656*dba0c291SJonathan Doman const size_t* cores = std::get_if<size_t>(&variant); 657*dba0c291SJonathan Doman if (cores != nullptr) 658*dba0c291SJonathan Doman { 659*dba0c291SJonathan Doman json["TotalAvailableCoreCount"] = *cores; 660*dba0c291SJonathan Doman } 661*dba0c291SJonathan Doman } 662*dba0c291SJonathan Doman else if (key == "BaseSpeed") 663*dba0c291SJonathan Doman { 664*dba0c291SJonathan Doman const uint32_t* speed = std::get_if<uint32_t>(&variant); 665*dba0c291SJonathan Doman if (speed != nullptr) 666*dba0c291SJonathan Doman { 667*dba0c291SJonathan Doman json["BaseSpeedMHz"] = *speed; 668*dba0c291SJonathan Doman } 669*dba0c291SJonathan Doman } 670*dba0c291SJonathan Doman else if (key == "MaxJunctionTemperature") 671*dba0c291SJonathan Doman { 672*dba0c291SJonathan Doman const uint32_t* temp = std::get_if<uint32_t>(&variant); 673*dba0c291SJonathan Doman if (temp != nullptr) 674*dba0c291SJonathan Doman { 675*dba0c291SJonathan Doman json["MaxJunctionTemperatureCelsius"] = *temp; 676*dba0c291SJonathan Doman } 677*dba0c291SJonathan Doman } 678*dba0c291SJonathan Doman else if (key == "MaxSpeed") 679*dba0c291SJonathan Doman { 680*dba0c291SJonathan Doman const uint32_t* speed = std::get_if<uint32_t>(&variant); 681*dba0c291SJonathan Doman if (speed != nullptr) 682*dba0c291SJonathan Doman { 683*dba0c291SJonathan Doman json["MaxSpeedMHz"] = *speed; 684*dba0c291SJonathan Doman } 685*dba0c291SJonathan Doman } 686*dba0c291SJonathan Doman else if (key == "PowerLimit") 687*dba0c291SJonathan Doman { 688*dba0c291SJonathan Doman const uint32_t* tdp = std::get_if<uint32_t>(&variant); 689*dba0c291SJonathan Doman if (tdp != nullptr) 690*dba0c291SJonathan Doman { 691*dba0c291SJonathan Doman json["TDPWatts"] = *tdp; 692*dba0c291SJonathan Doman } 693*dba0c291SJonathan Doman } 694*dba0c291SJonathan Doman else if (key == "TurboProfile") 695*dba0c291SJonathan Doman { 696*dba0c291SJonathan Doman const auto* turboList = 697*dba0c291SJonathan Doman std::get_if<TurboProfileProperty>(&variant); 698*dba0c291SJonathan Doman if (turboList == nullptr) 699*dba0c291SJonathan Doman { 700*dba0c291SJonathan Doman continue; 701*dba0c291SJonathan Doman } 702*dba0c291SJonathan Doman 703*dba0c291SJonathan Doman nlohmann::json& turboArray = json["TurboProfile"]; 704*dba0c291SJonathan Doman turboArray = nlohmann::json::array(); 705*dba0c291SJonathan Doman for (const auto& [turboSpeed, coreCount] : *turboList) 706*dba0c291SJonathan Doman { 707*dba0c291SJonathan Doman turboArray.push_back({{"ActiveCoreCount", coreCount}, 708*dba0c291SJonathan Doman {"MaxSpeedMHz", turboSpeed}}); 709*dba0c291SJonathan Doman } 710*dba0c291SJonathan Doman } 711*dba0c291SJonathan Doman else if (key == "BaseSpeedPrioritySettings") 712*dba0c291SJonathan Doman { 713*dba0c291SJonathan Doman const auto* baseSpeedList = 714*dba0c291SJonathan Doman std::get_if<BaseSpeedPrioritySettingsProperty>( 715*dba0c291SJonathan Doman &variant); 716*dba0c291SJonathan Doman if (baseSpeedList == nullptr) 717*dba0c291SJonathan Doman { 718*dba0c291SJonathan Doman continue; 719*dba0c291SJonathan Doman } 720*dba0c291SJonathan Doman 721*dba0c291SJonathan Doman nlohmann::json& baseSpeedArray = 722*dba0c291SJonathan Doman json["BaseSpeedPrioritySettings"]; 723*dba0c291SJonathan Doman baseSpeedArray = nlohmann::json::array(); 724*dba0c291SJonathan Doman for (const auto& [baseSpeed, coreList] : *baseSpeedList) 725*dba0c291SJonathan Doman { 726*dba0c291SJonathan Doman baseSpeedArray.push_back( 727*dba0c291SJonathan Doman {{"CoreCount", coreList.size()}, 728*dba0c291SJonathan Doman {"CoreIDs", coreList}, 729*dba0c291SJonathan Doman {"BaseSpeedMHz", baseSpeed}}); 730*dba0c291SJonathan Doman } 731*dba0c291SJonathan Doman } 732*dba0c291SJonathan Doman } 733*dba0c291SJonathan Doman }, 734*dba0c291SJonathan Doman service, objPath, "org.freedesktop.DBus.Properties", "GetAll", 735*dba0c291SJonathan Doman "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"); 736*dba0c291SJonathan Doman } 737*dba0c291SJonathan Doman 738*dba0c291SJonathan Doman class OperatingConfigCollection : public Node 739*dba0c291SJonathan Doman { 740*dba0c291SJonathan Doman public: 741*dba0c291SJonathan Doman OperatingConfigCollection(App& app) : 742*dba0c291SJonathan Doman Node(app, 743*dba0c291SJonathan Doman "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/", 744*dba0c291SJonathan Doman std::string()) 745*dba0c291SJonathan Doman { 746*dba0c291SJonathan Doman // Defined by Redfish spec privilege registry 747*dba0c291SJonathan Doman entityPrivileges = { 748*dba0c291SJonathan Doman {boost::beast::http::verb::get, {{"Login"}}}, 749*dba0c291SJonathan Doman {boost::beast::http::verb::head, {{"Login"}}}, 750*dba0c291SJonathan Doman {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 751*dba0c291SJonathan Doman {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 752*dba0c291SJonathan Doman {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 753*dba0c291SJonathan Doman {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 754*dba0c291SJonathan Doman } 755*dba0c291SJonathan Doman 756*dba0c291SJonathan Doman private: 757*dba0c291SJonathan Doman void doGet(crow::Response& res, const crow::Request& req, 758*dba0c291SJonathan Doman const std::vector<std::string>& params) override 759*dba0c291SJonathan Doman { 760*dba0c291SJonathan Doman if (params.size() != 1) 761*dba0c291SJonathan Doman { 762*dba0c291SJonathan Doman messages::internalError(res); 763*dba0c291SJonathan Doman res.end(); 764*dba0c291SJonathan Doman return; 765*dba0c291SJonathan Doman } 766*dba0c291SJonathan Doman 767*dba0c291SJonathan Doman const std::string& cpuName = params[0]; 768*dba0c291SJonathan Doman res.jsonValue["@odata.type"] = 769*dba0c291SJonathan Doman "#OperatingConfigCollection.OperatingConfigCollection"; 770*dba0c291SJonathan Doman res.jsonValue["@odata.id"] = req.url; 771*dba0c291SJonathan Doman res.jsonValue["Name"] = "Operating Config Collection"; 772*dba0c291SJonathan Doman 773*dba0c291SJonathan Doman auto asyncResp = std::make_shared<AsyncResp>(res); 774*dba0c291SJonathan Doman 775*dba0c291SJonathan Doman // First find the matching CPU object so we know how to constrain our 776*dba0c291SJonathan Doman // search for related Config objects. 777*dba0c291SJonathan Doman crow::connections::systemBus->async_method_call( 778*dba0c291SJonathan Doman [asyncResp, cpuName](const boost::system::error_code ec, 779*dba0c291SJonathan Doman const std::vector<std::string>& objects) { 780*dba0c291SJonathan Doman if (ec) 781*dba0c291SJonathan Doman { 782*dba0c291SJonathan Doman BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " 783*dba0c291SJonathan Doman << ec.message(); 784*dba0c291SJonathan Doman messages::internalError(asyncResp->res); 785*dba0c291SJonathan Doman return; 786*dba0c291SJonathan Doman } 787*dba0c291SJonathan Doman 788*dba0c291SJonathan Doman for (const std::string& object : objects) 789*dba0c291SJonathan Doman { 790*dba0c291SJonathan Doman if (!boost::ends_with(object, cpuName)) 791*dba0c291SJonathan Doman { 792*dba0c291SJonathan Doman continue; 793*dba0c291SJonathan Doman } 794*dba0c291SJonathan Doman 795*dba0c291SJonathan Doman // Not expected that there will be multiple matching CPU 796*dba0c291SJonathan Doman // objects, but if there are just use the first one. 797*dba0c291SJonathan Doman 798*dba0c291SJonathan Doman // Use the common search routine to construct the Collection 799*dba0c291SJonathan Doman // of all Config objects under this CPU. 800*dba0c291SJonathan Doman collection_util::getCollectionMembers( 801*dba0c291SJonathan Doman asyncResp, 802*dba0c291SJonathan Doman "/redfish/v1/Systems/system/Processors/" + cpuName + 803*dba0c291SJonathan Doman "/OperatingConfigs", 804*dba0c291SJonathan Doman {"xyz.openbmc_project.Inventory.Item.Cpu." 805*dba0c291SJonathan Doman "OperatingConfig"}, 806*dba0c291SJonathan Doman object.c_str()); 807*dba0c291SJonathan Doman return; 808*dba0c291SJonathan Doman } 809*dba0c291SJonathan Doman }, 810*dba0c291SJonathan Doman "xyz.openbmc_project.ObjectMapper", 811*dba0c291SJonathan Doman "/xyz/openbmc_project/object_mapper", 812*dba0c291SJonathan Doman "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 813*dba0c291SJonathan Doman "/xyz/openbmc_project/inventory", 0, 814*dba0c291SJonathan Doman std::array<const char*, 1>{"xyz.openbmc_project.Control.Processor." 815*dba0c291SJonathan Doman "CurrentOperatingConfig"}); 816*dba0c291SJonathan Doman } 817*dba0c291SJonathan Doman }; 818*dba0c291SJonathan Doman 819*dba0c291SJonathan Doman class OperatingConfig : public Node 820*dba0c291SJonathan Doman { 821*dba0c291SJonathan Doman public: 822*dba0c291SJonathan Doman OperatingConfig(App& app) : 823*dba0c291SJonathan Doman Node(app, 824*dba0c291SJonathan Doman "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/" 825*dba0c291SJonathan Doman "<str>/", 826*dba0c291SJonathan Doman std::string(), std::string()) 827*dba0c291SJonathan Doman { 828*dba0c291SJonathan Doman // Defined by Redfish spec privilege registry 829*dba0c291SJonathan Doman entityPrivileges = { 830*dba0c291SJonathan Doman {boost::beast::http::verb::get, {{"Login"}}}, 831*dba0c291SJonathan Doman {boost::beast::http::verb::head, {{"Login"}}}, 832*dba0c291SJonathan Doman {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 833*dba0c291SJonathan Doman {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 834*dba0c291SJonathan Doman {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 835*dba0c291SJonathan Doman {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 836*dba0c291SJonathan Doman } 837*dba0c291SJonathan Doman 838*dba0c291SJonathan Doman private: 839*dba0c291SJonathan Doman void doGet(crow::Response& res, const crow::Request& req, 840*dba0c291SJonathan Doman const std::vector<std::string>& params) override 841*dba0c291SJonathan Doman { 842*dba0c291SJonathan Doman if (params.size() != 2) 843*dba0c291SJonathan Doman { 844*dba0c291SJonathan Doman messages::internalError(res); 845*dba0c291SJonathan Doman res.end(); 846*dba0c291SJonathan Doman return; 847*dba0c291SJonathan Doman } 848*dba0c291SJonathan Doman 849*dba0c291SJonathan Doman const std::string& cpuName = params[0]; 850*dba0c291SJonathan Doman const std::string& configName = params[1]; 851*dba0c291SJonathan Doman 852*dba0c291SJonathan Doman auto asyncResp = std::make_shared<AsyncResp>(res); 853*dba0c291SJonathan Doman 854*dba0c291SJonathan Doman // Ask for all objects implementing OperatingConfig so we can search for 855*dba0c291SJonathan Doman // one with a matching name 856*dba0c291SJonathan Doman crow::connections::systemBus->async_method_call( 857*dba0c291SJonathan Doman [asyncResp, cpuName, configName, 858*dba0c291SJonathan Doman reqUrl{req.url}](boost::system::error_code ec, 859*dba0c291SJonathan Doman const MapperGetSubTreeResponse& subtree) { 860*dba0c291SJonathan Doman if (ec) 861*dba0c291SJonathan Doman { 862*dba0c291SJonathan Doman BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " 863*dba0c291SJonathan Doman << ec.message(); 864*dba0c291SJonathan Doman messages::internalError(asyncResp->res); 865*dba0c291SJonathan Doman return; 866*dba0c291SJonathan Doman } 867*dba0c291SJonathan Doman const std::string expectedEnding = cpuName + '/' + configName; 868*dba0c291SJonathan Doman for (const auto& [objectPath, serviceMap] : subtree) 869*dba0c291SJonathan Doman { 870*dba0c291SJonathan Doman // Ignore any configs without matching cpuX/configY 871*dba0c291SJonathan Doman if (!boost::ends_with(objectPath, expectedEnding) || 872*dba0c291SJonathan Doman serviceMap.empty()) 873*dba0c291SJonathan Doman { 874*dba0c291SJonathan Doman continue; 875*dba0c291SJonathan Doman } 876*dba0c291SJonathan Doman 877*dba0c291SJonathan Doman nlohmann::json& json = asyncResp->res.jsonValue; 878*dba0c291SJonathan Doman json["@odata.type"] = 879*dba0c291SJonathan Doman "#OperatingConfig.v1_0_0.OperatingConfig"; 880*dba0c291SJonathan Doman json["@odata.id"] = reqUrl; 881*dba0c291SJonathan Doman json["Name"] = "Processor Profile"; 882*dba0c291SJonathan Doman json["Id"] = configName; 883*dba0c291SJonathan Doman 884*dba0c291SJonathan Doman // Just use the first implementation of the object - not 885*dba0c291SJonathan Doman // expected that there would be multiple matching services 886*dba0c291SJonathan Doman getOperatingConfigData(asyncResp, serviceMap.begin()->first, 887*dba0c291SJonathan Doman objectPath); 888*dba0c291SJonathan Doman return; 889*dba0c291SJonathan Doman } 890*dba0c291SJonathan Doman messages::resourceNotFound(asyncResp->res, "OperatingConfig", 891*dba0c291SJonathan Doman configName); 892*dba0c291SJonathan Doman }, 893*dba0c291SJonathan Doman "xyz.openbmc_project.ObjectMapper", 894*dba0c291SJonathan Doman "/xyz/openbmc_project/object_mapper", 895*dba0c291SJonathan Doman "xyz.openbmc_project.ObjectMapper", "GetSubTree", 896*dba0c291SJonathan Doman "/xyz/openbmc_project/inventory", 0, 897*dba0c291SJonathan Doman std::array<const char*, 1>{ 898*dba0c291SJonathan Doman "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"}); 899*dba0c291SJonathan Doman } 900*dba0c291SJonathan Doman }; 901*dba0c291SJonathan Doman 902ac6a4445SGunnar Mills class ProcessorCollection : public Node 903ac6a4445SGunnar Mills { 904ac6a4445SGunnar Mills public: 905ac6a4445SGunnar Mills /* 906ac6a4445SGunnar Mills * Default Constructor 907ac6a4445SGunnar Mills */ 908ac6a4445SGunnar Mills ProcessorCollection(App& app) : 909ac6a4445SGunnar Mills Node(app, "/redfish/v1/Systems/system/Processors/") 910ac6a4445SGunnar Mills { 911ac6a4445SGunnar Mills entityPrivileges = { 912ac6a4445SGunnar Mills {boost::beast::http::verb::get, {{"Login"}}}, 913ac6a4445SGunnar Mills {boost::beast::http::verb::head, {{"Login"}}}, 914ac6a4445SGunnar Mills {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 915ac6a4445SGunnar Mills {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 916ac6a4445SGunnar Mills {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 917ac6a4445SGunnar Mills {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 918ac6a4445SGunnar Mills } 919ac6a4445SGunnar Mills 920ac6a4445SGunnar Mills private: 921ac6a4445SGunnar Mills /** 922ac6a4445SGunnar Mills * Functions triggers appropriate requests on DBus 923ac6a4445SGunnar Mills */ 924ac6a4445SGunnar Mills void doGet(crow::Response& res, const crow::Request&, 925ac6a4445SGunnar Mills const std::vector<std::string>&) override 926ac6a4445SGunnar Mills { 927ac6a4445SGunnar Mills res.jsonValue["@odata.type"] = 928ac6a4445SGunnar Mills "#ProcessorCollection.ProcessorCollection"; 929ac6a4445SGunnar Mills res.jsonValue["Name"] = "Processor Collection"; 930ac6a4445SGunnar Mills 9319dedf572SGunnar Mills res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Processors"; 932ac6a4445SGunnar Mills auto asyncResp = std::make_shared<AsyncResp>(res); 933ac6a4445SGunnar Mills 93405030b8eSGunnar Mills collection_util::getCollectionMembers( 93505030b8eSGunnar Mills asyncResp, "/redfish/v1/Systems/system/Processors", 936ac6a4445SGunnar Mills {"xyz.openbmc_project.Inventory.Item.Cpu", 937ac6a4445SGunnar Mills "xyz.openbmc_project.Inventory.Item.Accelerator"}); 938ac6a4445SGunnar Mills } 939ac6a4445SGunnar Mills }; 940ac6a4445SGunnar Mills 941ac6a4445SGunnar Mills class Processor : public Node 942ac6a4445SGunnar Mills { 943ac6a4445SGunnar Mills public: 944ac6a4445SGunnar Mills /* 945ac6a4445SGunnar Mills * Default Constructor 946ac6a4445SGunnar Mills */ 947ac6a4445SGunnar Mills Processor(App& app) : 948ac6a4445SGunnar Mills Node(app, "/redfish/v1/Systems/system/Processors/<str>/", std::string()) 949ac6a4445SGunnar Mills { 950ac6a4445SGunnar Mills entityPrivileges = { 951ac6a4445SGunnar Mills {boost::beast::http::verb::get, {{"Login"}}}, 952ac6a4445SGunnar Mills {boost::beast::http::verb::head, {{"Login"}}}, 953ac6a4445SGunnar Mills {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 954ac6a4445SGunnar Mills {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 955ac6a4445SGunnar Mills {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 956ac6a4445SGunnar Mills {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 957ac6a4445SGunnar Mills } 958ac6a4445SGunnar Mills 959ac6a4445SGunnar Mills private: 960ac6a4445SGunnar Mills /** 961ac6a4445SGunnar Mills * Functions triggers appropriate requests on DBus 962ac6a4445SGunnar Mills */ 963ac6a4445SGunnar Mills void doGet(crow::Response& res, const crow::Request&, 964ac6a4445SGunnar Mills const std::vector<std::string>& params) override 965ac6a4445SGunnar Mills { 966ac6a4445SGunnar Mills // Check if there is required param, truly entering this shall be 967ac6a4445SGunnar Mills // impossible 968ac6a4445SGunnar Mills if (params.size() != 1) 969ac6a4445SGunnar Mills { 970ac6a4445SGunnar Mills messages::internalError(res); 971ac6a4445SGunnar Mills 972ac6a4445SGunnar Mills res.end(); 973ac6a4445SGunnar Mills return; 974ac6a4445SGunnar Mills } 975ac6a4445SGunnar Mills const std::string& processorId = params[0]; 976ac6a4445SGunnar Mills res.jsonValue["@odata.type"] = "#Processor.v1_9_0.Processor"; 977ac6a4445SGunnar Mills res.jsonValue["@odata.id"] = 978ac6a4445SGunnar Mills "/redfish/v1/Systems/system/Processors/" + processorId; 979ac6a4445SGunnar Mills 980ac6a4445SGunnar Mills auto asyncResp = std::make_shared<AsyncResp>(res); 981ac6a4445SGunnar Mills 9822bab9831SJonathan Doman getProcessorData(asyncResp, processorId); 983ac6a4445SGunnar Mills } 984ac6a4445SGunnar Mills }; 985ac6a4445SGunnar Mills 986ac6a4445SGunnar Mills } // namespace redfish 987