blob: b33f9120a3b02be24a2d183142de465c7f198cc5 [file] [log] [blame]
Gunnar Millsac6a4442020-10-14 14:55:29 -05001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Jonathan Doman1e1e5982021-06-11 09:36:17 -070018#include "dbus_singleton.hpp"
19#include "error_messages.hpp"
Gunnar Millsac6a4442020-10-14 14:55:29 -050020#include "health.hpp"
21
John Edward Broadbent7e860f12021-04-08 15:57:16 -070022#include <app.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050023#include <boost/container/flat_map.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080024#include <dbus_utility.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070025#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070026#include <sdbusplus/asio/property.hpp>
Jonathan Domandba0c292020-12-02 15:34:13 -080027#include <sdbusplus/message/native_types.hpp>
28#include <sdbusplus/utility/dedup_variant.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050029#include <utils/collection.hpp>
30#include <utils/json_utils.hpp>
31
32namespace redfish
33{
34
35using InterfacesProperties = boost::container::flat_map<
36 std::string,
37 boost::container::flat_map<std::string, dbus::utility::DbusVariantType>>;
38
Jonathan Domanc9514482021-02-24 09:20:51 -080039// Map of service name to list of interfaces
40using MapperServiceMap =
41 std::vector<std::pair<std::string, std::vector<std::string>>>;
42
43// Map of object paths to MapperServiceMaps
44using MapperGetSubTreeResponse =
45 std::vector<std::pair<std::string, MapperServiceMap>>;
46
47// Interfaces which imply a D-Bus object represents a Processor
48constexpr std::array<const char*, 2> processorInterfaces = {
49 "xyz.openbmc_project.Inventory.Item.Cpu",
50 "xyz.openbmc_project.Inventory.Item.Accelerator"};
Jonathan Doman2bab9832020-12-02 15:27:40 -080051
Sharad Yadav71b82f22021-05-10 15:11:39 +053052/**
53 * @brief Fill out uuid info of a processor by
54 * requesting data from the given D-Bus object.
55 *
56 * @param[in,out] aResp Async HTTP response.
57 * @param[in] service D-Bus service to query.
58 * @param[in] objPath D-Bus object to query.
59 */
60inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp,
61 const std::string& service,
62 const std::string& objPath)
63{
64 BMCWEB_LOG_DEBUG << "Get Processor UUID";
Jonathan Doman1e1e5982021-06-11 09:36:17 -070065 sdbusplus::asio::getProperty<std::string>(
66 *crow::connections::systemBus, service, objPath,
67 "xyz.openbmc_project.Common.UUID", "UUID",
68 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
69 const std::string& property) {
Sharad Yadav71b82f22021-05-10 15:11:39 +053070 if (ec)
71 {
72 BMCWEB_LOG_DEBUG << "DBUS response error";
73 messages::internalError(aResp->res);
74 return;
75 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -070076 aResp->res.jsonValue["UUID"] = property;
77 });
Sharad Yadav71b82f22021-05-10 15:11:39 +053078}
79
Gunnar Millsac6a4442020-10-14 14:55:29 -050080inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080081 getCpuDataByInterface(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -050082 const InterfacesProperties& cpuInterfacesProperties)
83{
84 BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
85
Chicago Duana1649ec2021-03-30 16:54:58 +080086 // Set the default value of state
87 aResp->res.jsonValue["Status"]["State"] = "Enabled";
88 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -050089
90 for (const auto& interface : cpuInterfacesProperties)
91 {
92 for (const auto& property : interface.second)
93 {
Chicago Duana1649ec2021-03-30 16:54:58 +080094 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -050095 {
Chicago Duana1649ec2021-03-30 16:54:58 +080096 const bool* cpuPresent = std::get_if<bool>(&property.second);
97 if (cpuPresent == nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -050098 {
99 // Important property not in desired type
100 messages::internalError(aResp->res);
101 return;
102 }
Chicago Duana1649ec2021-03-30 16:54:58 +0800103 if (*cpuPresent == false)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500104 {
Chicago Duana1649ec2021-03-30 16:54:58 +0800105 // Slot is not populated
Gunnar Millsac6a4442020-10-14 14:55:29 -0500106 aResp->res.jsonValue["Status"]["State"] = "Absent";
Chicago Duana1649ec2021-03-30 16:54:58 +0800107 }
108 }
109 else if (property.first == "Functional")
110 {
111 const bool* cpuFunctional = std::get_if<bool>(&property.second);
112 if (cpuFunctional == nullptr)
113 {
114 messages::internalError(aResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500115 return;
116 }
Chicago Duana1649ec2021-03-30 16:54:58 +0800117 if (*cpuFunctional == false)
118 {
119 aResp->res.jsonValue["Status"]["Health"] = "Critical";
120 }
121 }
122 else if (property.first == "CoreCount")
123 {
124 const uint16_t* coresCount =
125 std::get_if<uint16_t>(&property.second);
126 if (coresCount == nullptr)
127 {
128 messages::internalError(aResp->res);
129 return;
130 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500131 aResp->res.jsonValue["TotalCores"] = *coresCount;
132 }
Jonathan Domandc3fa662020-10-26 23:10:24 -0700133 else if (property.first == "MaxSpeedInMhz")
134 {
135 const uint32_t* value = std::get_if<uint32_t>(&property.second);
136 if (value != nullptr)
137 {
138 aResp->res.jsonValue["MaxSpeedMHz"] = *value;
139 }
140 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500141 else if (property.first == "Socket")
142 {
143 const std::string* value =
144 std::get_if<std::string>(&property.second);
145 if (value != nullptr)
146 {
147 aResp->res.jsonValue["Socket"] = *value;
148 }
149 }
150 else if (property.first == "ThreadCount")
151 {
Jonathan Domandc3fa662020-10-26 23:10:24 -0700152 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500153 if (value != nullptr)
154 {
155 aResp->res.jsonValue["TotalThreads"] = *value;
156 }
157 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700158 else if (property.first == "EffectiveFamily")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500159 {
Brandon Kim1930fbd2021-09-14 17:52:51 -0700160 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500161 if (value != nullptr)
162 {
163 aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
Brandon Kim1930fbd2021-09-14 17:52:51 -0700164 "0x" + intToHexString(*value);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500165 }
166 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700167 else if (property.first == "EffectiveModel")
168 {
169 const uint16_t* value = std::get_if<uint16_t>(&property.second);
170 if (value == nullptr)
171 {
172 messages::internalError(aResp->res);
173 return;
174 }
175 aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] =
176 "0x" + intToHexString(*value);
177 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500178 else if (property.first == "Id")
179 {
180 const uint64_t* value = std::get_if<uint64_t>(&property.second);
181 if (value != nullptr && *value != 0)
182 {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500183 aResp->res
184 .jsonValue["ProcessorId"]["IdentificationRegisters"] =
Ed Tanousf201ffb2021-10-09 14:49:28 -0700185 "0x" + intToHexString(*value);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500186 }
187 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700188 else if (property.first == "Microcode")
189 {
190 const uint32_t* value = std::get_if<uint32_t>(&property.second);
191 if (value == nullptr)
192 {
193 messages::internalError(aResp->res);
194 return;
195 }
196 aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] =
197 "0x" + intToHexString(*value);
198 }
199 else if (property.first == "Step")
200 {
201 const uint16_t* value = std::get_if<uint16_t>(&property.second);
202 if (value == nullptr)
203 {
204 messages::internalError(aResp->res);
205 return;
206 }
207 aResp->res.jsonValue["ProcessorId"]["Step"] =
208 "0x" + intToHexString(*value);
209 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500210 }
211 }
212
Gunnar Millsac6a4442020-10-14 14:55:29 -0500213 return;
214}
215
zhanghch058d1b46d2021-04-01 11:18:24 +0800216inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500217 const std::string& cpuId,
218 const std::string& service,
219 const std::string& objPath)
220{
221 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
222
223 crow::connections::systemBus->async_method_call(
224 [cpuId, service, objPath, aResp{std::move(aResp)}](
225 const boost::system::error_code ec,
226 const dbus::utility::ManagedObjectType& dbusData) {
227 if (ec)
228 {
229 BMCWEB_LOG_DEBUG << "DBUS response error";
230 messages::internalError(aResp->res);
231 return;
232 }
233 aResp->res.jsonValue["Id"] = cpuId;
234 aResp->res.jsonValue["Name"] = "Processor";
235 aResp->res.jsonValue["ProcessorType"] = "CPU";
236
237 bool slotPresent = false;
238 std::string corePath = objPath + "/core";
239 size_t totalCores = 0;
240 for (const auto& object : dbusData)
241 {
242 if (object.first.str == objPath)
243 {
244 getCpuDataByInterface(aResp, object.second);
245 }
246 else if (boost::starts_with(object.first.str, corePath))
247 {
248 for (const auto& interface : object.second)
249 {
250 if (interface.first ==
251 "xyz.openbmc_project.Inventory.Item")
252 {
253 for (const auto& property : interface.second)
254 {
255 if (property.first == "Present")
256 {
257 const bool* present =
258 std::get_if<bool>(&property.second);
259 if (present != nullptr)
260 {
261 if (*present == true)
262 {
263 slotPresent = true;
264 totalCores++;
265 }
266 }
267 }
268 }
269 }
270 }
271 }
272 }
273 // In getCpuDataByInterface(), state and health are set
274 // based on the present and functional status. If core
275 // count is zero, then it has a higher precedence.
276 if (slotPresent)
277 {
278 if (totalCores == 0)
279 {
280 // Slot is not populated, set status end return
281 aResp->res.jsonValue["Status"]["State"] = "Absent";
282 aResp->res.jsonValue["Status"]["Health"] = "OK";
283 }
284 aResp->res.jsonValue["TotalCores"] = totalCores;
285 }
286 return;
287 },
288 service, "/xyz/openbmc_project/inventory",
289 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
290}
291
zhanghch058d1b46d2021-04-01 11:18:24 +0800292inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500293 const std::string& service,
294 const std::string& objPath)
295{
296 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
297 crow::connections::systemBus->async_method_call(
298 [objPath, aResp{std::move(aResp)}](
299 const boost::system::error_code ec,
300 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800301 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500302 if (ec)
303 {
304 BMCWEB_LOG_DEBUG << "DBUS response error";
305 messages::internalError(aResp->res);
306 return;
307 }
308
309 for (const auto& property : properties)
310 {
311 if (property.first == "SerialNumber")
312 {
313 const std::string* sn =
314 std::get_if<std::string>(&property.second);
315 if (sn != nullptr && !sn->empty())
316 {
317 aResp->res.jsonValue["SerialNumber"] = *sn;
318 }
319 }
320 else if (property.first == "Model")
321 {
322 const std::string* model =
323 std::get_if<std::string>(&property.second);
324 if (model != nullptr && !model->empty())
325 {
326 aResp->res.jsonValue["Model"] = *model;
327 }
328 }
329 else if (property.first == "Manufacturer")
330 {
331
332 const std::string* mfg =
333 std::get_if<std::string>(&property.second);
334 if (mfg != nullptr)
335 {
336 aResp->res.jsonValue["Manufacturer"] = *mfg;
337
338 // Otherwise would be unexpected.
339 if (mfg->find("Intel") != std::string::npos)
340 {
341 aResp->res.jsonValue["ProcessorArchitecture"] =
342 "x86";
343 aResp->res.jsonValue["InstructionSet"] = "x86-64";
344 }
345 else if (mfg->find("IBM") != std::string::npos)
346 {
347 aResp->res.jsonValue["ProcessorArchitecture"] =
348 "Power";
349 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
350 }
351 }
352 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600353 else if (property.first == "PartNumber")
354 {
355 const std::string* partNumber =
356 std::get_if<std::string>(&property.second);
357
358 if (partNumber == nullptr)
359 {
360 messages::internalError(aResp->res);
361 return;
362 }
363 aResp->res.jsonValue["PartNumber"] = *partNumber;
364 }
365 else if (property.first == "SparePartNumber")
366 {
367 const std::string* sparePartNumber =
368 std::get_if<std::string>(&property.second);
369
370 if (sparePartNumber == nullptr)
371 {
372 messages::internalError(aResp->res);
373 return;
374 }
375 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
376 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500377 }
378 },
379 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
380 "xyz.openbmc_project.Inventory.Decorator.Asset");
381}
382
zhanghch058d1b46d2021-04-01 11:18:24 +0800383inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500384 const std::string& service,
385 const std::string& objPath)
386{
387 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
388 crow::connections::systemBus->async_method_call(
389 [objPath, aResp{std::move(aResp)}](
390 const boost::system::error_code ec,
391 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800392 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500393 if (ec)
394 {
395 BMCWEB_LOG_DEBUG << "DBUS response error";
396 messages::internalError(aResp->res);
397 return;
398 }
399
400 for (const auto& property : properties)
401 {
402 if (property.first == "Version")
403 {
404 const std::string* ver =
405 std::get_if<std::string>(&property.second);
406 if (ver != nullptr)
407 {
408 aResp->res.jsonValue["Version"] = *ver;
409 }
410 break;
411 }
412 }
413 },
414 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
415 "xyz.openbmc_project.Inventory.Decorator.Revision");
416}
417
zhanghch058d1b46d2021-04-01 11:18:24 +0800418inline void getAcceleratorDataByService(
419 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
420 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500421{
422 BMCWEB_LOG_DEBUG
423 << "Get available system Accelerator resources by service.";
424 crow::connections::systemBus->async_method_call(
425 [acclrtrId, aResp{std::move(aResp)}](
426 const boost::system::error_code ec,
427 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800428 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500429 if (ec)
430 {
431 BMCWEB_LOG_DEBUG << "DBUS response error";
432 messages::internalError(aResp->res);
433 return;
434 }
435 aResp->res.jsonValue["Id"] = acclrtrId;
436 aResp->res.jsonValue["Name"] = "Processor";
437 const bool* accPresent = nullptr;
438 const bool* accFunctional = nullptr;
439
440 for (const auto& property : properties)
441 {
442 if (property.first == "Functional")
443 {
444 accFunctional = std::get_if<bool>(&property.second);
445 }
446 else if (property.first == "Present")
447 {
448 accPresent = std::get_if<bool>(&property.second);
449 }
450 }
451
452 std::string state = "Enabled";
453 std::string health = "OK";
454
455 if (accPresent != nullptr && *accPresent == false)
456 {
457 state = "Absent";
458 }
459
460 if ((accFunctional != nullptr) && (*accFunctional == false))
461 {
462 if (state == "Enabled")
463 {
464 health = "Critical";
465 }
466 }
467
468 aResp->res.jsonValue["Status"]["State"] = state;
469 aResp->res.jsonValue["Status"]["Health"] = health;
470 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
471 },
472 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
473}
474
Jonathan Domandba0c292020-12-02 15:34:13 -0800475// OperatingConfig D-Bus Types
476using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
477using BaseSpeedPrioritySettingsProperty =
478 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
479// uint32_t and size_t may or may not be the same type, requiring a dedup'd
480// variant
Ed Tanous168e20c2021-12-13 14:39:53 -0800481using OperatingConfigProperties =
482 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>;
Jonathan Domandba0c292020-12-02 15:34:13 -0800483
484/**
485 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
486 * OperatingConfig D-Bus property.
487 *
488 * @param[in,out] aResp Async HTTP response.
489 * @param[in] baseSpeedSettings Full list of base speed priority groups,
490 * to use to determine the list of high
491 * speed cores.
492 */
493inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800494 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800495 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
496{
497 // The D-Bus property does not indicate which bucket is the "high
498 // priority" group, so let's discern that by looking for the one with
499 // highest base frequency.
500 auto highPriorityGroup = baseSpeedSettings.cend();
501 uint32_t highestBaseSpeed = 0;
502 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
503 ++it)
504 {
505 const uint32_t baseFreq = std::get<uint32_t>(*it);
506 if (baseFreq > highestBaseSpeed)
507 {
508 highestBaseSpeed = baseFreq;
509 highPriorityGroup = it;
510 }
511 }
512
513 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
514 jsonCoreIds = nlohmann::json::array();
515
516 // There may not be any entries in the D-Bus property, so only populate
517 // if there was actually something there.
518 if (highPriorityGroup != baseSpeedSettings.cend())
519 {
520 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
521 }
522}
523
524/**
525 * Fill out OperatingConfig related items in a Processor resource by requesting
526 * data from the given D-Bus object.
527 *
528 * @param[in,out] aResp Async HTTP response.
529 * @param[in] cpuId CPU D-Bus name.
530 * @param[in] service D-Bus service to query.
531 * @param[in] objPath D-Bus object to query.
532 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800533inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800534 const std::string& cpuId,
535 const std::string& service,
536 const std::string& objPath)
537{
538 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
539
540 // First, GetAll CurrentOperatingConfig properties on the object
541 crow::connections::systemBus->async_method_call(
542 [aResp, cpuId, service](
543 const boost::system::error_code ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800544 const std::vector<std::pair<
545 std::string, dbus::utility::DbusVariantType>>& properties) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800546 if (ec)
547 {
548 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
549 << ec.message();
550 messages::internalError(aResp->res);
551 return;
552 }
553
554 nlohmann::json& json = aResp->res.jsonValue;
555
556 for (const auto& [dbusPropName, variantVal] : properties)
557 {
558 if (dbusPropName == "AppliedConfig")
559 {
560 const sdbusplus::message::object_path* dbusPathWrapper =
561 std::get_if<sdbusplus::message::object_path>(
562 &variantVal);
563 if (dbusPathWrapper == nullptr)
564 {
565 continue;
566 }
567
568 const std::string& dbusPath = dbusPathWrapper->str;
569 std::string uri = "/redfish/v1/Systems/system/Processors/" +
570 cpuId + "/OperatingConfigs";
571 json["OperatingConfigs"] = {{"@odata.id", uri}};
572
573 // Reuse the D-Bus config object name for the Redfish
574 // URI
575 size_t baseNamePos = dbusPath.rfind('/');
576 if (baseNamePos == std::string::npos ||
577 baseNamePos == (dbusPath.size() - 1))
578 {
579 // If the AppliedConfig was somehow not a valid path,
580 // skip adding any more properties, since everything
581 // else is tied to this applied config.
582 messages::internalError(aResp->res);
583 break;
584 }
585 uri += '/';
586 uri += dbusPath.substr(baseNamePos + 1);
587 json["AppliedOperatingConfig"] = {{"@odata.id", uri}};
588
589 // Once we found the current applied config, queue another
590 // request to read the base freq core ids out of that
591 // config.
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700592 sdbusplus::asio::getProperty<
593 BaseSpeedPrioritySettingsProperty>(
594 *crow::connections::systemBus, service, dbusPath,
595 "xyz.openbmc_project.Inventory.Item.Cpu."
596 "OperatingConfig",
597 "BaseSpeedPrioritySettings",
598 [aResp](const boost::system::error_code ec,
599 const BaseSpeedPrioritySettingsProperty&
600 baseSpeedList) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800601 if (ec)
602 {
603 BMCWEB_LOG_WARNING
604 << "D-Bus Property Get error: " << ec;
605 messages::internalError(aResp->res);
606 return;
607 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700608
609 highSpeedCoreIdsHandler(aResp, baseSpeedList);
610 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800611 }
612 else if (dbusPropName == "BaseSpeedPriorityEnabled")
613 {
614 const bool* state = std::get_if<bool>(&variantVal);
615 if (state != nullptr)
616 {
617 json["BaseSpeedPriorityState"] =
618 *state ? "Enabled" : "Disabled";
619 }
620 }
621 }
622 },
623 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
624 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
625}
626
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600627/**
628 * @brief Fill out location info of a processor by
629 * requesting data from the given D-Bus object.
630 *
631 * @param[in,out] aResp Async HTTP response.
632 * @param[in] service D-Bus service to query.
633 * @param[in] objPath D-Bus object to query.
634 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800635inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600636 const std::string& service,
637 const std::string& objPath)
638{
639 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700640 sdbusplus::asio::getProperty<std::string>(
641 *crow::connections::systemBus, service, objPath,
642 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
643 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
644 const std::string& property) {
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600645 if (ec)
646 {
647 BMCWEB_LOG_DEBUG << "DBUS response error";
648 messages::internalError(aResp->res);
649 return;
650 }
651
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600652 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700653 property;
654 });
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600655}
656
Jonathan Domanc9514482021-02-24 09:20:51 -0800657/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800658 * Populate the unique identifier in a Processor resource by requesting data
659 * from the given D-Bus object.
660 *
661 * @param[in,out] aResp Async HTTP response.
662 * @param[in] service D-Bus service to query.
663 * @param[in] objPath D-Bus object to query.
664 */
665inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
666 const std::string& service,
667 const std::string& objectPath)
668{
669 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700670 sdbusplus::asio::getProperty<std::string>(
671 *crow::connections::systemBus, service, objectPath,
672 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
673 "UniqueIdentifier",
674 [aResp](boost::system::error_code ec, const std::string& id) {
675 if (ec)
Jonathan Doman49e429c2021-03-03 13:11:44 -0800676 {
677 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
678 messages::internalError(aResp->res);
679 return;
680 }
681 aResp->res
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700682 .jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] = id;
683 });
Jonathan Doman49e429c2021-03-03 13:11:44 -0800684}
685
686/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800687 * Find the D-Bus object representing the requested Processor, and call the
688 * handler with the results. If matching object is not found, add 404 error to
689 * response and don't call the handler.
690 *
691 * @param[in,out] resp Async HTTP response.
692 * @param[in] processorId Redfish Processor Id.
693 * @param[in] handler Callback to continue processing request upon
694 * successfully finding object.
695 */
696template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800697inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800698 const std::string& processorId,
699 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500700{
701 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
702
Jonathan Domanc9514482021-02-24 09:20:51 -0800703 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500704 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800705 [resp, processorId, handler = std::forward<Handler>(handler)](
706 boost::system::error_code ec,
707 const MapperGetSubTreeResponse& subtree) mutable {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500708 if (ec)
709 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800710 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
711 messages::internalError(resp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500712 return;
713 }
Jonathan Doman2bab9832020-12-02 15:27:40 -0800714 for (const auto& [objectPath, serviceMap] : subtree)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500715 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800716 // Ignore any objects which don't end with our desired cpu name
717 if (!boost::ends_with(objectPath, processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500718 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800719 continue;
720 }
721
Jonathan Domanc9514482021-02-24 09:20:51 -0800722 bool found = false;
723 // Filter out objects that don't have the CPU-specific
724 // interfaces to make sure we can return 404 on non-CPUs
725 // (e.g. /redfish/../Processors/dimm0)
Jonathan Doman2bab9832020-12-02 15:27:40 -0800726 for (const auto& [serviceName, interfaceList] : serviceMap)
727 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800728 if (std::find_first_of(
729 interfaceList.begin(), interfaceList.end(),
730 processorInterfaces.begin(),
731 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500732 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800733 found = true;
734 break;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500735 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500736 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800737
738 if (!found)
739 {
740 continue;
741 }
742
743 // Process the first object which does match our cpu name and
744 // required interfaces, and potentially ignore any other
745 // matching objects. Assume all interfaces we want to process
746 // must be on the same object path.
747
748 handler(resp, processorId, objectPath, serviceMap);
Jonathan Doman2bab9832020-12-02 15:27:40 -0800749 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500750 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800751 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500752 },
753 "xyz.openbmc_project.ObjectMapper",
754 "/xyz/openbmc_project/object_mapper",
755 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800756 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800757 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530758 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800759 "xyz.openbmc_project.Inventory.Decorator.Asset",
760 "xyz.openbmc_project.Inventory.Decorator.Revision",
761 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600762 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800763 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800764 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
765 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500766}
767
zhanghch058d1b46d2021-04-01 11:18:24 +0800768inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800769 const std::string& processorId,
770 const std::string& objectPath,
771 const MapperServiceMap& serviceMap)
772{
773 for (const auto& [serviceName, interfaceList] : serviceMap)
774 {
775 for (const auto& interface : interfaceList)
776 {
777 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
778 {
779 getCpuAssetData(aResp, serviceName, objectPath);
780 }
George Liu0fda0f12021-11-16 10:06:17 +0800781 else if (interface ==
782 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800783 {
784 getCpuRevisionData(aResp, serviceName, objectPath);
785 }
786 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
787 {
788 getCpuDataByService(aResp, processorId, serviceName,
789 objectPath);
790 }
George Liu0fda0f12021-11-16 10:06:17 +0800791 else if (interface ==
792 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800793 {
794 getAcceleratorDataByService(aResp, processorId, serviceName,
795 objectPath);
796 }
George Liu0fda0f12021-11-16 10:06:17 +0800797 else if (
798 interface ==
799 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800800 {
801 getCpuConfigData(aResp, processorId, serviceName, objectPath);
802 }
George Liu0fda0f12021-11-16 10:06:17 +0800803 else if (interface ==
804 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800805 {
806 getCpuLocationCode(aResp, serviceName, objectPath);
807 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530808 else if (interface == "xyz.openbmc_project.Common.UUID")
809 {
810 getProcessorUUID(aResp, serviceName, objectPath);
811 }
George Liu0fda0f12021-11-16 10:06:17 +0800812 else if (interface ==
813 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800814 {
815 getCpuUniqueId(aResp, serviceName, objectPath);
816 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800817 }
818 }
819}
820
Jonathan Domandba0c292020-12-02 15:34:13 -0800821/**
822 * Request all the properties for the given D-Bus object and fill out the
823 * related entries in the Redfish OperatingConfig response.
824 *
825 * @param[in,out] aResp Async HTTP response.
826 * @param[in] service D-Bus service name to query.
827 * @param[in] objPath D-Bus object to query.
828 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800829inline void
830 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
831 const std::string& service,
832 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800833{
834 crow::connections::systemBus->async_method_call(
835 [aResp](boost::system::error_code ec,
836 const OperatingConfigProperties& properties) {
837 if (ec)
838 {
839 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
840 << ec.message();
841 messages::internalError(aResp->res);
842 return;
843 }
844
845 nlohmann::json& json = aResp->res.jsonValue;
846 for (const auto& [key, variant] : properties)
847 {
848 if (key == "AvailableCoreCount")
849 {
850 const size_t* cores = std::get_if<size_t>(&variant);
851 if (cores != nullptr)
852 {
853 json["TotalAvailableCoreCount"] = *cores;
854 }
855 }
856 else if (key == "BaseSpeed")
857 {
858 const uint32_t* speed = std::get_if<uint32_t>(&variant);
859 if (speed != nullptr)
860 {
861 json["BaseSpeedMHz"] = *speed;
862 }
863 }
864 else if (key == "MaxJunctionTemperature")
865 {
866 const uint32_t* temp = std::get_if<uint32_t>(&variant);
867 if (temp != nullptr)
868 {
869 json["MaxJunctionTemperatureCelsius"] = *temp;
870 }
871 }
872 else if (key == "MaxSpeed")
873 {
874 const uint32_t* speed = std::get_if<uint32_t>(&variant);
875 if (speed != nullptr)
876 {
877 json["MaxSpeedMHz"] = *speed;
878 }
879 }
880 else if (key == "PowerLimit")
881 {
882 const uint32_t* tdp = std::get_if<uint32_t>(&variant);
883 if (tdp != nullptr)
884 {
885 json["TDPWatts"] = *tdp;
886 }
887 }
888 else if (key == "TurboProfile")
889 {
890 const auto* turboList =
891 std::get_if<TurboProfileProperty>(&variant);
892 if (turboList == nullptr)
893 {
894 continue;
895 }
896
897 nlohmann::json& turboArray = json["TurboProfile"];
898 turboArray = nlohmann::json::array();
899 for (const auto& [turboSpeed, coreCount] : *turboList)
900 {
901 turboArray.push_back({{"ActiveCoreCount", coreCount},
902 {"MaxSpeedMHz", turboSpeed}});
903 }
904 }
905 else if (key == "BaseSpeedPrioritySettings")
906 {
907 const auto* baseSpeedList =
908 std::get_if<BaseSpeedPrioritySettingsProperty>(
909 &variant);
910 if (baseSpeedList == nullptr)
911 {
912 continue;
913 }
914
915 nlohmann::json& baseSpeedArray =
916 json["BaseSpeedPrioritySettings"];
917 baseSpeedArray = nlohmann::json::array();
918 for (const auto& [baseSpeed, coreList] : *baseSpeedList)
919 {
920 baseSpeedArray.push_back(
921 {{"CoreCount", coreList.size()},
922 {"CoreIDs", coreList},
923 {"BaseSpeedMHz", baseSpeed}});
924 }
925 }
926 }
927 },
928 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
929 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig");
930}
931
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800932/**
933 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
934 * property. Main task is to translate error messages into Redfish errors.
935 *
936 * @param[in,out] resp HTTP response.
937 * @param[in] setPropVal Value which we attempted to set.
938 * @param[in] ec D-Bus response error code.
939 * @param[in] msg D-Bus response message.
940 */
941inline void
942 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
943 const std::string& setPropVal,
944 boost::system::error_code ec,
945 const sdbusplus::message::message& msg)
946{
947 if (!ec)
948 {
949 BMCWEB_LOG_DEBUG << "Set Property succeeded";
950 return;
951 }
952
953 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
954
955 const sd_bus_error* dbusError = msg.get_error();
956 if (dbusError == nullptr)
957 {
958 messages::internalError(resp->res);
959 return;
960 }
961
962 // The asio error code doesn't know about our custom errors, so we have to
963 // parse the error string. Some of these D-Bus -> Redfish translations are a
964 // stretch, but it's good to try to communicate something vaguely useful.
965 if (strcmp(dbusError->name,
966 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
967 {
968 // Service did not like the object_path we tried to set.
969 messages::propertyValueIncorrect(
970 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
971 }
972 else if (strcmp(dbusError->name,
973 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
974 {
975 // Service indicates we can never change the config for this processor.
976 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
977 }
978 else if (strcmp(dbusError->name,
979 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
980 {
981 // Service indicates the config cannot be changed right now, but maybe
982 // in a different system state.
983 messages::resourceInStandby(resp->res);
984 }
985 else if (strcmp(dbusError->name,
986 "xyz.openbmc_project.Common.Device.Error.WriteFailure") ==
987 0)
988 {
989 // Service tried to change the config, but it failed.
990 messages::operationFailed(resp->res);
991 }
992 else
993 {
994 messages::internalError(resp->res);
995 }
996}
997
998/**
999 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
1000 * validation of the input data, and then set the D-Bus property.
1001 *
1002 * @param[in,out] resp Async HTTP response.
1003 * @param[in] processorId Processor's Id.
1004 * @param[in] appliedConfigUri New property value to apply.
1005 * @param[in] cpuObjectPath Path of CPU object to modify.
1006 * @param[in] serviceMap Service map for CPU object.
1007 */
1008inline void patchAppliedOperatingConfig(
1009 const std::shared_ptr<bmcweb::AsyncResp>& resp,
1010 const std::string& processorId, const std::string& appliedConfigUri,
1011 const std::string& cpuObjectPath, const MapperServiceMap& serviceMap)
1012{
1013 // Check that the property even exists by checking for the interface
1014 const std::string* controlService = nullptr;
1015 for (const auto& [serviceName, interfaceList] : serviceMap)
1016 {
1017 if (std::find(interfaceList.begin(), interfaceList.end(),
1018 "xyz.openbmc_project.Control.Processor."
1019 "CurrentOperatingConfig") != interfaceList.end())
1020 {
1021 controlService = &serviceName;
1022 break;
1023 }
1024 }
1025
1026 if (controlService == nullptr)
1027 {
1028 messages::internalError(resp->res);
1029 return;
1030 }
1031
1032 // Check that the config URI is a child of the cpu URI being patched.
1033 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
1034 expectedPrefix += processorId;
1035 expectedPrefix += "/OperatingConfigs/";
1036 if (!boost::starts_with(appliedConfigUri, expectedPrefix) ||
1037 expectedPrefix.size() == appliedConfigUri.size())
1038 {
1039 messages::propertyValueIncorrect(
1040 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1041 return;
1042 }
1043
1044 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1045 // direct child of the CPU object.
1046 // Strip the expectedPrefix from the config URI to get the "filename", and
1047 // append to the CPU's path.
1048 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1049 sdbusplus::message::object_path configPath(cpuObjectPath);
1050 configPath /= configBaseName;
1051
1052 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1053
1054 // Set the property, with handler to check error responses
1055 crow::connections::systemBus->async_method_call(
1056 [resp, appliedConfigUri](boost::system::error_code ec,
1057 sdbusplus::message::message& msg) {
1058 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
1059 },
1060 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1061 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
Ed Tanous168e20c2021-12-13 14:39:53 -08001062 "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001063}
1064
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001065inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001066{
Jonathan Domandba0c292020-12-02 15:34:13 -08001067
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001068 BMCWEB_ROUTE(
1069 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001070 .privileges(redfish::privileges::getOperatingConfigCollection)
George Liu0fda0f12021-11-16 10:06:17 +08001071 .methods(
1072 boost::beast::http::verb::get)([](const crow::Request& req,
1073 const std::shared_ptr<
1074 bmcweb::AsyncResp>& asyncResp,
1075 const std::string& cpuName) {
1076 asyncResp->res.jsonValue["@odata.type"] =
1077 "#OperatingConfigCollection.OperatingConfigCollection";
1078 asyncResp->res.jsonValue["@odata.id"] = req.url;
1079 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
Jonathan Domandba0c292020-12-02 15:34:13 -08001080
George Liu0fda0f12021-11-16 10:06:17 +08001081 // First find the matching CPU object so we know how to
1082 // constrain our search for related Config objects.
1083 crow::connections::systemBus->async_method_call(
1084 [asyncResp, cpuName](const boost::system::error_code ec,
1085 const std::vector<std::string>& objects) {
1086 if (ec)
1087 {
1088 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1089 << ec.message();
1090 messages::internalError(asyncResp->res);
1091 return;
1092 }
1093
1094 for (const std::string& object : objects)
1095 {
1096 if (!boost::ends_with(object, cpuName))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001097 {
George Liu0fda0f12021-11-16 10:06:17 +08001098 continue;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001099 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001100
George Liu0fda0f12021-11-16 10:06:17 +08001101 // Not expected that there will be multiple matching
1102 // CPU objects, but if there are just use the first
1103 // one.
Jonathan Domandba0c292020-12-02 15:34:13 -08001104
George Liu0fda0f12021-11-16 10:06:17 +08001105 // Use the common search routine to construct the
1106 // Collection of all Config objects under this CPU.
1107 collection_util::getCollectionMembers(
1108 asyncResp,
1109 "/redfish/v1/Systems/system/Processors/" + cpuName +
1110 "/OperatingConfigs",
1111 {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1112 object.c_str());
1113 return;
1114 }
1115 },
1116 "xyz.openbmc_project.ObjectMapper",
1117 "/xyz/openbmc_project/object_mapper",
1118 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1119 "/xyz/openbmc_project/inventory", 0,
1120 std::array<const char*, 1>{
1121 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
1122 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001123}
1124
1125inline void requestRoutesOperatingConfig(App& app)
1126{
1127 BMCWEB_ROUTE(
1128 app,
1129 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001130 .privileges(redfish::privileges::getOperatingConfig)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001131 .methods(
1132 boost::beast::http::verb::get)([](const crow::Request& req,
1133 const std::shared_ptr<
1134 bmcweb::AsyncResp>& asyncResp,
1135 const std::string& cpuName,
1136 const std::string& configName) {
1137 // Ask for all objects implementing OperatingConfig so we can search
1138 // for one with a matching name
1139 crow::connections::systemBus->async_method_call(
1140 [asyncResp, cpuName, configName,
1141 reqUrl{req.url}](boost::system::error_code ec,
1142 const MapperGetSubTreeResponse& subtree) {
1143 if (ec)
Jonathan Domandba0c292020-12-02 15:34:13 -08001144 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001145 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1146 << ec.message();
1147 messages::internalError(asyncResp->res);
1148 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001149 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001150 const std::string expectedEnding =
1151 cpuName + '/' + configName;
1152 for (const auto& [objectPath, serviceMap] : subtree)
Jonathan Domandba0c292020-12-02 15:34:13 -08001153 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001154 // Ignore any configs without matching cpuX/configY
1155 if (!boost::ends_with(objectPath, expectedEnding) ||
1156 serviceMap.empty())
1157 {
1158 continue;
1159 }
1160
1161 nlohmann::json& json = asyncResp->res.jsonValue;
1162 json["@odata.type"] =
1163 "#OperatingConfig.v1_0_0.OperatingConfig";
1164 json["@odata.id"] = reqUrl;
1165 json["Name"] = "Processor Profile";
1166 json["Id"] = configName;
1167
1168 // Just use the first implementation of the object - not
1169 // expected that there would be multiple matching
1170 // services
1171 getOperatingConfigData(
1172 asyncResp, serviceMap.begin()->first, objectPath);
1173 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001174 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001175 messages::resourceNotFound(asyncResp->res,
1176 "OperatingConfig", configName);
1177 },
1178 "xyz.openbmc_project.ObjectMapper",
1179 "/xyz/openbmc_project/object_mapper",
1180 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1181 "/xyz/openbmc_project/inventory", 0,
1182 std::array<const char*, 1>{
1183 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
1184 });
1185}
Jonathan Domandba0c292020-12-02 15:34:13 -08001186
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001187inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001188{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001189 /**
1190 * Functions triggers appropriate requests on DBus
1191 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001192 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001193 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001194 .methods(boost::beast::http::verb::get)(
1195 [](const crow::Request&,
1196 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1197 asyncResp->res.jsonValue["@odata.type"] =
1198 "#ProcessorCollection.ProcessorCollection";
1199 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001200
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001201 asyncResp->res.jsonValue["@odata.id"] =
1202 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001203
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001204 collection_util::getCollectionMembers(
1205 asyncResp, "/redfish/v1/Systems/system/Processors",
1206 std::vector<const char*>(processorInterfaces.begin(),
1207 processorInterfaces.end()));
1208 });
1209}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001210
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001211inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001212{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001213 /**
1214 * Functions triggers appropriate requests on DBus
1215 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001216
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001217 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001218 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219 .methods(boost::beast::http::verb::get)(
1220 [](const crow::Request&,
1221 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1222 const std::string& processorId) {
1223 asyncResp->res.jsonValue["@odata.type"] =
1224 "#Processor.v1_11_0.Processor";
1225 asyncResp->res.jsonValue["@odata.id"] =
1226 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001227
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001228 getProcessorObject(asyncResp, processorId, getProcessorData);
1229 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001230
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001231 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001232 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001233 .methods(boost::beast::http::verb::patch)(
1234 [](const crow::Request& req,
1235 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1236 const std::string& processorId) {
1237 std::optional<nlohmann::json> appliedConfigJson;
1238 if (!json_util::readJson(req, asyncResp->res,
1239 "AppliedOperatingConfig",
1240 appliedConfigJson))
1241 {
1242 return;
1243 }
1244
1245 std::string appliedConfigUri;
1246 if (appliedConfigJson)
1247 {
1248 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1249 "@odata.id", appliedConfigUri))
1250 {
1251 return;
1252 }
1253 // Check for 404 and find matching D-Bus object, then run
1254 // property patch handlers if that all succeeds.
1255 getProcessorObject(
1256 asyncResp, processorId,
1257 [appliedConfigUri = std::move(appliedConfigUri)](
1258 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1259 const std::string& processorId,
1260 const std::string& objectPath,
1261 const MapperServiceMap& serviceMap) {
1262 patchAppliedOperatingConfig(asyncResp, processorId,
1263 appliedConfigUri,
1264 objectPath, serviceMap);
1265 });
1266 }
1267 });
1268}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001269
1270} // namespace redfish