xref: /openbmc/bmcweb/features/redfish/lib/processor.hpp (revision 351053f210e8b233f680bde66d9ea9760c22d848)
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 
181e1e598dSJonathan Doman #include "dbus_singleton.hpp"
191e1e598dSJonathan Doman #include "error_messages.hpp"
20ac6a4445SGunnar Mills #include "health.hpp"
21ac6a4445SGunnar Mills 
227e860f15SJohn Edward Broadbent #include <app.hpp>
23ac6a4445SGunnar Mills #include <boost/container/flat_map.hpp>
24168e20c1SEd Tanous #include <dbus_utility.hpp>
2545ca1b86SEd Tanous #include <query.hpp>
26ed398213SEd Tanous #include <registries/privilege_registry.hpp>
271e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
28dba0c291SJonathan Doman #include <sdbusplus/message/native_types.hpp>
29*351053f2SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
30dba0c291SJonathan Doman #include <sdbusplus/utility/dedup_variant.hpp>
31ac6a4445SGunnar Mills #include <utils/collection.hpp>
32*351053f2SKrzysztof Grobelny #include <utils/dbus_utils.hpp>
33ac6a4445SGunnar Mills #include <utils/json_utils.hpp>
34ac6a4445SGunnar Mills 
35ac6a4445SGunnar Mills namespace redfish
36ac6a4445SGunnar Mills {
37ac6a4445SGunnar Mills 
38c951448aSJonathan Doman // Interfaces which imply a D-Bus object represents a Processor
39c951448aSJonathan Doman constexpr std::array<const char*, 2> processorInterfaces = {
40c951448aSJonathan Doman     "xyz.openbmc_project.Inventory.Item.Cpu",
41c951448aSJonathan Doman     "xyz.openbmc_project.Inventory.Item.Accelerator"};
422bab9831SJonathan Doman 
4371b82f26SSharad Yadav /**
4471b82f26SSharad Yadav  * @brief Fill out uuid info of a processor by
4571b82f26SSharad Yadav  * requesting data from the given D-Bus object.
4671b82f26SSharad Yadav  *
4771b82f26SSharad Yadav  * @param[in,out]   aResp       Async HTTP response.
4871b82f26SSharad Yadav  * @param[in]       service     D-Bus service to query.
4971b82f26SSharad Yadav  * @param[in]       objPath     D-Bus object to query.
5071b82f26SSharad Yadav  */
5171b82f26SSharad Yadav inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp,
5271b82f26SSharad Yadav                              const std::string& service,
5371b82f26SSharad Yadav                              const std::string& objPath)
5471b82f26SSharad Yadav {
5571b82f26SSharad Yadav     BMCWEB_LOG_DEBUG << "Get Processor UUID";
561e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
571e1e598dSJonathan Doman         *crow::connections::systemBus, service, objPath,
581e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
591e1e598dSJonathan Doman         [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
601e1e598dSJonathan Doman                                            const std::string& property) {
6171b82f26SSharad Yadav         if (ec)
6271b82f26SSharad Yadav         {
6371b82f26SSharad Yadav             BMCWEB_LOG_DEBUG << "DBUS response error";
6471b82f26SSharad Yadav             messages::internalError(aResp->res);
6571b82f26SSharad Yadav             return;
6671b82f26SSharad Yadav         }
671e1e598dSJonathan Doman         aResp->res.jsonValue["UUID"] = property;
681e1e598dSJonathan Doman         });
6971b82f26SSharad Yadav }
7071b82f26SSharad Yadav 
71711ac7a9SEd Tanous inline void getCpuDataByInterface(
72711ac7a9SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
73711ac7a9SEd Tanous     const dbus::utility::DBusInteracesMap& cpuInterfacesProperties)
74ac6a4445SGunnar Mills {
75ac6a4445SGunnar Mills     BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
76ac6a4445SGunnar Mills 
77a1649ec6SChicago Duan     // Set the default value of state
78a1649ec6SChicago Duan     aResp->res.jsonValue["Status"]["State"] = "Enabled";
79a1649ec6SChicago Duan     aResp->res.jsonValue["Status"]["Health"] = "OK";
80ac6a4445SGunnar Mills 
81ac6a4445SGunnar Mills     for (const auto& interface : cpuInterfacesProperties)
82ac6a4445SGunnar Mills     {
83ac6a4445SGunnar Mills         for (const auto& property : interface.second)
84ac6a4445SGunnar Mills         {
85a1649ec6SChicago Duan             if (property.first == "Present")
86ac6a4445SGunnar Mills             {
87a1649ec6SChicago Duan                 const bool* cpuPresent = std::get_if<bool>(&property.second);
88a1649ec6SChicago Duan                 if (cpuPresent == nullptr)
89ac6a4445SGunnar Mills                 {
90ac6a4445SGunnar Mills                     // Important property not in desired type
91ac6a4445SGunnar Mills                     messages::internalError(aResp->res);
92ac6a4445SGunnar Mills                     return;
93ac6a4445SGunnar Mills                 }
94e05aec50SEd Tanous                 if (!*cpuPresent)
95ac6a4445SGunnar Mills                 {
96a1649ec6SChicago Duan                     // Slot is not populated
97ac6a4445SGunnar Mills                     aResp->res.jsonValue["Status"]["State"] = "Absent";
98a1649ec6SChicago Duan                 }
99a1649ec6SChicago Duan             }
100a1649ec6SChicago Duan             else if (property.first == "Functional")
101a1649ec6SChicago Duan             {
102a1649ec6SChicago Duan                 const bool* cpuFunctional = std::get_if<bool>(&property.second);
103a1649ec6SChicago Duan                 if (cpuFunctional == nullptr)
104a1649ec6SChicago Duan                 {
105a1649ec6SChicago Duan                     messages::internalError(aResp->res);
106ac6a4445SGunnar Mills                     return;
107ac6a4445SGunnar Mills                 }
108e05aec50SEd Tanous                 if (!*cpuFunctional)
109a1649ec6SChicago Duan                 {
110a1649ec6SChicago Duan                     aResp->res.jsonValue["Status"]["Health"] = "Critical";
111a1649ec6SChicago Duan                 }
112a1649ec6SChicago Duan             }
113a1649ec6SChicago Duan             else if (property.first == "CoreCount")
114a1649ec6SChicago Duan             {
115a1649ec6SChicago Duan                 const uint16_t* coresCount =
116a1649ec6SChicago Duan                     std::get_if<uint16_t>(&property.second);
117a1649ec6SChicago Duan                 if (coresCount == nullptr)
118a1649ec6SChicago Duan                 {
119a1649ec6SChicago Duan                     messages::internalError(aResp->res);
120a1649ec6SChicago Duan                     return;
121a1649ec6SChicago Duan                 }
122ac6a4445SGunnar Mills                 aResp->res.jsonValue["TotalCores"] = *coresCount;
123ac6a4445SGunnar Mills             }
124dc3fa667SJonathan Doman             else if (property.first == "MaxSpeedInMhz")
125dc3fa667SJonathan Doman             {
126dc3fa667SJonathan Doman                 const uint32_t* value = std::get_if<uint32_t>(&property.second);
127dc3fa667SJonathan Doman                 if (value != nullptr)
128dc3fa667SJonathan Doman                 {
129dc3fa667SJonathan Doman                     aResp->res.jsonValue["MaxSpeedMHz"] = *value;
130dc3fa667SJonathan Doman                 }
131dc3fa667SJonathan Doman             }
132ac6a4445SGunnar Mills             else if (property.first == "Socket")
133ac6a4445SGunnar Mills             {
134ac6a4445SGunnar Mills                 const std::string* value =
135ac6a4445SGunnar Mills                     std::get_if<std::string>(&property.second);
136ac6a4445SGunnar Mills                 if (value != nullptr)
137ac6a4445SGunnar Mills                 {
138ac6a4445SGunnar Mills                     aResp->res.jsonValue["Socket"] = *value;
139ac6a4445SGunnar Mills                 }
140ac6a4445SGunnar Mills             }
141ac6a4445SGunnar Mills             else if (property.first == "ThreadCount")
142ac6a4445SGunnar Mills             {
143dc3fa667SJonathan Doman                 const uint16_t* value = std::get_if<uint16_t>(&property.second);
144ac6a4445SGunnar Mills                 if (value != nullptr)
145ac6a4445SGunnar Mills                 {
146ac6a4445SGunnar Mills                     aResp->res.jsonValue["TotalThreads"] = *value;
147ac6a4445SGunnar Mills                 }
148ac6a4445SGunnar Mills             }
1491930fbd4SBrandon Kim             else if (property.first == "EffectiveFamily")
150ac6a4445SGunnar Mills             {
1511930fbd4SBrandon Kim                 const uint16_t* value = std::get_if<uint16_t>(&property.second);
152ac6a4445SGunnar Mills                 if (value != nullptr)
153ac6a4445SGunnar Mills                 {
154ac6a4445SGunnar Mills                     aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
155866e4862SEd Tanous                         "0x" + intToHexString(*value, 4);
156ac6a4445SGunnar Mills                 }
157ac6a4445SGunnar Mills             }
1581930fbd4SBrandon Kim             else if (property.first == "EffectiveModel")
1591930fbd4SBrandon Kim             {
1601930fbd4SBrandon Kim                 const uint16_t* value = std::get_if<uint16_t>(&property.second);
1611930fbd4SBrandon Kim                 if (value == nullptr)
1621930fbd4SBrandon Kim                 {
1631930fbd4SBrandon Kim                     messages::internalError(aResp->res);
1641930fbd4SBrandon Kim                     return;
1651930fbd4SBrandon Kim                 }
1661930fbd4SBrandon Kim                 aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] =
167866e4862SEd Tanous                     "0x" + intToHexString(*value, 4);
1681930fbd4SBrandon Kim             }
169ac6a4445SGunnar Mills             else if (property.first == "Id")
170ac6a4445SGunnar Mills             {
171ac6a4445SGunnar Mills                 const uint64_t* value = std::get_if<uint64_t>(&property.second);
172ac6a4445SGunnar Mills                 if (value != nullptr && *value != 0)
173ac6a4445SGunnar Mills                 {
174ac6a4445SGunnar Mills                     aResp->res
175ac6a4445SGunnar Mills                         .jsonValue["ProcessorId"]["IdentificationRegisters"] =
176866e4862SEd Tanous                         "0x" + intToHexString(*value, 16);
177ac6a4445SGunnar Mills                 }
178ac6a4445SGunnar Mills             }
1791930fbd4SBrandon Kim             else if (property.first == "Microcode")
1801930fbd4SBrandon Kim             {
1811930fbd4SBrandon Kim                 const uint32_t* value = std::get_if<uint32_t>(&property.second);
1821930fbd4SBrandon Kim                 if (value == nullptr)
1831930fbd4SBrandon Kim                 {
1841930fbd4SBrandon Kim                     messages::internalError(aResp->res);
1851930fbd4SBrandon Kim                     return;
1861930fbd4SBrandon Kim                 }
1871930fbd4SBrandon Kim                 aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] =
188866e4862SEd Tanous                     "0x" + intToHexString(*value, 8);
1891930fbd4SBrandon Kim             }
1901930fbd4SBrandon Kim             else if (property.first == "Step")
1911930fbd4SBrandon Kim             {
1921930fbd4SBrandon Kim                 const uint16_t* value = std::get_if<uint16_t>(&property.second);
1931930fbd4SBrandon Kim                 if (value == nullptr)
1941930fbd4SBrandon Kim                 {
1951930fbd4SBrandon Kim                     messages::internalError(aResp->res);
1961930fbd4SBrandon Kim                     return;
1971930fbd4SBrandon Kim                 }
1981930fbd4SBrandon Kim                 aResp->res.jsonValue["ProcessorId"]["Step"] =
199866e4862SEd Tanous                     "0x" + intToHexString(*value, 4);
2001930fbd4SBrandon Kim             }
201ac6a4445SGunnar Mills         }
202ac6a4445SGunnar Mills     }
203ac6a4445SGunnar Mills }
204ac6a4445SGunnar Mills 
2058d1b46d7Szhanghch05 inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
206ac6a4445SGunnar Mills                                 const std::string& cpuId,
207ac6a4445SGunnar Mills                                 const std::string& service,
208ac6a4445SGunnar Mills                                 const std::string& objPath)
209ac6a4445SGunnar Mills {
210ac6a4445SGunnar Mills     BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
211ac6a4445SGunnar Mills 
212ac6a4445SGunnar Mills     crow::connections::systemBus->async_method_call(
213ac6a4445SGunnar Mills         [cpuId, service, objPath, aResp{std::move(aResp)}](
214ac6a4445SGunnar Mills             const boost::system::error_code ec,
215ac6a4445SGunnar Mills             const dbus::utility::ManagedObjectType& dbusData) {
216ac6a4445SGunnar Mills         if (ec)
217ac6a4445SGunnar Mills         {
218ac6a4445SGunnar Mills             BMCWEB_LOG_DEBUG << "DBUS response error";
219ac6a4445SGunnar Mills             messages::internalError(aResp->res);
220ac6a4445SGunnar Mills             return;
221ac6a4445SGunnar Mills         }
222ac6a4445SGunnar Mills         aResp->res.jsonValue["Id"] = cpuId;
223ac6a4445SGunnar Mills         aResp->res.jsonValue["Name"] = "Processor";
224ac6a4445SGunnar Mills         aResp->res.jsonValue["ProcessorType"] = "CPU";
225ac6a4445SGunnar Mills 
226ac6a4445SGunnar Mills         bool slotPresent = false;
227ac6a4445SGunnar Mills         std::string corePath = objPath + "/core";
228ac6a4445SGunnar Mills         size_t totalCores = 0;
229ac6a4445SGunnar Mills         for (const auto& object : dbusData)
230ac6a4445SGunnar Mills         {
231ac6a4445SGunnar Mills             if (object.first.str == objPath)
232ac6a4445SGunnar Mills             {
233ac6a4445SGunnar Mills                 getCpuDataByInterface(aResp, object.second);
234ac6a4445SGunnar Mills             }
23511ba3979SEd Tanous             else if (object.first.str.starts_with(corePath))
236ac6a4445SGunnar Mills             {
237ac6a4445SGunnar Mills                 for (const auto& interface : object.second)
238ac6a4445SGunnar Mills                 {
239002d39b4SEd Tanous                     if (interface.first == "xyz.openbmc_project.Inventory.Item")
240ac6a4445SGunnar Mills                     {
241ac6a4445SGunnar Mills                         for (const auto& property : interface.second)
242ac6a4445SGunnar Mills                         {
243ac6a4445SGunnar Mills                             if (property.first == "Present")
244ac6a4445SGunnar Mills                             {
245ac6a4445SGunnar Mills                                 const bool* present =
246ac6a4445SGunnar Mills                                     std::get_if<bool>(&property.second);
247ac6a4445SGunnar Mills                                 if (present != nullptr)
248ac6a4445SGunnar Mills                                 {
249e05aec50SEd Tanous                                     if (*present)
250ac6a4445SGunnar Mills                                     {
251ac6a4445SGunnar Mills                                         slotPresent = true;
252ac6a4445SGunnar Mills                                         totalCores++;
253ac6a4445SGunnar Mills                                     }
254ac6a4445SGunnar Mills                                 }
255ac6a4445SGunnar Mills                             }
256ac6a4445SGunnar Mills                         }
257ac6a4445SGunnar Mills                     }
258ac6a4445SGunnar Mills                 }
259ac6a4445SGunnar Mills             }
260ac6a4445SGunnar Mills         }
261ac6a4445SGunnar Mills         // In getCpuDataByInterface(), state and health are set
262ac6a4445SGunnar Mills         // based on the present and functional status. If core
263ac6a4445SGunnar Mills         // count is zero, then it has a higher precedence.
264ac6a4445SGunnar Mills         if (slotPresent)
265ac6a4445SGunnar Mills         {
266ac6a4445SGunnar Mills             if (totalCores == 0)
267ac6a4445SGunnar Mills             {
268ac6a4445SGunnar Mills                 // Slot is not populated, set status end return
269ac6a4445SGunnar Mills                 aResp->res.jsonValue["Status"]["State"] = "Absent";
270ac6a4445SGunnar Mills                 aResp->res.jsonValue["Status"]["Health"] = "OK";
271ac6a4445SGunnar Mills             }
272ac6a4445SGunnar Mills             aResp->res.jsonValue["TotalCores"] = totalCores;
273ac6a4445SGunnar Mills         }
274ac6a4445SGunnar Mills         return;
275ac6a4445SGunnar Mills         },
276ac6a4445SGunnar Mills         service, "/xyz/openbmc_project/inventory",
277ac6a4445SGunnar Mills         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
278ac6a4445SGunnar Mills }
279ac6a4445SGunnar Mills 
2808d1b46d7Szhanghch05 inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
281ac6a4445SGunnar Mills                             const std::string& service,
282ac6a4445SGunnar Mills                             const std::string& objPath)
283ac6a4445SGunnar Mills {
284ac6a4445SGunnar Mills     BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
285*351053f2SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
286*351053f2SKrzysztof Grobelny         *crow::connections::systemBus, service, objPath,
287*351053f2SKrzysztof Grobelny         "xyz.openbmc_project.Inventory.Decorator.Asset",
288ac6a4445SGunnar Mills         [objPath, aResp{std::move(aResp)}](
289ac6a4445SGunnar Mills             const boost::system::error_code ec,
290*351053f2SKrzysztof Grobelny             const dbus::utility::DBusPropertiesMap& properties) {
291ac6a4445SGunnar Mills         if (ec)
292ac6a4445SGunnar Mills         {
293ac6a4445SGunnar Mills             BMCWEB_LOG_DEBUG << "DBUS response error";
294ac6a4445SGunnar Mills             messages::internalError(aResp->res);
295ac6a4445SGunnar Mills             return;
296ac6a4445SGunnar Mills         }
297ac6a4445SGunnar Mills 
298*351053f2SKrzysztof Grobelny         const std::string* serialNumber = nullptr;
299*351053f2SKrzysztof Grobelny         const std::string* model = nullptr;
300*351053f2SKrzysztof Grobelny         const std::string* manufacturer = nullptr;
301*351053f2SKrzysztof Grobelny         const std::string* partNumber = nullptr;
302*351053f2SKrzysztof Grobelny         const std::string* sparePartNumber = nullptr;
303*351053f2SKrzysztof Grobelny 
304*351053f2SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
305*351053f2SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "SerialNumber",
306*351053f2SKrzysztof Grobelny             serialNumber, "Model", model, "Manufacturer", manufacturer,
307*351053f2SKrzysztof Grobelny             "PartNumber", partNumber, "SparePartNumber", sparePartNumber);
308*351053f2SKrzysztof Grobelny 
309*351053f2SKrzysztof Grobelny         if (!success)
310ac6a4445SGunnar Mills         {
311*351053f2SKrzysztof Grobelny             messages::internalError(aResp->res);
312*351053f2SKrzysztof Grobelny             return;
313ac6a4445SGunnar Mills         }
314*351053f2SKrzysztof Grobelny 
315*351053f2SKrzysztof Grobelny         if (serialNumber != nullptr && !serialNumber->empty())
316ac6a4445SGunnar Mills         {
317*351053f2SKrzysztof Grobelny             aResp->res.jsonValue["SerialNumber"] = *serialNumber;
318*351053f2SKrzysztof Grobelny         }
319*351053f2SKrzysztof Grobelny 
320*351053f2SKrzysztof Grobelny         if ((model != nullptr) && !model->empty())
321ac6a4445SGunnar Mills         {
322ac6a4445SGunnar Mills             aResp->res.jsonValue["Model"] = *model;
323ac6a4445SGunnar Mills         }
324ac6a4445SGunnar Mills 
325*351053f2SKrzysztof Grobelny         if (manufacturer != nullptr)
326ac6a4445SGunnar Mills         {
327*351053f2SKrzysztof Grobelny             aResp->res.jsonValue["Manufacturer"] = *manufacturer;
328ac6a4445SGunnar Mills 
329ac6a4445SGunnar Mills             // Otherwise would be unexpected.
330*351053f2SKrzysztof Grobelny             if (manufacturer->find("Intel") != std::string::npos)
331ac6a4445SGunnar Mills             {
332002d39b4SEd Tanous                 aResp->res.jsonValue["ProcessorArchitecture"] = "x86";
333ac6a4445SGunnar Mills                 aResp->res.jsonValue["InstructionSet"] = "x86-64";
334ac6a4445SGunnar Mills             }
335*351053f2SKrzysztof Grobelny             else if (manufacturer->find("IBM") != std::string::npos)
336ac6a4445SGunnar Mills             {
337002d39b4SEd Tanous                 aResp->res.jsonValue["ProcessorArchitecture"] = "Power";
338ac6a4445SGunnar Mills                 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
339ac6a4445SGunnar Mills             }
340ac6a4445SGunnar Mills         }
341cba4f448SSunnySrivastava1984 
342*351053f2SKrzysztof Grobelny         if (partNumber != nullptr)
343cba4f448SSunnySrivastava1984         {
344cba4f448SSunnySrivastava1984             aResp->res.jsonValue["PartNumber"] = *partNumber;
345cba4f448SSunnySrivastava1984         }
346cba4f448SSunnySrivastava1984 
347*351053f2SKrzysztof Grobelny         if (sparePartNumber != nullptr)
348cba4f448SSunnySrivastava1984         {
349cba4f448SSunnySrivastava1984             aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
350cba4f448SSunnySrivastava1984         }
351*351053f2SKrzysztof Grobelny         });
352ac6a4445SGunnar Mills }
353ac6a4445SGunnar Mills 
3548d1b46d7Szhanghch05 inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
355ac6a4445SGunnar Mills                                const std::string& service,
356ac6a4445SGunnar Mills                                const std::string& objPath)
357ac6a4445SGunnar Mills {
358ac6a4445SGunnar Mills     BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
359*351053f2SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
360*351053f2SKrzysztof Grobelny         *crow::connections::systemBus, service, objPath,
361*351053f2SKrzysztof Grobelny         "xyz.openbmc_project.Inventory.Decorator.Revision",
362ac6a4445SGunnar Mills         [objPath, aResp{std::move(aResp)}](
363ac6a4445SGunnar Mills             const boost::system::error_code ec,
364*351053f2SKrzysztof Grobelny             const dbus::utility::DBusPropertiesMap& properties) {
365ac6a4445SGunnar Mills         if (ec)
366ac6a4445SGunnar Mills         {
367ac6a4445SGunnar Mills             BMCWEB_LOG_DEBUG << "DBUS response error";
368ac6a4445SGunnar Mills             messages::internalError(aResp->res);
369ac6a4445SGunnar Mills             return;
370ac6a4445SGunnar Mills         }
371ac6a4445SGunnar Mills 
372*351053f2SKrzysztof Grobelny         const std::string* version = nullptr;
373*351053f2SKrzysztof Grobelny 
374*351053f2SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
375*351053f2SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "Version", version);
376*351053f2SKrzysztof Grobelny 
377*351053f2SKrzysztof Grobelny         if (!success)
378ac6a4445SGunnar Mills         {
379*351053f2SKrzysztof Grobelny             messages::internalError(aResp->res);
380*351053f2SKrzysztof Grobelny             return;
381*351053f2SKrzysztof Grobelny         }
382*351053f2SKrzysztof Grobelny 
383*351053f2SKrzysztof Grobelny         if (version != nullptr)
384ac6a4445SGunnar Mills         {
385*351053f2SKrzysztof Grobelny             aResp->res.jsonValue["Version"] = *version;
386ac6a4445SGunnar Mills         }
387*351053f2SKrzysztof Grobelny         });
388ac6a4445SGunnar Mills }
389ac6a4445SGunnar Mills 
3908d1b46d7Szhanghch05 inline void getAcceleratorDataByService(
3918d1b46d7Szhanghch05     std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
3928d1b46d7Szhanghch05     const std::string& service, const std::string& objPath)
393ac6a4445SGunnar Mills {
394ac6a4445SGunnar Mills     BMCWEB_LOG_DEBUG
395ac6a4445SGunnar Mills         << "Get available system Accelerator resources by service.";
396*351053f2SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
397*351053f2SKrzysztof Grobelny         *crow::connections::systemBus, service, objPath, "",
398ac6a4445SGunnar Mills         [acclrtrId, aResp{std::move(aResp)}](
399ac6a4445SGunnar Mills             const boost::system::error_code ec,
400*351053f2SKrzysztof 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 
408*351053f2SKrzysztof Grobelny         const bool* functional = nullptr;
409*351053f2SKrzysztof Grobelny         const bool* present = nullptr;
410*351053f2SKrzysztof Grobelny 
411*351053f2SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
412*351053f2SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "Functional",
413*351053f2SKrzysztof Grobelny             functional, "Present", present);
414*351053f2SKrzysztof Grobelny 
415*351053f2SKrzysztof Grobelny         if (!success)
416ac6a4445SGunnar Mills         {
417*351053f2SKrzysztof Grobelny             messages::internalError(aResp->res);
418*351053f2SKrzysztof Grobelny             return;
419ac6a4445SGunnar Mills         }
420ac6a4445SGunnar Mills 
421ac6a4445SGunnar Mills         std::string state = "Enabled";
422ac6a4445SGunnar Mills         std::string health = "OK";
423ac6a4445SGunnar Mills 
424*351053f2SKrzysztof Grobelny         if (present != nullptr && !*present)
425ac6a4445SGunnar Mills         {
426ac6a4445SGunnar Mills             state = "Absent";
427ac6a4445SGunnar Mills         }
428ac6a4445SGunnar Mills 
429*351053f2SKrzysztof Grobelny         if (functional != nullptr && !*functional)
430ac6a4445SGunnar Mills         {
431ac6a4445SGunnar Mills             if (state == "Enabled")
432ac6a4445SGunnar Mills             {
433ac6a4445SGunnar Mills                 health = "Critical";
434ac6a4445SGunnar Mills             }
435ac6a4445SGunnar Mills         }
436ac6a4445SGunnar Mills 
437*351053f2SKrzysztof Grobelny         aResp->res.jsonValue["Id"] = acclrtrId;
438*351053f2SKrzysztof Grobelny         aResp->res.jsonValue["Name"] = "Processor";
439ac6a4445SGunnar Mills         aResp->res.jsonValue["Status"]["State"] = state;
440ac6a4445SGunnar Mills         aResp->res.jsonValue["Status"]["Health"] = health;
441ac6a4445SGunnar Mills         aResp->res.jsonValue["ProcessorType"] = "Accelerator";
442*351053f2SKrzysztof Grobelny         });
443ac6a4445SGunnar Mills }
444ac6a4445SGunnar Mills 
445dba0c291SJonathan Doman // OperatingConfig D-Bus Types
446dba0c291SJonathan Doman using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
447dba0c291SJonathan Doman using BaseSpeedPrioritySettingsProperty =
448dba0c291SJonathan Doman     std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
449dba0c291SJonathan Doman // uint32_t and size_t may or may not be the same type, requiring a dedup'd
450dba0c291SJonathan Doman // variant
451dba0c291SJonathan Doman 
452dba0c291SJonathan Doman /**
453dba0c291SJonathan Doman  * Fill out the HighSpeedCoreIDs in a Processor resource from the given
454dba0c291SJonathan Doman  * OperatingConfig D-Bus property.
455dba0c291SJonathan Doman  *
456dba0c291SJonathan Doman  * @param[in,out]   aResp               Async HTTP response.
457dba0c291SJonathan Doman  * @param[in]       baseSpeedSettings   Full list of base speed priority groups,
458dba0c291SJonathan Doman  *                                      to use to determine the list of high
459dba0c291SJonathan Doman  *                                      speed cores.
460dba0c291SJonathan Doman  */
461dba0c291SJonathan Doman inline void highSpeedCoreIdsHandler(
4628d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
463dba0c291SJonathan Doman     const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
464dba0c291SJonathan Doman {
465dba0c291SJonathan Doman     // The D-Bus property does not indicate which bucket is the "high
466dba0c291SJonathan Doman     // priority" group, so let's discern that by looking for the one with
467dba0c291SJonathan Doman     // highest base frequency.
468dba0c291SJonathan Doman     auto highPriorityGroup = baseSpeedSettings.cend();
469dba0c291SJonathan Doman     uint32_t highestBaseSpeed = 0;
470dba0c291SJonathan Doman     for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
471dba0c291SJonathan Doman          ++it)
472dba0c291SJonathan Doman     {
473dba0c291SJonathan Doman         const uint32_t baseFreq = std::get<uint32_t>(*it);
474dba0c291SJonathan Doman         if (baseFreq > highestBaseSpeed)
475dba0c291SJonathan Doman         {
476dba0c291SJonathan Doman             highestBaseSpeed = baseFreq;
477dba0c291SJonathan Doman             highPriorityGroup = it;
478dba0c291SJonathan Doman         }
479dba0c291SJonathan Doman     }
480dba0c291SJonathan Doman 
481dba0c291SJonathan Doman     nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
482dba0c291SJonathan Doman     jsonCoreIds = nlohmann::json::array();
483dba0c291SJonathan Doman 
484dba0c291SJonathan Doman     // There may not be any entries in the D-Bus property, so only populate
485dba0c291SJonathan Doman     // if there was actually something there.
486dba0c291SJonathan Doman     if (highPriorityGroup != baseSpeedSettings.cend())
487dba0c291SJonathan Doman     {
488dba0c291SJonathan Doman         jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
489dba0c291SJonathan Doman     }
490dba0c291SJonathan Doman }
491dba0c291SJonathan Doman 
492dba0c291SJonathan Doman /**
493dba0c291SJonathan Doman  * Fill out OperatingConfig related items in a Processor resource by requesting
494dba0c291SJonathan Doman  * data from the given D-Bus object.
495dba0c291SJonathan Doman  *
496dba0c291SJonathan Doman  * @param[in,out]   aResp       Async HTTP response.
497dba0c291SJonathan Doman  * @param[in]       cpuId       CPU D-Bus name.
498dba0c291SJonathan Doman  * @param[in]       service     D-Bus service to query.
499dba0c291SJonathan Doman  * @param[in]       objPath     D-Bus object to query.
500dba0c291SJonathan Doman  */
5018d1b46d7Szhanghch05 inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
502dba0c291SJonathan Doman                              const std::string& cpuId,
503dba0c291SJonathan Doman                              const std::string& service,
504dba0c291SJonathan Doman                              const std::string& objPath)
505dba0c291SJonathan Doman {
506dba0c291SJonathan Doman     BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
507dba0c291SJonathan Doman 
508dba0c291SJonathan Doman     // First, GetAll CurrentOperatingConfig properties on the object
509*351053f2SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
510*351053f2SKrzysztof Grobelny         *crow::connections::systemBus, service, objPath,
511*351053f2SKrzysztof Grobelny         "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
512*351053f2SKrzysztof Grobelny         [aResp, cpuId,
513*351053f2SKrzysztof Grobelny          service](const boost::system::error_code ec,
514*351053f2SKrzysztof Grobelny                   const dbus::utility::DBusPropertiesMap& properties) {
515dba0c291SJonathan Doman         if (ec)
516dba0c291SJonathan Doman         {
517002d39b4SEd Tanous             BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message();
518dba0c291SJonathan Doman             messages::internalError(aResp->res);
519dba0c291SJonathan Doman             return;
520dba0c291SJonathan Doman         }
521dba0c291SJonathan Doman 
522dba0c291SJonathan Doman         nlohmann::json& json = aResp->res.jsonValue;
523dba0c291SJonathan Doman 
524*351053f2SKrzysztof Grobelny         const sdbusplus::message::object_path* appliedConfig = nullptr;
525*351053f2SKrzysztof Grobelny         const bool* baseSpeedPriorityEnabled = nullptr;
526*351053f2SKrzysztof Grobelny 
527*351053f2SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
528*351053f2SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "AppliedConfig",
529*351053f2SKrzysztof Grobelny             appliedConfig, "BaseSpeedPriorityEnabled",
530*351053f2SKrzysztof Grobelny             baseSpeedPriorityEnabled);
531*351053f2SKrzysztof Grobelny 
532*351053f2SKrzysztof Grobelny         if (!success)
533dba0c291SJonathan Doman         {
534*351053f2SKrzysztof Grobelny             messages::internalError(aResp->res);
535*351053f2SKrzysztof Grobelny             return;
536dba0c291SJonathan Doman         }
537dba0c291SJonathan Doman 
538*351053f2SKrzysztof Grobelny         if (appliedConfig != nullptr)
539*351053f2SKrzysztof Grobelny         {
540*351053f2SKrzysztof Grobelny             const std::string& dbusPath = appliedConfig->str;
541*351053f2SKrzysztof Grobelny             std::string uri = "/redfish/v1/Systems/system/Processors/" + cpuId +
542*351053f2SKrzysztof Grobelny                               "/OperatingConfigs";
5431476687dSEd Tanous             nlohmann::json::object_t operatingConfig;
5441476687dSEd Tanous             operatingConfig["@odata.id"] = uri;
5451476687dSEd Tanous             json["OperatingConfigs"] = std::move(operatingConfig);
546dba0c291SJonathan Doman 
547dba0c291SJonathan Doman             // Reuse the D-Bus config object name for the Redfish
548dba0c291SJonathan Doman             // URI
549dba0c291SJonathan Doman             size_t baseNamePos = dbusPath.rfind('/');
550dba0c291SJonathan Doman             if (baseNamePos == std::string::npos ||
551dba0c291SJonathan Doman                 baseNamePos == (dbusPath.size() - 1))
552dba0c291SJonathan Doman             {
553dba0c291SJonathan Doman                 // If the AppliedConfig was somehow not a valid path,
554dba0c291SJonathan Doman                 // skip adding any more properties, since everything
555dba0c291SJonathan Doman                 // else is tied to this applied config.
556dba0c291SJonathan Doman                 messages::internalError(aResp->res);
557*351053f2SKrzysztof Grobelny                 return;
558dba0c291SJonathan Doman             }
559dba0c291SJonathan Doman             uri += '/';
560dba0c291SJonathan Doman             uri += dbusPath.substr(baseNamePos + 1);
5611476687dSEd Tanous             nlohmann::json::object_t appliedOperatingConfig;
5621476687dSEd Tanous             appliedOperatingConfig["@odata.id"] = uri;
563*351053f2SKrzysztof Grobelny             json["AppliedOperatingConfig"] = std::move(appliedOperatingConfig);
564dba0c291SJonathan Doman 
565dba0c291SJonathan Doman             // Once we found the current applied config, queue another
566dba0c291SJonathan Doman             // request to read the base freq core ids out of that
567dba0c291SJonathan Doman             // config.
568002d39b4SEd Tanous             sdbusplus::asio::getProperty<BaseSpeedPrioritySettingsProperty>(
5691e1e598dSJonathan Doman                 *crow::connections::systemBus, service, dbusPath,
5701e1e598dSJonathan Doman                 "xyz.openbmc_project.Inventory.Item.Cpu."
5711e1e598dSJonathan Doman                 "OperatingConfig",
5721e1e598dSJonathan Doman                 "BaseSpeedPrioritySettings",
573*351053f2SKrzysztof Grobelny                 [aResp](
574*351053f2SKrzysztof Grobelny                     const boost::system::error_code ec2,
575*351053f2SKrzysztof Grobelny                     const BaseSpeedPrioritySettingsProperty& baseSpeedList) {
5768a592810SEd Tanous                 if (ec2)
577dba0c291SJonathan Doman                 {
578*351053f2SKrzysztof Grobelny                     BMCWEB_LOG_WARNING << "D-Bus Property Get error: " << ec2;
579dba0c291SJonathan Doman                     messages::internalError(aResp->res);
580dba0c291SJonathan Doman                     return;
581dba0c291SJonathan Doman                 }
5821e1e598dSJonathan Doman 
5831e1e598dSJonathan Doman                 highSpeedCoreIdsHandler(aResp, baseSpeedList);
5841e1e598dSJonathan Doman                 });
585dba0c291SJonathan Doman         }
586*351053f2SKrzysztof Grobelny 
587*351053f2SKrzysztof Grobelny         if (baseSpeedPriorityEnabled != nullptr)
588dba0c291SJonathan Doman         {
589dba0c291SJonathan Doman             json["BaseSpeedPriorityState"] =
590*351053f2SKrzysztof Grobelny                 *baseSpeedPriorityEnabled ? "Enabled" : "Disabled";
591dba0c291SJonathan Doman         }
592*351053f2SKrzysztof Grobelny         });
593dba0c291SJonathan Doman }
594dba0c291SJonathan Doman 
595cba4f448SSunnySrivastava1984 /**
596cba4f448SSunnySrivastava1984  * @brief Fill out location info of a processor by
597cba4f448SSunnySrivastava1984  * requesting data from the given D-Bus object.
598cba4f448SSunnySrivastava1984  *
599cba4f448SSunnySrivastava1984  * @param[in,out]   aResp       Async HTTP response.
600cba4f448SSunnySrivastava1984  * @param[in]       service     D-Bus service to query.
601cba4f448SSunnySrivastava1984  * @param[in]       objPath     D-Bus object to query.
602cba4f448SSunnySrivastava1984  */
6038d1b46d7Szhanghch05 inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
604cba4f448SSunnySrivastava1984                                const std::string& service,
605cba4f448SSunnySrivastava1984                                const std::string& objPath)
606cba4f448SSunnySrivastava1984 {
607cba4f448SSunnySrivastava1984     BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
6081e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
6091e1e598dSJonathan Doman         *crow::connections::systemBus, service, objPath,
6101e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
6111e1e598dSJonathan Doman         [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
6121e1e598dSJonathan Doman                                            const std::string& property) {
613cba4f448SSunnySrivastava1984         if (ec)
614cba4f448SSunnySrivastava1984         {
615cba4f448SSunnySrivastava1984             BMCWEB_LOG_DEBUG << "DBUS response error";
616cba4f448SSunnySrivastava1984             messages::internalError(aResp->res);
617cba4f448SSunnySrivastava1984             return;
618cba4f448SSunnySrivastava1984         }
619cba4f448SSunnySrivastava1984 
620cba4f448SSunnySrivastava1984         aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
6211e1e598dSJonathan Doman             property;
6221e1e598dSJonathan Doman         });
623cba4f448SSunnySrivastava1984 }
624cba4f448SSunnySrivastava1984 
625c951448aSJonathan Doman /**
62649e429caSJonathan Doman  * Populate the unique identifier in a Processor resource by requesting data
62749e429caSJonathan Doman  * from the given D-Bus object.
62849e429caSJonathan Doman  *
62949e429caSJonathan Doman  * @param[in,out]   aResp       Async HTTP response.
63049e429caSJonathan Doman  * @param[in]       service     D-Bus service to query.
63149e429caSJonathan Doman  * @param[in]       objPath     D-Bus object to query.
63249e429caSJonathan Doman  */
63349e429caSJonathan Doman inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
63449e429caSJonathan Doman                            const std::string& service,
63549e429caSJonathan Doman                            const std::string& objectPath)
63649e429caSJonathan Doman {
63749e429caSJonathan Doman     BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
6381e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
6391e1e598dSJonathan Doman         *crow::connections::systemBus, service, objectPath,
6401e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
6411e1e598dSJonathan Doman         "UniqueIdentifier",
6421e1e598dSJonathan Doman         [aResp](boost::system::error_code ec, const std::string& id) {
6431e1e598dSJonathan Doman         if (ec)
64449e429caSJonathan Doman         {
64549e429caSJonathan Doman             BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
64649e429caSJonathan Doman             messages::internalError(aResp->res);
64749e429caSJonathan Doman             return;
64849e429caSJonathan Doman         }
649002d39b4SEd Tanous         aResp->res.jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] =
650002d39b4SEd Tanous             id;
6511e1e598dSJonathan Doman         });
65249e429caSJonathan Doman }
65349e429caSJonathan Doman 
65449e429caSJonathan Doman /**
655c951448aSJonathan Doman  * Find the D-Bus object representing the requested Processor, and call the
656c951448aSJonathan Doman  * handler with the results. If matching object is not found, add 404 error to
657c951448aSJonathan Doman  * response and don't call the handler.
658c951448aSJonathan Doman  *
659c951448aSJonathan Doman  * @param[in,out]   resp            Async HTTP response.
660c951448aSJonathan Doman  * @param[in]       processorId     Redfish Processor Id.
661c951448aSJonathan Doman  * @param[in]       handler         Callback to continue processing request upon
662c951448aSJonathan Doman  *                                  successfully finding object.
663c951448aSJonathan Doman  */
664c951448aSJonathan Doman template <typename Handler>
6658d1b46d7Szhanghch05 inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
666c951448aSJonathan Doman                                const std::string& processorId,
667c951448aSJonathan Doman                                Handler&& handler)
668ac6a4445SGunnar Mills {
669ac6a4445SGunnar Mills     BMCWEB_LOG_DEBUG << "Get available system processor resources.";
670ac6a4445SGunnar Mills 
671c951448aSJonathan Doman     // GetSubTree on all interfaces which provide info about a Processor
672ac6a4445SGunnar Mills     crow::connections::systemBus->async_method_call(
673c951448aSJonathan Doman         [resp, processorId, handler = std::forward<Handler>(handler)](
674c951448aSJonathan Doman             boost::system::error_code ec,
6755df6eda2SShantappa Teekappanavar             const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
676ac6a4445SGunnar Mills         if (ec)
677ac6a4445SGunnar Mills         {
678c951448aSJonathan Doman             BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
679c951448aSJonathan Doman             messages::internalError(resp->res);
680ac6a4445SGunnar Mills             return;
681ac6a4445SGunnar Mills         }
6822bab9831SJonathan Doman         for (const auto& [objectPath, serviceMap] : subtree)
683ac6a4445SGunnar Mills         {
6842bab9831SJonathan Doman             // Ignore any objects which don't end with our desired cpu name
68511ba3979SEd Tanous             if (!objectPath.ends_with(processorId))
686ac6a4445SGunnar Mills             {
6872bab9831SJonathan Doman                 continue;
688ac6a4445SGunnar Mills             }
6892bab9831SJonathan Doman 
690c951448aSJonathan Doman             bool found = false;
691c951448aSJonathan Doman             // Filter out objects that don't have the CPU-specific
692c951448aSJonathan Doman             // interfaces to make sure we can return 404 on non-CPUs
693c951448aSJonathan Doman             // (e.g. /redfish/../Processors/dimm0)
6942bab9831SJonathan Doman             for (const auto& [serviceName, interfaceList] : serviceMap)
695ac6a4445SGunnar Mills             {
696c951448aSJonathan Doman                 if (std::find_first_of(
697c951448aSJonathan Doman                         interfaceList.begin(), interfaceList.end(),
698c951448aSJonathan Doman                         processorInterfaces.begin(),
699c951448aSJonathan Doman                         processorInterfaces.end()) != interfaceList.end())
7002bab9831SJonathan Doman                 {
701c951448aSJonathan Doman                     found = true;
702c951448aSJonathan Doman                     break;
703c951448aSJonathan Doman                 }
704c951448aSJonathan Doman             }
705c951448aSJonathan Doman 
706c951448aSJonathan Doman             if (!found)
7072bab9831SJonathan Doman             {
708c951448aSJonathan Doman                 continue;
709ac6a4445SGunnar Mills             }
710c951448aSJonathan Doman 
711c951448aSJonathan Doman             // Process the first object which does match our cpu name and
712c951448aSJonathan Doman             // required interfaces, and potentially ignore any other
713c951448aSJonathan Doman             // matching objects. Assume all interfaces we want to process
714c951448aSJonathan Doman             // must be on the same object path.
715c951448aSJonathan Doman 
7168a592810SEd Tanous             handler(objectPath, serviceMap);
717ac6a4445SGunnar Mills             return;
718ac6a4445SGunnar Mills         }
719c951448aSJonathan Doman         messages::resourceNotFound(resp->res, "Processor", processorId);
720ac6a4445SGunnar Mills         },
721ac6a4445SGunnar Mills         "xyz.openbmc_project.ObjectMapper",
722ac6a4445SGunnar Mills         "/xyz/openbmc_project/object_mapper",
723ac6a4445SGunnar Mills         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
7242bab9831SJonathan Doman         "/xyz/openbmc_project/inventory", 0,
72549e429caSJonathan Doman         std::array<const char*, 8>{
72671b82f26SSharad Yadav             "xyz.openbmc_project.Common.UUID",
7272bab9831SJonathan Doman             "xyz.openbmc_project.Inventory.Decorator.Asset",
7282bab9831SJonathan Doman             "xyz.openbmc_project.Inventory.Decorator.Revision",
7292bab9831SJonathan Doman             "xyz.openbmc_project.Inventory.Item.Cpu",
730cba4f448SSunnySrivastava1984             "xyz.openbmc_project.Inventory.Decorator.LocationCode",
731dba0c291SJonathan Doman             "xyz.openbmc_project.Inventory.Item.Accelerator",
73249e429caSJonathan Doman             "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
73349e429caSJonathan Doman             "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
734ac6a4445SGunnar Mills }
735ac6a4445SGunnar Mills 
7368d1b46d7Szhanghch05 inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
737c951448aSJonathan Doman                              const std::string& processorId,
738c951448aSJonathan Doman                              const std::string& objectPath,
7395df6eda2SShantappa Teekappanavar                              const dbus::utility::MapperServiceMap& serviceMap)
740c951448aSJonathan Doman {
741c951448aSJonathan Doman     for (const auto& [serviceName, interfaceList] : serviceMap)
742c951448aSJonathan Doman     {
743c951448aSJonathan Doman         for (const auto& interface : interfaceList)
744c951448aSJonathan Doman         {
745c951448aSJonathan Doman             if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
746c951448aSJonathan Doman             {
747c951448aSJonathan Doman                 getCpuAssetData(aResp, serviceName, objectPath);
748c951448aSJonathan Doman             }
7490fda0f12SGeorge Liu             else if (interface ==
7500fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.Revision")
751c951448aSJonathan Doman             {
752c951448aSJonathan Doman                 getCpuRevisionData(aResp, serviceName, objectPath);
753c951448aSJonathan Doman             }
754c951448aSJonathan Doman             else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
755c951448aSJonathan Doman             {
756c951448aSJonathan Doman                 getCpuDataByService(aResp, processorId, serviceName,
757c951448aSJonathan Doman                                     objectPath);
758c951448aSJonathan Doman             }
7590fda0f12SGeorge Liu             else if (interface ==
7600fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Item.Accelerator")
761c951448aSJonathan Doman             {
762c951448aSJonathan Doman                 getAcceleratorDataByService(aResp, processorId, serviceName,
763c951448aSJonathan Doman                                             objectPath);
764c951448aSJonathan Doman             }
7650fda0f12SGeorge Liu             else if (
7660fda0f12SGeorge Liu                 interface ==
7670fda0f12SGeorge Liu                 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
768c951448aSJonathan Doman             {
769c951448aSJonathan Doman                 getCpuConfigData(aResp, processorId, serviceName, objectPath);
770c951448aSJonathan Doman             }
7710fda0f12SGeorge Liu             else if (interface ==
7720fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
773c951448aSJonathan Doman             {
774c951448aSJonathan Doman                 getCpuLocationCode(aResp, serviceName, objectPath);
775c951448aSJonathan Doman             }
77671b82f26SSharad Yadav             else if (interface == "xyz.openbmc_project.Common.UUID")
77771b82f26SSharad Yadav             {
77871b82f26SSharad Yadav                 getProcessorUUID(aResp, serviceName, objectPath);
77971b82f26SSharad Yadav             }
7800fda0f12SGeorge Liu             else if (interface ==
7810fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
78249e429caSJonathan Doman             {
78349e429caSJonathan Doman                 getCpuUniqueId(aResp, serviceName, objectPath);
78449e429caSJonathan Doman             }
785c951448aSJonathan Doman         }
786c951448aSJonathan Doman     }
787c951448aSJonathan Doman }
788c951448aSJonathan Doman 
789dba0c291SJonathan Doman /**
790dba0c291SJonathan Doman  * Request all the properties for the given D-Bus object and fill out the
791dba0c291SJonathan Doman  * related entries in the Redfish OperatingConfig response.
792dba0c291SJonathan Doman  *
793dba0c291SJonathan Doman  * @param[in,out]   aResp       Async HTTP response.
794dba0c291SJonathan Doman  * @param[in]       service     D-Bus service name to query.
795dba0c291SJonathan Doman  * @param[in]       objPath     D-Bus object to query.
796dba0c291SJonathan Doman  */
7978d1b46d7Szhanghch05 inline void
7988d1b46d7Szhanghch05     getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
799dba0c291SJonathan Doman                            const std::string& service,
800dba0c291SJonathan Doman                            const std::string& objPath)
801dba0c291SJonathan Doman {
802*351053f2SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
803*351053f2SKrzysztof Grobelny         *crow::connections::systemBus, service, objPath,
804*351053f2SKrzysztof Grobelny         "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig",
805914e2d5dSEd Tanous         [aResp](const boost::system::error_code ec,
806*351053f2SKrzysztof Grobelny                 const dbus::utility::DBusPropertiesMap& properties) {
807dba0c291SJonathan Doman         if (ec)
808dba0c291SJonathan Doman         {
809002d39b4SEd Tanous             BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message();
810dba0c291SJonathan Doman             messages::internalError(aResp->res);
811dba0c291SJonathan Doman             return;
812dba0c291SJonathan Doman         }
813dba0c291SJonathan Doman 
814*351053f2SKrzysztof Grobelny         const size_t* availableCoreCount = nullptr;
815*351053f2SKrzysztof Grobelny         const uint32_t* baseSpeed = nullptr;
816*351053f2SKrzysztof Grobelny         const uint32_t* maxJunctionTemperature = nullptr;
817*351053f2SKrzysztof Grobelny         const uint32_t* maxSpeed = nullptr;
818*351053f2SKrzysztof Grobelny         const uint32_t* powerLimit = nullptr;
819*351053f2SKrzysztof Grobelny         const TurboProfileProperty* turboProfile = nullptr;
820*351053f2SKrzysztof Grobelny         const BaseSpeedPrioritySettingsProperty* baseSpeedPrioritySettings =
821*351053f2SKrzysztof Grobelny             nullptr;
822*351053f2SKrzysztof Grobelny 
823*351053f2SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
824*351053f2SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), properties, "AvailableCoreCount",
825*351053f2SKrzysztof Grobelny             availableCoreCount, "BaseSpeed", baseSpeed,
826*351053f2SKrzysztof Grobelny             "MaxJunctionTemperature", maxJunctionTemperature, "MaxSpeed",
827*351053f2SKrzysztof Grobelny             maxSpeed, "PowerLimit", powerLimit, "TurboProfile", turboProfile,
828*351053f2SKrzysztof Grobelny             "BaseSpeedPrioritySettings", baseSpeedPrioritySettings);
829*351053f2SKrzysztof Grobelny 
830*351053f2SKrzysztof Grobelny         if (!success)
831dba0c291SJonathan Doman         {
832*351053f2SKrzysztof Grobelny             messages::internalError(aResp->res);
833*351053f2SKrzysztof Grobelny             return;
834dba0c291SJonathan Doman         }
835dba0c291SJonathan Doman 
836*351053f2SKrzysztof Grobelny         nlohmann::json& json = aResp->res.jsonValue;
837*351053f2SKrzysztof Grobelny 
838*351053f2SKrzysztof Grobelny         if (availableCoreCount != nullptr)
839*351053f2SKrzysztof Grobelny         {
840*351053f2SKrzysztof Grobelny             json["TotalAvailableCoreCount"] = *availableCoreCount;
841*351053f2SKrzysztof Grobelny         }
842*351053f2SKrzysztof Grobelny 
843*351053f2SKrzysztof Grobelny         if (baseSpeed != nullptr)
844*351053f2SKrzysztof Grobelny         {
845*351053f2SKrzysztof Grobelny             json["BaseSpeedMHz"] = *baseSpeed;
846*351053f2SKrzysztof Grobelny         }
847*351053f2SKrzysztof Grobelny 
848*351053f2SKrzysztof Grobelny         if (maxJunctionTemperature != nullptr)
849*351053f2SKrzysztof Grobelny         {
850*351053f2SKrzysztof Grobelny             json["MaxJunctionTemperatureCelsius"] = *maxJunctionTemperature;
851*351053f2SKrzysztof Grobelny         }
852*351053f2SKrzysztof Grobelny 
853*351053f2SKrzysztof Grobelny         if (maxSpeed != nullptr)
854*351053f2SKrzysztof Grobelny         {
855*351053f2SKrzysztof Grobelny             json["MaxSpeedMHz"] = *maxSpeed;
856*351053f2SKrzysztof Grobelny         }
857*351053f2SKrzysztof Grobelny 
858*351053f2SKrzysztof Grobelny         if (powerLimit != nullptr)
859*351053f2SKrzysztof Grobelny         {
860*351053f2SKrzysztof Grobelny             json["TDPWatts"] = *powerLimit;
861*351053f2SKrzysztof Grobelny         }
862*351053f2SKrzysztof Grobelny 
863*351053f2SKrzysztof Grobelny         if (turboProfile != nullptr)
864*351053f2SKrzysztof Grobelny         {
865dba0c291SJonathan Doman             nlohmann::json& turboArray = json["TurboProfile"];
866dba0c291SJonathan Doman             turboArray = nlohmann::json::array();
867*351053f2SKrzysztof Grobelny             for (const auto& [turboSpeed, coreCount] : *turboProfile)
868dba0c291SJonathan Doman             {
8691476687dSEd Tanous                 nlohmann::json::object_t turbo;
8701476687dSEd Tanous                 turbo["ActiveCoreCount"] = coreCount;
8711476687dSEd Tanous                 turbo["MaxSpeedMHz"] = turboSpeed;
8721476687dSEd Tanous                 turboArray.push_back(std::move(turbo));
873dba0c291SJonathan Doman             }
874dba0c291SJonathan Doman         }
875dba0c291SJonathan Doman 
876*351053f2SKrzysztof Grobelny         if (baseSpeedPrioritySettings != nullptr)
877*351053f2SKrzysztof Grobelny         {
878*351053f2SKrzysztof Grobelny             nlohmann::json& baseSpeedArray = json["BaseSpeedPrioritySettings"];
879dba0c291SJonathan Doman             baseSpeedArray = nlohmann::json::array();
880*351053f2SKrzysztof Grobelny             for (const auto& [baseSpeedMhz, coreList] :
881*351053f2SKrzysztof Grobelny                  *baseSpeedPrioritySettings)
882dba0c291SJonathan Doman             {
8831476687dSEd Tanous                 nlohmann::json::object_t speed;
8841476687dSEd Tanous                 speed["CoreCount"] = coreList.size();
8851476687dSEd Tanous                 speed["CoreIDs"] = coreList;
886*351053f2SKrzysztof Grobelny                 speed["BaseSpeedMHz"] = baseSpeedMhz;
8871476687dSEd Tanous                 baseSpeedArray.push_back(std::move(speed));
888dba0c291SJonathan Doman             }
889dba0c291SJonathan Doman         }
890*351053f2SKrzysztof Grobelny         });
891dba0c291SJonathan Doman }
892dba0c291SJonathan Doman 
8933cde86f1SJonathan Doman /**
8943cde86f1SJonathan Doman  * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
8953cde86f1SJonathan Doman  * property. Main task is to translate error messages into Redfish errors.
8963cde86f1SJonathan Doman  *
8973cde86f1SJonathan Doman  * @param[in,out]   resp    HTTP response.
8983cde86f1SJonathan Doman  * @param[in]       setPropVal  Value which we attempted to set.
8993cde86f1SJonathan Doman  * @param[in]       ec      D-Bus response error code.
9003cde86f1SJonathan Doman  * @param[in]       msg     D-Bus response message.
9013cde86f1SJonathan Doman  */
9023cde86f1SJonathan Doman inline void
9033cde86f1SJonathan Doman     handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
9043cde86f1SJonathan Doman                                 const std::string& setPropVal,
9053cde86f1SJonathan Doman                                 boost::system::error_code ec,
90659d494eeSPatrick Williams                                 const sdbusplus::message_t& msg)
9073cde86f1SJonathan Doman {
9083cde86f1SJonathan Doman     if (!ec)
9093cde86f1SJonathan Doman     {
9103cde86f1SJonathan Doman         BMCWEB_LOG_DEBUG << "Set Property succeeded";
9113cde86f1SJonathan Doman         return;
9123cde86f1SJonathan Doman     }
9133cde86f1SJonathan Doman 
9143cde86f1SJonathan Doman     BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
9153cde86f1SJonathan Doman 
9163cde86f1SJonathan Doman     const sd_bus_error* dbusError = msg.get_error();
9173cde86f1SJonathan Doman     if (dbusError == nullptr)
9183cde86f1SJonathan Doman     {
9193cde86f1SJonathan Doman         messages::internalError(resp->res);
9203cde86f1SJonathan Doman         return;
9213cde86f1SJonathan Doman     }
9223cde86f1SJonathan Doman 
9233cde86f1SJonathan Doman     // The asio error code doesn't know about our custom errors, so we have to
9243cde86f1SJonathan Doman     // parse the error string. Some of these D-Bus -> Redfish translations are a
9253cde86f1SJonathan Doman     // stretch, but it's good to try to communicate something vaguely useful.
9263cde86f1SJonathan Doman     if (strcmp(dbusError->name,
9273cde86f1SJonathan Doman                "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
9283cde86f1SJonathan Doman     {
9293cde86f1SJonathan Doman         // Service did not like the object_path we tried to set.
9303cde86f1SJonathan Doman         messages::propertyValueIncorrect(
9313cde86f1SJonathan Doman             resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
9323cde86f1SJonathan Doman     }
9333cde86f1SJonathan Doman     else if (strcmp(dbusError->name,
9343cde86f1SJonathan Doman                     "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
9353cde86f1SJonathan Doman     {
9363cde86f1SJonathan Doman         // Service indicates we can never change the config for this processor.
9373cde86f1SJonathan Doman         messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
9383cde86f1SJonathan Doman     }
9393cde86f1SJonathan Doman     else if (strcmp(dbusError->name,
9403cde86f1SJonathan Doman                     "xyz.openbmc_project.Common.Error.Unavailable") == 0)
9413cde86f1SJonathan Doman     {
9423cde86f1SJonathan Doman         // Service indicates the config cannot be changed right now, but maybe
9433cde86f1SJonathan Doman         // in a different system state.
9443cde86f1SJonathan Doman         messages::resourceInStandby(resp->res);
9453cde86f1SJonathan Doman     }
9463cde86f1SJonathan Doman     else
9473cde86f1SJonathan Doman     {
9483cde86f1SJonathan Doman         messages::internalError(resp->res);
9493cde86f1SJonathan Doman     }
9503cde86f1SJonathan Doman }
9513cde86f1SJonathan Doman 
9523cde86f1SJonathan Doman /**
9533cde86f1SJonathan Doman  * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
9543cde86f1SJonathan Doman  * validation of the input data, and then set the D-Bus property.
9553cde86f1SJonathan Doman  *
9563cde86f1SJonathan Doman  * @param[in,out]   resp            Async HTTP response.
9573cde86f1SJonathan Doman  * @param[in]       processorId     Processor's Id.
9583cde86f1SJonathan Doman  * @param[in]       appliedConfigUri    New property value to apply.
9593cde86f1SJonathan Doman  * @param[in]       cpuObjectPath   Path of CPU object to modify.
9603cde86f1SJonathan Doman  * @param[in]       serviceMap      Service map for CPU object.
9613cde86f1SJonathan Doman  */
9623cde86f1SJonathan Doman inline void patchAppliedOperatingConfig(
9633cde86f1SJonathan Doman     const std::shared_ptr<bmcweb::AsyncResp>& resp,
9643cde86f1SJonathan Doman     const std::string& processorId, const std::string& appliedConfigUri,
9655df6eda2SShantappa Teekappanavar     const std::string& cpuObjectPath,
9665df6eda2SShantappa Teekappanavar     const dbus::utility::MapperServiceMap& serviceMap)
9673cde86f1SJonathan Doman {
9683cde86f1SJonathan Doman     // Check that the property even exists by checking for the interface
9693cde86f1SJonathan Doman     const std::string* controlService = nullptr;
9703cde86f1SJonathan Doman     for (const auto& [serviceName, interfaceList] : serviceMap)
9713cde86f1SJonathan Doman     {
9723cde86f1SJonathan Doman         if (std::find(interfaceList.begin(), interfaceList.end(),
9733cde86f1SJonathan Doman                       "xyz.openbmc_project.Control.Processor."
9743cde86f1SJonathan Doman                       "CurrentOperatingConfig") != interfaceList.end())
9753cde86f1SJonathan Doman         {
9763cde86f1SJonathan Doman             controlService = &serviceName;
9773cde86f1SJonathan Doman             break;
9783cde86f1SJonathan Doman         }
9793cde86f1SJonathan Doman     }
9803cde86f1SJonathan Doman 
9813cde86f1SJonathan Doman     if (controlService == nullptr)
9823cde86f1SJonathan Doman     {
9833cde86f1SJonathan Doman         messages::internalError(resp->res);
9843cde86f1SJonathan Doman         return;
9853cde86f1SJonathan Doman     }
9863cde86f1SJonathan Doman 
9873cde86f1SJonathan Doman     // Check that the config URI is a child of the cpu URI being patched.
9883cde86f1SJonathan Doman     std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
9893cde86f1SJonathan Doman     expectedPrefix += processorId;
9903cde86f1SJonathan Doman     expectedPrefix += "/OperatingConfigs/";
99111ba3979SEd Tanous     if (!appliedConfigUri.starts_with(expectedPrefix) ||
9923cde86f1SJonathan Doman         expectedPrefix.size() == appliedConfigUri.size())
9933cde86f1SJonathan Doman     {
9943cde86f1SJonathan Doman         messages::propertyValueIncorrect(
9953cde86f1SJonathan Doman             resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
9963cde86f1SJonathan Doman         return;
9973cde86f1SJonathan Doman     }
9983cde86f1SJonathan Doman 
9993cde86f1SJonathan Doman     // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
10003cde86f1SJonathan Doman     // direct child of the CPU object.
10013cde86f1SJonathan Doman     // Strip the expectedPrefix from the config URI to get the "filename", and
10023cde86f1SJonathan Doman     // append to the CPU's path.
10033cde86f1SJonathan Doman     std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
10043cde86f1SJonathan Doman     sdbusplus::message::object_path configPath(cpuObjectPath);
10053cde86f1SJonathan Doman     configPath /= configBaseName;
10063cde86f1SJonathan Doman 
10073cde86f1SJonathan Doman     BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
10083cde86f1SJonathan Doman 
10093cde86f1SJonathan Doman     // Set the property, with handler to check error responses
10103cde86f1SJonathan Doman     crow::connections::systemBus->async_method_call(
1011914e2d5dSEd Tanous         [resp, appliedConfigUri](const boost::system::error_code ec,
101259d494eeSPatrick Williams                                  const sdbusplus::message_t& msg) {
10133cde86f1SJonathan Doman         handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
10143cde86f1SJonathan Doman         },
10153cde86f1SJonathan Doman         *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
10163cde86f1SJonathan Doman         "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
1017168e20c1SEd Tanous         "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
10183cde86f1SJonathan Doman }
10193cde86f1SJonathan Doman 
10207e860f15SJohn Edward Broadbent inline void requestRoutesOperatingConfigCollection(App& app)
1021dba0c291SJonathan Doman {
1022dba0c291SJonathan Doman 
10237e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
10247e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
1025ed398213SEd Tanous         .privileges(redfish::privileges::getOperatingConfigCollection)
1026002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1027002d39b4SEd Tanous             [&app](const crow::Request& req,
102845ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10297e860f15SJohn Edward Broadbent                    const std::string& cpuName) {
10303ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
103145ca1b86SEd Tanous         {
103245ca1b86SEd Tanous             return;
103345ca1b86SEd Tanous         }
10348d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.type"] =
1035dba0c291SJonathan Doman             "#OperatingConfigCollection.OperatingConfigCollection";
10368d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.id"] = req.url;
10370fda0f12SGeorge Liu         asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
1038dba0c291SJonathan Doman 
10397e860f15SJohn Edward Broadbent         // First find the matching CPU object so we know how to
10407e860f15SJohn Edward Broadbent         // constrain our search for related Config objects.
1041dba0c291SJonathan Doman         crow::connections::systemBus->async_method_call(
1042002d39b4SEd Tanous             [asyncResp, cpuName](
1043002d39b4SEd Tanous                 const boost::system::error_code ec,
1044002d39b4SEd Tanous                 const dbus::utility::MapperGetSubTreePathsResponse& objects) {
1045dba0c291SJonathan Doman             if (ec)
1046dba0c291SJonathan Doman             {
1047dba0c291SJonathan Doman                 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1048dba0c291SJonathan Doman                                    << ec.message();
1049dba0c291SJonathan Doman                 messages::internalError(asyncResp->res);
1050dba0c291SJonathan Doman                 return;
1051dba0c291SJonathan Doman             }
1052dba0c291SJonathan Doman 
1053dba0c291SJonathan Doman             for (const std::string& object : objects)
1054dba0c291SJonathan Doman             {
105511ba3979SEd Tanous                 if (!object.ends_with(cpuName))
1056dba0c291SJonathan Doman                 {
1057dba0c291SJonathan Doman                     continue;
1058dba0c291SJonathan Doman                 }
1059dba0c291SJonathan Doman 
10607e860f15SJohn Edward Broadbent                 // Not expected that there will be multiple matching
10617e860f15SJohn Edward Broadbent                 // CPU objects, but if there are just use the first
10627e860f15SJohn Edward Broadbent                 // one.
1063dba0c291SJonathan Doman 
10647e860f15SJohn Edward Broadbent                 // Use the common search routine to construct the
10657e860f15SJohn Edward Broadbent                 // Collection of all Config objects under this CPU.
1066dba0c291SJonathan Doman                 collection_util::getCollectionMembers(
1067dba0c291SJonathan Doman                     asyncResp,
10680fda0f12SGeorge Liu                     "/redfish/v1/Systems/system/Processors/" + cpuName +
10690fda0f12SGeorge Liu                         "/OperatingConfigs",
10700fda0f12SGeorge Liu                     {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1071dba0c291SJonathan Doman                     object.c_str());
1072dba0c291SJonathan Doman                 return;
1073dba0c291SJonathan Doman             }
1074dba0c291SJonathan Doman             },
1075dba0c291SJonathan Doman             "xyz.openbmc_project.ObjectMapper",
1076dba0c291SJonathan Doman             "/xyz/openbmc_project/object_mapper",
1077dba0c291SJonathan Doman             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1078dba0c291SJonathan Doman             "/xyz/openbmc_project/inventory", 0,
10797e860f15SJohn Edward Broadbent             std::array<const char*, 1>{
10800fda0f12SGeorge Liu                 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
10817e860f15SJohn Edward Broadbent         });
1082dba0c291SJonathan Doman }
1083dba0c291SJonathan Doman 
10847e860f15SJohn Edward Broadbent inline void requestRoutesOperatingConfig(App& app)
1085dba0c291SJonathan Doman {
10867e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
10877e860f15SJohn Edward Broadbent         app,
10887e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
1089ed398213SEd Tanous         .privileges(redfish::privileges::getOperatingConfig)
1090002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1091002d39b4SEd Tanous             [&app](const crow::Request& req,
109245ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1093002d39b4SEd Tanous                    const std::string& cpuName, const std::string& configName) {
10943ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
109545ca1b86SEd Tanous         {
109645ca1b86SEd Tanous             return;
109745ca1b86SEd Tanous         }
10987e860f15SJohn Edward Broadbent         // Ask for all objects implementing OperatingConfig so we can search
10997e860f15SJohn Edward Broadbent         // for one with a matching name
1100dba0c291SJonathan Doman         crow::connections::systemBus->async_method_call(
11015df6eda2SShantappa Teekappanavar             [asyncResp, cpuName, configName, reqUrl{req.url}](
11025df6eda2SShantappa Teekappanavar                 boost::system::error_code ec,
11035df6eda2SShantappa Teekappanavar                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1104dba0c291SJonathan Doman             if (ec)
1105dba0c291SJonathan Doman             {
1106dba0c291SJonathan Doman                 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1107dba0c291SJonathan Doman                                    << ec.message();
1108dba0c291SJonathan Doman                 messages::internalError(asyncResp->res);
1109dba0c291SJonathan Doman                 return;
1110dba0c291SJonathan Doman             }
1111002d39b4SEd Tanous             const std::string expectedEnding = cpuName + '/' + configName;
1112dba0c291SJonathan Doman             for (const auto& [objectPath, serviceMap] : subtree)
1113dba0c291SJonathan Doman             {
1114dba0c291SJonathan Doman                 // Ignore any configs without matching cpuX/configY
111511ba3979SEd Tanous                 if (!objectPath.ends_with(expectedEnding) || serviceMap.empty())
1116dba0c291SJonathan Doman                 {
1117dba0c291SJonathan Doman                     continue;
1118dba0c291SJonathan Doman                 }
1119dba0c291SJonathan Doman 
1120dba0c291SJonathan Doman                 nlohmann::json& json = asyncResp->res.jsonValue;
1121002d39b4SEd Tanous                 json["@odata.type"] = "#OperatingConfig.v1_0_0.OperatingConfig";
1122dba0c291SJonathan Doman                 json["@odata.id"] = reqUrl;
1123dba0c291SJonathan Doman                 json["Name"] = "Processor Profile";
1124dba0c291SJonathan Doman                 json["Id"] = configName;
1125dba0c291SJonathan Doman 
1126dba0c291SJonathan Doman                 // Just use the first implementation of the object - not
11277e860f15SJohn Edward Broadbent                 // expected that there would be multiple matching
11287e860f15SJohn Edward Broadbent                 // services
1129002d39b4SEd Tanous                 getOperatingConfigData(asyncResp, serviceMap.begin()->first,
1130002d39b4SEd Tanous                                        objectPath);
1131dba0c291SJonathan Doman                 return;
1132dba0c291SJonathan Doman             }
1133002d39b4SEd Tanous             messages::resourceNotFound(asyncResp->res, "OperatingConfig",
1134002d39b4SEd Tanous                                        configName);
1135dba0c291SJonathan Doman             },
1136dba0c291SJonathan Doman             "xyz.openbmc_project.ObjectMapper",
1137dba0c291SJonathan Doman             "/xyz/openbmc_project/object_mapper",
1138dba0c291SJonathan Doman             "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1139dba0c291SJonathan Doman             "/xyz/openbmc_project/inventory", 0,
1140dba0c291SJonathan Doman             std::array<const char*, 1>{
1141dba0c291SJonathan Doman                 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
11427e860f15SJohn Edward Broadbent         });
1143ac6a4445SGunnar Mills }
1144ac6a4445SGunnar Mills 
11457e860f15SJohn Edward Broadbent inline void requestRoutesProcessorCollection(App& app)
11467e860f15SJohn Edward Broadbent {
1147ac6a4445SGunnar Mills     /**
1148ac6a4445SGunnar Mills      * Functions triggers appropriate requests on DBus
1149ac6a4445SGunnar Mills      */
11507e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/")
1151ed398213SEd Tanous         .privileges(redfish::privileges::getProcessorCollection)
11527e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
115345ca1b86SEd Tanous             [&app](const crow::Request& req,
11547e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
11553ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
115645ca1b86SEd Tanous         {
115745ca1b86SEd Tanous             return;
115845ca1b86SEd Tanous         }
11598d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.type"] =
1160ac6a4445SGunnar Mills             "#ProcessorCollection.ProcessorCollection";
11618d1b46d7Szhanghch05         asyncResp->res.jsonValue["Name"] = "Processor Collection";
1162ac6a4445SGunnar Mills 
11638d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.id"] =
11648d1b46d7Szhanghch05             "/redfish/v1/Systems/system/Processors";
1165ac6a4445SGunnar Mills 
116605030b8eSGunnar Mills         collection_util::getCollectionMembers(
116705030b8eSGunnar Mills             asyncResp, "/redfish/v1/Systems/system/Processors",
1168c951448aSJonathan Doman             std::vector<const char*>(processorInterfaces.begin(),
1169c951448aSJonathan Doman                                      processorInterfaces.end()));
11707e860f15SJohn Edward Broadbent         });
1171ac6a4445SGunnar Mills }
1172ac6a4445SGunnar Mills 
11737e860f15SJohn Edward Broadbent inline void requestRoutesProcessor(App& app)
11747e860f15SJohn Edward Broadbent {
1175ac6a4445SGunnar Mills     /**
1176ac6a4445SGunnar Mills      * Functions triggers appropriate requests on DBus
1177ac6a4445SGunnar Mills      */
11787e860f15SJohn Edward Broadbent 
11797e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
1180ed398213SEd Tanous         .privileges(redfish::privileges::getProcessor)
11817e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
118245ca1b86SEd Tanous             [&app](const crow::Request& req,
11837e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11847e860f15SJohn Edward Broadbent                    const std::string& processorId) {
11853ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
118645ca1b86SEd Tanous         {
118745ca1b86SEd Tanous             return;
118845ca1b86SEd Tanous         }
11898d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.type"] =
11908d1b46d7Szhanghch05             "#Processor.v1_11_0.Processor";
11918d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.id"] =
1192ac6a4445SGunnar Mills             "/redfish/v1/Systems/system/Processors/" + processorId;
1193ac6a4445SGunnar Mills 
11948a592810SEd Tanous         getProcessorObject(
11958a592810SEd Tanous             asyncResp, processorId,
11968a592810SEd Tanous             std::bind_front(getProcessorData, asyncResp, processorId));
11977e860f15SJohn Edward Broadbent         });
11983cde86f1SJonathan Doman 
11997e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
1200ed398213SEd Tanous         .privileges(redfish::privileges::patchProcessor)
12017e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
120245ca1b86SEd Tanous             [&app](const crow::Request& req,
12037e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12047e860f15SJohn Edward Broadbent                    const std::string& processorId) {
12053ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
120645ca1b86SEd Tanous         {
120745ca1b86SEd Tanous             return;
120845ca1b86SEd Tanous         }
12093cde86f1SJonathan Doman         std::optional<nlohmann::json> appliedConfigJson;
121015ed6780SWilly Tu         if (!json_util::readJsonPatch(req, asyncResp->res,
12117e860f15SJohn Edward Broadbent                                       "AppliedOperatingConfig",
12123cde86f1SJonathan Doman                                       appliedConfigJson))
12133cde86f1SJonathan Doman         {
12143cde86f1SJonathan Doman             return;
12153cde86f1SJonathan Doman         }
12163cde86f1SJonathan Doman 
12173cde86f1SJonathan Doman         std::string appliedConfigUri;
12183cde86f1SJonathan Doman         if (appliedConfigJson)
12193cde86f1SJonathan Doman         {
12203cde86f1SJonathan Doman             if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
12213cde86f1SJonathan Doman                                      "@odata.id", appliedConfigUri))
12223cde86f1SJonathan Doman             {
12233cde86f1SJonathan Doman                 return;
12243cde86f1SJonathan Doman             }
12257e860f15SJohn Edward Broadbent             // Check for 404 and find matching D-Bus object, then run
12267e860f15SJohn Edward Broadbent             // property patch handlers if that all succeeds.
12278a592810SEd Tanous             getProcessorObject(asyncResp, processorId,
12288a592810SEd Tanous                                std::bind_front(patchAppliedOperatingConfig,
12297e860f15SJohn Edward Broadbent                                                asyncResp, processorId,
12308a592810SEd Tanous                                                appliedConfigUri));
12313cde86f1SJonathan Doman         }
12327e860f15SJohn Edward Broadbent         });
12333cde86f1SJonathan Doman }
1234ac6a4445SGunnar Mills 
1235ac6a4445SGunnar Mills } // namespace redfish
1236