blob: e5107684424b8dfb6c3af89cf74dabe807f21644 [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
18#include "health.hpp"
19
John Edward Broadbent7e860f12021-04-08 15:57:16 -070020#include <app.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050021#include <boost/container/flat_map.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070022#include <registries/privilege_registry.hpp>
Jonathan Domandba0c292020-12-02 15:34:13 -080023#include <sdbusplus/message/native_types.hpp>
24#include <sdbusplus/utility/dedup_variant.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050025#include <utils/collection.hpp>
26#include <utils/json_utils.hpp>
27
28namespace redfish
29{
30
31using InterfacesProperties = boost::container::flat_map<
32 std::string,
33 boost::container::flat_map<std::string, dbus::utility::DbusVariantType>>;
34
Jonathan Domanc9514482021-02-24 09:20:51 -080035// Map of service name to list of interfaces
36using MapperServiceMap =
37 std::vector<std::pair<std::string, std::vector<std::string>>>;
38
39// Map of object paths to MapperServiceMaps
40using MapperGetSubTreeResponse =
41 std::vector<std::pair<std::string, MapperServiceMap>>;
42
43// Interfaces which imply a D-Bus object represents a Processor
44constexpr std::array<const char*, 2> processorInterfaces = {
45 "xyz.openbmc_project.Inventory.Item.Cpu",
46 "xyz.openbmc_project.Inventory.Item.Accelerator"};
Jonathan Doman2bab9832020-12-02 15:27:40 -080047
Sharad Yadav71b82f22021-05-10 15:11:39 +053048/**
49 * @brief Fill out uuid info of a processor by
50 * requesting data from the given D-Bus object.
51 *
52 * @param[in,out] aResp Async HTTP response.
53 * @param[in] service D-Bus service to query.
54 * @param[in] objPath D-Bus object to query.
55 */
56inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp,
57 const std::string& service,
58 const std::string& objPath)
59{
60 BMCWEB_LOG_DEBUG << "Get Processor UUID";
61 crow::connections::systemBus->async_method_call(
62 [objPath,
63 aResp{std::move(aResp)}](const boost::system::error_code ec,
64 const std::variant<std::string>& property) {
65 if (ec)
66 {
67 BMCWEB_LOG_DEBUG << "DBUS response error";
68 messages::internalError(aResp->res);
69 return;
70 }
71 const std::string* value = std::get_if<std::string>(&property);
72 if (value == nullptr)
73 {
74 BMCWEB_LOG_DEBUG << "Null value returned "
75 "for UUID";
76 messages::internalError(aResp->res);
77 return;
78 }
79 aResp->res.jsonValue["UUID"] = *value;
80 },
81 service, objPath, "org.freedesktop.DBus.Properties", "Get",
82 "xyz.openbmc_project.Common.UUID", "UUID");
83}
84
Gunnar Millsac6a4442020-10-14 14:55:29 -050085inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080086 getCpuDataByInterface(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -050087 const InterfacesProperties& cpuInterfacesProperties)
88{
89 BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
90
Chicago Duana1649ec2021-03-30 16:54:58 +080091 // Set the default value of state
92 aResp->res.jsonValue["Status"]["State"] = "Enabled";
93 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -050094
95 for (const auto& interface : cpuInterfacesProperties)
96 {
97 for (const auto& property : interface.second)
98 {
Chicago Duana1649ec2021-03-30 16:54:58 +080099 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500100 {
Chicago Duana1649ec2021-03-30 16:54:58 +0800101 const bool* cpuPresent = std::get_if<bool>(&property.second);
102 if (cpuPresent == nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500103 {
104 // Important property not in desired type
105 messages::internalError(aResp->res);
106 return;
107 }
Chicago Duana1649ec2021-03-30 16:54:58 +0800108 if (*cpuPresent == false)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500109 {
Chicago Duana1649ec2021-03-30 16:54:58 +0800110 // Slot is not populated
Gunnar Millsac6a4442020-10-14 14:55:29 -0500111 aResp->res.jsonValue["Status"]["State"] = "Absent";
Chicago Duana1649ec2021-03-30 16:54:58 +0800112 }
113 }
114 else if (property.first == "Functional")
115 {
116 const bool* cpuFunctional = std::get_if<bool>(&property.second);
117 if (cpuFunctional == nullptr)
118 {
119 messages::internalError(aResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500120 return;
121 }
Chicago Duana1649ec2021-03-30 16:54:58 +0800122 if (*cpuFunctional == false)
123 {
124 aResp->res.jsonValue["Status"]["Health"] = "Critical";
125 }
126 }
127 else if (property.first == "CoreCount")
128 {
129 const uint16_t* coresCount =
130 std::get_if<uint16_t>(&property.second);
131 if (coresCount == nullptr)
132 {
133 messages::internalError(aResp->res);
134 return;
135 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500136 aResp->res.jsonValue["TotalCores"] = *coresCount;
137 }
Jonathan Domandc3fa662020-10-26 23:10:24 -0700138 else if (property.first == "MaxSpeedInMhz")
139 {
140 const uint32_t* value = std::get_if<uint32_t>(&property.second);
141 if (value != nullptr)
142 {
143 aResp->res.jsonValue["MaxSpeedMHz"] = *value;
144 }
145 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500146 else if (property.first == "Socket")
147 {
148 const std::string* value =
149 std::get_if<std::string>(&property.second);
150 if (value != nullptr)
151 {
152 aResp->res.jsonValue["Socket"] = *value;
153 }
154 }
155 else if (property.first == "ThreadCount")
156 {
Jonathan Domandc3fa662020-10-26 23:10:24 -0700157 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500158 if (value != nullptr)
159 {
160 aResp->res.jsonValue["TotalThreads"] = *value;
161 }
162 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700163 else if (property.first == "EffectiveFamily")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500164 {
Brandon Kim1930fbd2021-09-14 17:52:51 -0700165 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500166 if (value != nullptr)
167 {
168 aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
Brandon Kim1930fbd2021-09-14 17:52:51 -0700169 "0x" + intToHexString(*value);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500170 }
171 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700172 else if (property.first == "EffectiveModel")
173 {
174 const uint16_t* value = std::get_if<uint16_t>(&property.second);
175 if (value == nullptr)
176 {
177 messages::internalError(aResp->res);
178 return;
179 }
180 aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] =
181 "0x" + intToHexString(*value);
182 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500183 else if (property.first == "Id")
184 {
185 const uint64_t* value = std::get_if<uint64_t>(&property.second);
186 if (value != nullptr && *value != 0)
187 {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500188 aResp->res
189 .jsonValue["ProcessorId"]["IdentificationRegisters"] =
Ed Tanousf201ffb2021-10-09 14:49:28 -0700190 "0x" + intToHexString(*value);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500191 }
192 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700193 else if (property.first == "Microcode")
194 {
195 const uint32_t* value = std::get_if<uint32_t>(&property.second);
196 if (value == nullptr)
197 {
198 messages::internalError(aResp->res);
199 return;
200 }
201 aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] =
202 "0x" + intToHexString(*value);
203 }
204 else if (property.first == "Step")
205 {
206 const uint16_t* value = std::get_if<uint16_t>(&property.second);
207 if (value == nullptr)
208 {
209 messages::internalError(aResp->res);
210 return;
211 }
212 aResp->res.jsonValue["ProcessorId"]["Step"] =
213 "0x" + intToHexString(*value);
214 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500215 }
216 }
217
Gunnar Millsac6a4442020-10-14 14:55:29 -0500218 return;
219}
220
zhanghch058d1b46d2021-04-01 11:18:24 +0800221inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500222 const std::string& cpuId,
223 const std::string& service,
224 const std::string& objPath)
225{
226 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
227
228 crow::connections::systemBus->async_method_call(
229 [cpuId, service, objPath, aResp{std::move(aResp)}](
230 const boost::system::error_code ec,
231 const dbus::utility::ManagedObjectType& dbusData) {
232 if (ec)
233 {
234 BMCWEB_LOG_DEBUG << "DBUS response error";
235 messages::internalError(aResp->res);
236 return;
237 }
238 aResp->res.jsonValue["Id"] = cpuId;
239 aResp->res.jsonValue["Name"] = "Processor";
240 aResp->res.jsonValue["ProcessorType"] = "CPU";
241
242 bool slotPresent = false;
243 std::string corePath = objPath + "/core";
244 size_t totalCores = 0;
245 for (const auto& object : dbusData)
246 {
247 if (object.first.str == objPath)
248 {
249 getCpuDataByInterface(aResp, object.second);
250 }
251 else if (boost::starts_with(object.first.str, corePath))
252 {
253 for (const auto& interface : object.second)
254 {
255 if (interface.first ==
256 "xyz.openbmc_project.Inventory.Item")
257 {
258 for (const auto& property : interface.second)
259 {
260 if (property.first == "Present")
261 {
262 const bool* present =
263 std::get_if<bool>(&property.second);
264 if (present != nullptr)
265 {
266 if (*present == true)
267 {
268 slotPresent = true;
269 totalCores++;
270 }
271 }
272 }
273 }
274 }
275 }
276 }
277 }
278 // In getCpuDataByInterface(), state and health are set
279 // based on the present and functional status. If core
280 // count is zero, then it has a higher precedence.
281 if (slotPresent)
282 {
283 if (totalCores == 0)
284 {
285 // Slot is not populated, set status end return
286 aResp->res.jsonValue["Status"]["State"] = "Absent";
287 aResp->res.jsonValue["Status"]["Health"] = "OK";
288 }
289 aResp->res.jsonValue["TotalCores"] = totalCores;
290 }
291 return;
292 },
293 service, "/xyz/openbmc_project/inventory",
294 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
295}
296
zhanghch058d1b46d2021-04-01 11:18:24 +0800297inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500298 const std::string& service,
299 const std::string& objPath)
300{
301 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
302 crow::connections::systemBus->async_method_call(
303 [objPath, aResp{std::move(aResp)}](
304 const boost::system::error_code ec,
305 const boost::container::flat_map<
306 std::string, std::variant<std::string, uint32_t, uint16_t,
307 bool>>& properties) {
308 if (ec)
309 {
310 BMCWEB_LOG_DEBUG << "DBUS response error";
311 messages::internalError(aResp->res);
312 return;
313 }
314
315 for (const auto& property : properties)
316 {
317 if (property.first == "SerialNumber")
318 {
319 const std::string* sn =
320 std::get_if<std::string>(&property.second);
321 if (sn != nullptr && !sn->empty())
322 {
323 aResp->res.jsonValue["SerialNumber"] = *sn;
324 }
325 }
326 else if (property.first == "Model")
327 {
328 const std::string* model =
329 std::get_if<std::string>(&property.second);
330 if (model != nullptr && !model->empty())
331 {
332 aResp->res.jsonValue["Model"] = *model;
333 }
334 }
335 else if (property.first == "Manufacturer")
336 {
337
338 const std::string* mfg =
339 std::get_if<std::string>(&property.second);
340 if (mfg != nullptr)
341 {
342 aResp->res.jsonValue["Manufacturer"] = *mfg;
343
344 // Otherwise would be unexpected.
345 if (mfg->find("Intel") != std::string::npos)
346 {
347 aResp->res.jsonValue["ProcessorArchitecture"] =
348 "x86";
349 aResp->res.jsonValue["InstructionSet"] = "x86-64";
350 }
351 else if (mfg->find("IBM") != std::string::npos)
352 {
353 aResp->res.jsonValue["ProcessorArchitecture"] =
354 "Power";
355 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
356 }
357 }
358 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600359 else if (property.first == "PartNumber")
360 {
361 const std::string* partNumber =
362 std::get_if<std::string>(&property.second);
363
364 if (partNumber == nullptr)
365 {
366 messages::internalError(aResp->res);
367 return;
368 }
369 aResp->res.jsonValue["PartNumber"] = *partNumber;
370 }
371 else if (property.first == "SparePartNumber")
372 {
373 const std::string* sparePartNumber =
374 std::get_if<std::string>(&property.second);
375
376 if (sparePartNumber == nullptr)
377 {
378 messages::internalError(aResp->res);
379 return;
380 }
381 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
382 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500383 }
384 },
385 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
386 "xyz.openbmc_project.Inventory.Decorator.Asset");
387}
388
zhanghch058d1b46d2021-04-01 11:18:24 +0800389inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500390 const std::string& service,
391 const std::string& objPath)
392{
393 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
394 crow::connections::systemBus->async_method_call(
395 [objPath, aResp{std::move(aResp)}](
396 const boost::system::error_code ec,
397 const boost::container::flat_map<
398 std::string, std::variant<std::string, uint32_t, uint16_t,
399 bool>>& properties) {
400 if (ec)
401 {
402 BMCWEB_LOG_DEBUG << "DBUS response error";
403 messages::internalError(aResp->res);
404 return;
405 }
406
407 for (const auto& property : properties)
408 {
409 if (property.first == "Version")
410 {
411 const std::string* ver =
412 std::get_if<std::string>(&property.second);
413 if (ver != nullptr)
414 {
415 aResp->res.jsonValue["Version"] = *ver;
416 }
417 break;
418 }
419 }
420 },
421 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
422 "xyz.openbmc_project.Inventory.Decorator.Revision");
423}
424
zhanghch058d1b46d2021-04-01 11:18:24 +0800425inline void getAcceleratorDataByService(
426 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
427 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500428{
429 BMCWEB_LOG_DEBUG
430 << "Get available system Accelerator resources by service.";
431 crow::connections::systemBus->async_method_call(
432 [acclrtrId, aResp{std::move(aResp)}](
433 const boost::system::error_code ec,
434 const boost::container::flat_map<
435 std::string, std::variant<std::string, uint32_t, uint16_t,
436 bool>>& properties) {
437 if (ec)
438 {
439 BMCWEB_LOG_DEBUG << "DBUS response error";
440 messages::internalError(aResp->res);
441 return;
442 }
443 aResp->res.jsonValue["Id"] = acclrtrId;
444 aResp->res.jsonValue["Name"] = "Processor";
445 const bool* accPresent = nullptr;
446 const bool* accFunctional = nullptr;
447
448 for (const auto& property : properties)
449 {
450 if (property.first == "Functional")
451 {
452 accFunctional = std::get_if<bool>(&property.second);
453 }
454 else if (property.first == "Present")
455 {
456 accPresent = std::get_if<bool>(&property.second);
457 }
458 }
459
460 std::string state = "Enabled";
461 std::string health = "OK";
462
463 if (accPresent != nullptr && *accPresent == false)
464 {
465 state = "Absent";
466 }
467
468 if ((accFunctional != nullptr) && (*accFunctional == false))
469 {
470 if (state == "Enabled")
471 {
472 health = "Critical";
473 }
474 }
475
476 aResp->res.jsonValue["Status"]["State"] = state;
477 aResp->res.jsonValue["Status"]["Health"] = health;
478 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
479 },
480 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
481}
482
Jonathan Domandba0c292020-12-02 15:34:13 -0800483// OperatingConfig D-Bus Types
484using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
485using BaseSpeedPrioritySettingsProperty =
486 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
487// uint32_t and size_t may or may not be the same type, requiring a dedup'd
488// variant
489using OperatingConfigProperties = std::vector<std::pair<
490 std::string,
Patrick Williams4f9637f2021-07-15 08:51:53 -0500491 sdbusplus::utility::dedup_variant_t<uint32_t, size_t, TurboProfileProperty,
492 BaseSpeedPrioritySettingsProperty>>>;
Jonathan Domandba0c292020-12-02 15:34:13 -0800493
494/**
495 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
496 * OperatingConfig D-Bus property.
497 *
498 * @param[in,out] aResp Async HTTP response.
499 * @param[in] baseSpeedSettings Full list of base speed priority groups,
500 * to use to determine the list of high
501 * speed cores.
502 */
503inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800504 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800505 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
506{
507 // The D-Bus property does not indicate which bucket is the "high
508 // priority" group, so let's discern that by looking for the one with
509 // highest base frequency.
510 auto highPriorityGroup = baseSpeedSettings.cend();
511 uint32_t highestBaseSpeed = 0;
512 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
513 ++it)
514 {
515 const uint32_t baseFreq = std::get<uint32_t>(*it);
516 if (baseFreq > highestBaseSpeed)
517 {
518 highestBaseSpeed = baseFreq;
519 highPriorityGroup = it;
520 }
521 }
522
523 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
524 jsonCoreIds = nlohmann::json::array();
525
526 // There may not be any entries in the D-Bus property, so only populate
527 // if there was actually something there.
528 if (highPriorityGroup != baseSpeedSettings.cend())
529 {
530 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
531 }
532}
533
534/**
535 * Fill out OperatingConfig related items in a Processor resource by requesting
536 * data from the given D-Bus object.
537 *
538 * @param[in,out] aResp Async HTTP response.
539 * @param[in] cpuId CPU D-Bus name.
540 * @param[in] service D-Bus service to query.
541 * @param[in] objPath D-Bus object to query.
542 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800543inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800544 const std::string& cpuId,
545 const std::string& service,
546 const std::string& objPath)
547{
548 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
549
550 // First, GetAll CurrentOperatingConfig properties on the object
551 crow::connections::systemBus->async_method_call(
552 [aResp, cpuId, service](
553 const boost::system::error_code ec,
554 const std::vector<
555 std::pair<std::string,
556 std::variant<sdbusplus::message::object_path, bool>>>&
557 properties) {
558 if (ec)
559 {
560 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
561 << ec.message();
562 messages::internalError(aResp->res);
563 return;
564 }
565
566 nlohmann::json& json = aResp->res.jsonValue;
567
568 for (const auto& [dbusPropName, variantVal] : properties)
569 {
570 if (dbusPropName == "AppliedConfig")
571 {
572 const sdbusplus::message::object_path* dbusPathWrapper =
573 std::get_if<sdbusplus::message::object_path>(
574 &variantVal);
575 if (dbusPathWrapper == nullptr)
576 {
577 continue;
578 }
579
580 const std::string& dbusPath = dbusPathWrapper->str;
581 std::string uri = "/redfish/v1/Systems/system/Processors/" +
582 cpuId + "/OperatingConfigs";
583 json["OperatingConfigs"] = {{"@odata.id", uri}};
584
585 // Reuse the D-Bus config object name for the Redfish
586 // URI
587 size_t baseNamePos = dbusPath.rfind('/');
588 if (baseNamePos == std::string::npos ||
589 baseNamePos == (dbusPath.size() - 1))
590 {
591 // If the AppliedConfig was somehow not a valid path,
592 // skip adding any more properties, since everything
593 // else is tied to this applied config.
594 messages::internalError(aResp->res);
595 break;
596 }
597 uri += '/';
598 uri += dbusPath.substr(baseNamePos + 1);
599 json["AppliedOperatingConfig"] = {{"@odata.id", uri}};
600
601 // Once we found the current applied config, queue another
602 // request to read the base freq core ids out of that
603 // config.
604 crow::connections::systemBus->async_method_call(
605 [aResp](
606 const boost::system::error_code ec,
607 const std::variant<
608 BaseSpeedPrioritySettingsProperty>& property) {
609 if (ec)
610 {
611 BMCWEB_LOG_WARNING
612 << "D-Bus Property Get error: " << ec;
613 messages::internalError(aResp->res);
614 return;
615 }
616 auto baseSpeedList =
617 std::get_if<BaseSpeedPrioritySettingsProperty>(
618 &property);
619 if (baseSpeedList != nullptr)
620 {
621 highSpeedCoreIdsHandler(aResp, *baseSpeedList);
622 }
623 },
624 service, dbusPath, "org.freedesktop.DBus.Properties",
625 "Get",
George Liu0fda0f12021-11-16 10:06:17 +0800626 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig",
Jonathan Domandba0c292020-12-02 15:34:13 -0800627 "BaseSpeedPrioritySettings");
628 }
629 else if (dbusPropName == "BaseSpeedPriorityEnabled")
630 {
631 const bool* state = std::get_if<bool>(&variantVal);
632 if (state != nullptr)
633 {
634 json["BaseSpeedPriorityState"] =
635 *state ? "Enabled" : "Disabled";
636 }
637 }
638 }
639 },
640 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
641 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
642}
643
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600644/**
645 * @brief Fill out location info of a processor by
646 * requesting data from the given D-Bus object.
647 *
648 * @param[in,out] aResp Async HTTP response.
649 * @param[in] service D-Bus service to query.
650 * @param[in] objPath D-Bus object to query.
651 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800652inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600653 const std::string& service,
654 const std::string& objPath)
655{
656 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
657 crow::connections::systemBus->async_method_call(
658 [objPath,
659 aResp{std::move(aResp)}](const boost::system::error_code ec,
660 const std::variant<std::string>& property) {
661 if (ec)
662 {
663 BMCWEB_LOG_DEBUG << "DBUS response error";
664 messages::internalError(aResp->res);
665 return;
666 }
667
668 const std::string* value = std::get_if<std::string>(&property);
669
670 if (value == nullptr)
671 {
672 // illegal value
673 BMCWEB_LOG_DEBUG << "Location code value error";
674 messages::internalError(aResp->res);
675 return;
676 }
677
678 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
679 *value;
680 },
681 service, objPath, "org.freedesktop.DBus.Properties", "Get",
682 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode");
683}
684
Jonathan Domanc9514482021-02-24 09:20:51 -0800685/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800686 * Populate the unique identifier in a Processor resource by requesting data
687 * from the given D-Bus object.
688 *
689 * @param[in,out] aResp Async HTTP response.
690 * @param[in] service D-Bus service to query.
691 * @param[in] objPath D-Bus object to query.
692 */
693inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
694 const std::string& service,
695 const std::string& objectPath)
696{
697 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
698 crow::connections::systemBus->async_method_call(
699 [aResp](boost::system::error_code ec,
700 const std::variant<std::string>& property) {
701 const std::string* id = std::get_if<std::string>(&property);
702 if (ec || id == nullptr)
703 {
704 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
705 messages::internalError(aResp->res);
706 return;
707 }
708 aResp->res
709 .jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] =
710 *id;
711 },
712 service, objectPath, "org.freedesktop.DBus.Properties", "Get",
713 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
714 "UniqueIdentifier");
715}
716
717/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800718 * Find the D-Bus object representing the requested Processor, and call the
719 * handler with the results. If matching object is not found, add 404 error to
720 * response and don't call the handler.
721 *
722 * @param[in,out] resp Async HTTP response.
723 * @param[in] processorId Redfish Processor Id.
724 * @param[in] handler Callback to continue processing request upon
725 * successfully finding object.
726 */
727template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800728inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800729 const std::string& processorId,
730 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500731{
732 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
733
Jonathan Domanc9514482021-02-24 09:20:51 -0800734 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500735 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800736 [resp, processorId, handler = std::forward<Handler>(handler)](
737 boost::system::error_code ec,
738 const MapperGetSubTreeResponse& subtree) mutable {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500739 if (ec)
740 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800741 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
742 messages::internalError(resp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500743 return;
744 }
Jonathan Doman2bab9832020-12-02 15:27:40 -0800745 for (const auto& [objectPath, serviceMap] : subtree)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500746 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800747 // Ignore any objects which don't end with our desired cpu name
748 if (!boost::ends_with(objectPath, processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500749 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800750 continue;
751 }
752
Jonathan Domanc9514482021-02-24 09:20:51 -0800753 bool found = false;
754 // Filter out objects that don't have the CPU-specific
755 // interfaces to make sure we can return 404 on non-CPUs
756 // (e.g. /redfish/../Processors/dimm0)
Jonathan Doman2bab9832020-12-02 15:27:40 -0800757 for (const auto& [serviceName, interfaceList] : serviceMap)
758 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800759 if (std::find_first_of(
760 interfaceList.begin(), interfaceList.end(),
761 processorInterfaces.begin(),
762 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500763 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800764 found = true;
765 break;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500766 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500767 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800768
769 if (!found)
770 {
771 continue;
772 }
773
774 // Process the first object which does match our cpu name and
775 // required interfaces, and potentially ignore any other
776 // matching objects. Assume all interfaces we want to process
777 // must be on the same object path.
778
779 handler(resp, processorId, objectPath, serviceMap);
Jonathan Doman2bab9832020-12-02 15:27:40 -0800780 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500781 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800782 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500783 },
784 "xyz.openbmc_project.ObjectMapper",
785 "/xyz/openbmc_project/object_mapper",
786 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800787 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800788 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530789 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800790 "xyz.openbmc_project.Inventory.Decorator.Asset",
791 "xyz.openbmc_project.Inventory.Decorator.Revision",
792 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600793 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800794 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800795 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
796 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500797}
798
zhanghch058d1b46d2021-04-01 11:18:24 +0800799inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800800 const std::string& processorId,
801 const std::string& objectPath,
802 const MapperServiceMap& serviceMap)
803{
804 for (const auto& [serviceName, interfaceList] : serviceMap)
805 {
806 for (const auto& interface : interfaceList)
807 {
808 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
809 {
810 getCpuAssetData(aResp, serviceName, objectPath);
811 }
George Liu0fda0f12021-11-16 10:06:17 +0800812 else if (interface ==
813 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800814 {
815 getCpuRevisionData(aResp, serviceName, objectPath);
816 }
817 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
818 {
819 getCpuDataByService(aResp, processorId, serviceName,
820 objectPath);
821 }
George Liu0fda0f12021-11-16 10:06:17 +0800822 else if (interface ==
823 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800824 {
825 getAcceleratorDataByService(aResp, processorId, serviceName,
826 objectPath);
827 }
George Liu0fda0f12021-11-16 10:06:17 +0800828 else if (
829 interface ==
830 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800831 {
832 getCpuConfigData(aResp, processorId, serviceName, objectPath);
833 }
George Liu0fda0f12021-11-16 10:06:17 +0800834 else if (interface ==
835 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800836 {
837 getCpuLocationCode(aResp, serviceName, objectPath);
838 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530839 else if (interface == "xyz.openbmc_project.Common.UUID")
840 {
841 getProcessorUUID(aResp, serviceName, objectPath);
842 }
George Liu0fda0f12021-11-16 10:06:17 +0800843 else if (interface ==
844 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800845 {
846 getCpuUniqueId(aResp, serviceName, objectPath);
847 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800848 }
849 }
850}
851
Jonathan Domandba0c292020-12-02 15:34:13 -0800852/**
853 * Request all the properties for the given D-Bus object and fill out the
854 * related entries in the Redfish OperatingConfig response.
855 *
856 * @param[in,out] aResp Async HTTP response.
857 * @param[in] service D-Bus service name to query.
858 * @param[in] objPath D-Bus object to query.
859 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800860inline void
861 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
862 const std::string& service,
863 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800864{
865 crow::connections::systemBus->async_method_call(
866 [aResp](boost::system::error_code ec,
867 const OperatingConfigProperties& properties) {
868 if (ec)
869 {
870 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
871 << ec.message();
872 messages::internalError(aResp->res);
873 return;
874 }
875
876 nlohmann::json& json = aResp->res.jsonValue;
877 for (const auto& [key, variant] : properties)
878 {
879 if (key == "AvailableCoreCount")
880 {
881 const size_t* cores = std::get_if<size_t>(&variant);
882 if (cores != nullptr)
883 {
884 json["TotalAvailableCoreCount"] = *cores;
885 }
886 }
887 else if (key == "BaseSpeed")
888 {
889 const uint32_t* speed = std::get_if<uint32_t>(&variant);
890 if (speed != nullptr)
891 {
892 json["BaseSpeedMHz"] = *speed;
893 }
894 }
895 else if (key == "MaxJunctionTemperature")
896 {
897 const uint32_t* temp = std::get_if<uint32_t>(&variant);
898 if (temp != nullptr)
899 {
900 json["MaxJunctionTemperatureCelsius"] = *temp;
901 }
902 }
903 else if (key == "MaxSpeed")
904 {
905 const uint32_t* speed = std::get_if<uint32_t>(&variant);
906 if (speed != nullptr)
907 {
908 json["MaxSpeedMHz"] = *speed;
909 }
910 }
911 else if (key == "PowerLimit")
912 {
913 const uint32_t* tdp = std::get_if<uint32_t>(&variant);
914 if (tdp != nullptr)
915 {
916 json["TDPWatts"] = *tdp;
917 }
918 }
919 else if (key == "TurboProfile")
920 {
921 const auto* turboList =
922 std::get_if<TurboProfileProperty>(&variant);
923 if (turboList == nullptr)
924 {
925 continue;
926 }
927
928 nlohmann::json& turboArray = json["TurboProfile"];
929 turboArray = nlohmann::json::array();
930 for (const auto& [turboSpeed, coreCount] : *turboList)
931 {
932 turboArray.push_back({{"ActiveCoreCount", coreCount},
933 {"MaxSpeedMHz", turboSpeed}});
934 }
935 }
936 else if (key == "BaseSpeedPrioritySettings")
937 {
938 const auto* baseSpeedList =
939 std::get_if<BaseSpeedPrioritySettingsProperty>(
940 &variant);
941 if (baseSpeedList == nullptr)
942 {
943 continue;
944 }
945
946 nlohmann::json& baseSpeedArray =
947 json["BaseSpeedPrioritySettings"];
948 baseSpeedArray = nlohmann::json::array();
949 for (const auto& [baseSpeed, coreList] : *baseSpeedList)
950 {
951 baseSpeedArray.push_back(
952 {{"CoreCount", coreList.size()},
953 {"CoreIDs", coreList},
954 {"BaseSpeedMHz", baseSpeed}});
955 }
956 }
957 }
958 },
959 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
960 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig");
961}
962
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800963/**
964 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
965 * property. Main task is to translate error messages into Redfish errors.
966 *
967 * @param[in,out] resp HTTP response.
968 * @param[in] setPropVal Value which we attempted to set.
969 * @param[in] ec D-Bus response error code.
970 * @param[in] msg D-Bus response message.
971 */
972inline void
973 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
974 const std::string& setPropVal,
975 boost::system::error_code ec,
976 const sdbusplus::message::message& msg)
977{
978 if (!ec)
979 {
980 BMCWEB_LOG_DEBUG << "Set Property succeeded";
981 return;
982 }
983
984 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
985
986 const sd_bus_error* dbusError = msg.get_error();
987 if (dbusError == nullptr)
988 {
989 messages::internalError(resp->res);
990 return;
991 }
992
993 // The asio error code doesn't know about our custom errors, so we have to
994 // parse the error string. Some of these D-Bus -> Redfish translations are a
995 // stretch, but it's good to try to communicate something vaguely useful.
996 if (strcmp(dbusError->name,
997 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
998 {
999 // Service did not like the object_path we tried to set.
1000 messages::propertyValueIncorrect(
1001 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
1002 }
1003 else if (strcmp(dbusError->name,
1004 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
1005 {
1006 // Service indicates we can never change the config for this processor.
1007 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
1008 }
1009 else if (strcmp(dbusError->name,
1010 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
1011 {
1012 // Service indicates the config cannot be changed right now, but maybe
1013 // in a different system state.
1014 messages::resourceInStandby(resp->res);
1015 }
1016 else if (strcmp(dbusError->name,
1017 "xyz.openbmc_project.Common.Device.Error.WriteFailure") ==
1018 0)
1019 {
1020 // Service tried to change the config, but it failed.
1021 messages::operationFailed(resp->res);
1022 }
1023 else
1024 {
1025 messages::internalError(resp->res);
1026 }
1027}
1028
1029/**
1030 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
1031 * validation of the input data, and then set the D-Bus property.
1032 *
1033 * @param[in,out] resp Async HTTP response.
1034 * @param[in] processorId Processor's Id.
1035 * @param[in] appliedConfigUri New property value to apply.
1036 * @param[in] cpuObjectPath Path of CPU object to modify.
1037 * @param[in] serviceMap Service map for CPU object.
1038 */
1039inline void patchAppliedOperatingConfig(
1040 const std::shared_ptr<bmcweb::AsyncResp>& resp,
1041 const std::string& processorId, const std::string& appliedConfigUri,
1042 const std::string& cpuObjectPath, const MapperServiceMap& serviceMap)
1043{
1044 // Check that the property even exists by checking for the interface
1045 const std::string* controlService = nullptr;
1046 for (const auto& [serviceName, interfaceList] : serviceMap)
1047 {
1048 if (std::find(interfaceList.begin(), interfaceList.end(),
1049 "xyz.openbmc_project.Control.Processor."
1050 "CurrentOperatingConfig") != interfaceList.end())
1051 {
1052 controlService = &serviceName;
1053 break;
1054 }
1055 }
1056
1057 if (controlService == nullptr)
1058 {
1059 messages::internalError(resp->res);
1060 return;
1061 }
1062
1063 // Check that the config URI is a child of the cpu URI being patched.
1064 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
1065 expectedPrefix += processorId;
1066 expectedPrefix += "/OperatingConfigs/";
1067 if (!boost::starts_with(appliedConfigUri, expectedPrefix) ||
1068 expectedPrefix.size() == appliedConfigUri.size())
1069 {
1070 messages::propertyValueIncorrect(
1071 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1072 return;
1073 }
1074
1075 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1076 // direct child of the CPU object.
1077 // Strip the expectedPrefix from the config URI to get the "filename", and
1078 // append to the CPU's path.
1079 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1080 sdbusplus::message::object_path configPath(cpuObjectPath);
1081 configPath /= configBaseName;
1082
1083 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1084
1085 // Set the property, with handler to check error responses
1086 crow::connections::systemBus->async_method_call(
1087 [resp, appliedConfigUri](boost::system::error_code ec,
1088 sdbusplus::message::message& msg) {
1089 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
1090 },
1091 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1092 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
1093 "AppliedConfig",
1094 std::variant<sdbusplus::message::object_path>(std::move(configPath)));
1095}
1096
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001097inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001098{
Jonathan Domandba0c292020-12-02 15:34:13 -08001099
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001100 BMCWEB_ROUTE(
1101 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001102 .privileges(redfish::privileges::getOperatingConfigCollection)
George Liu0fda0f12021-11-16 10:06:17 +08001103 .methods(
1104 boost::beast::http::verb::get)([](const crow::Request& req,
1105 const std::shared_ptr<
1106 bmcweb::AsyncResp>& asyncResp,
1107 const std::string& cpuName) {
1108 asyncResp->res.jsonValue["@odata.type"] =
1109 "#OperatingConfigCollection.OperatingConfigCollection";
1110 asyncResp->res.jsonValue["@odata.id"] = req.url;
1111 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
Jonathan Domandba0c292020-12-02 15:34:13 -08001112
George Liu0fda0f12021-11-16 10:06:17 +08001113 // First find the matching CPU object so we know how to
1114 // constrain our search for related Config objects.
1115 crow::connections::systemBus->async_method_call(
1116 [asyncResp, cpuName](const boost::system::error_code ec,
1117 const std::vector<std::string>& objects) {
1118 if (ec)
1119 {
1120 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1121 << ec.message();
1122 messages::internalError(asyncResp->res);
1123 return;
1124 }
1125
1126 for (const std::string& object : objects)
1127 {
1128 if (!boost::ends_with(object, cpuName))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001129 {
George Liu0fda0f12021-11-16 10:06:17 +08001130 continue;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001131 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001132
George Liu0fda0f12021-11-16 10:06:17 +08001133 // Not expected that there will be multiple matching
1134 // CPU objects, but if there are just use the first
1135 // one.
Jonathan Domandba0c292020-12-02 15:34:13 -08001136
George Liu0fda0f12021-11-16 10:06:17 +08001137 // Use the common search routine to construct the
1138 // Collection of all Config objects under this CPU.
1139 collection_util::getCollectionMembers(
1140 asyncResp,
1141 "/redfish/v1/Systems/system/Processors/" + cpuName +
1142 "/OperatingConfigs",
1143 {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1144 object.c_str());
1145 return;
1146 }
1147 },
1148 "xyz.openbmc_project.ObjectMapper",
1149 "/xyz/openbmc_project/object_mapper",
1150 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1151 "/xyz/openbmc_project/inventory", 0,
1152 std::array<const char*, 1>{
1153 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
1154 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001155}
1156
1157inline void requestRoutesOperatingConfig(App& app)
1158{
1159 BMCWEB_ROUTE(
1160 app,
1161 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001162 .privileges(redfish::privileges::getOperatingConfig)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001163 .methods(
1164 boost::beast::http::verb::get)([](const crow::Request& req,
1165 const std::shared_ptr<
1166 bmcweb::AsyncResp>& asyncResp,
1167 const std::string& cpuName,
1168 const std::string& configName) {
1169 // Ask for all objects implementing OperatingConfig so we can search
1170 // for one with a matching name
1171 crow::connections::systemBus->async_method_call(
1172 [asyncResp, cpuName, configName,
1173 reqUrl{req.url}](boost::system::error_code ec,
1174 const MapperGetSubTreeResponse& subtree) {
1175 if (ec)
Jonathan Domandba0c292020-12-02 15:34:13 -08001176 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001177 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1178 << ec.message();
1179 messages::internalError(asyncResp->res);
1180 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001181 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001182 const std::string expectedEnding =
1183 cpuName + '/' + configName;
1184 for (const auto& [objectPath, serviceMap] : subtree)
Jonathan Domandba0c292020-12-02 15:34:13 -08001185 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001186 // Ignore any configs without matching cpuX/configY
1187 if (!boost::ends_with(objectPath, expectedEnding) ||
1188 serviceMap.empty())
1189 {
1190 continue;
1191 }
1192
1193 nlohmann::json& json = asyncResp->res.jsonValue;
1194 json["@odata.type"] =
1195 "#OperatingConfig.v1_0_0.OperatingConfig";
1196 json["@odata.id"] = reqUrl;
1197 json["Name"] = "Processor Profile";
1198 json["Id"] = configName;
1199
1200 // Just use the first implementation of the object - not
1201 // expected that there would be multiple matching
1202 // services
1203 getOperatingConfigData(
1204 asyncResp, serviceMap.begin()->first, objectPath);
1205 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001206 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001207 messages::resourceNotFound(asyncResp->res,
1208 "OperatingConfig", configName);
1209 },
1210 "xyz.openbmc_project.ObjectMapper",
1211 "/xyz/openbmc_project/object_mapper",
1212 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1213 "/xyz/openbmc_project/inventory", 0,
1214 std::array<const char*, 1>{
1215 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
1216 });
1217}
Jonathan Domandba0c292020-12-02 15:34:13 -08001218
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001220{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001221 /**
1222 * Functions triggers appropriate requests on DBus
1223 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001224 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001225 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001226 .methods(boost::beast::http::verb::get)(
1227 [](const crow::Request&,
1228 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1229 asyncResp->res.jsonValue["@odata.type"] =
1230 "#ProcessorCollection.ProcessorCollection";
1231 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001232
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001233 asyncResp->res.jsonValue["@odata.id"] =
1234 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001235
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001236 collection_util::getCollectionMembers(
1237 asyncResp, "/redfish/v1/Systems/system/Processors",
1238 std::vector<const char*>(processorInterfaces.begin(),
1239 processorInterfaces.end()));
1240 });
1241}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001242
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001243inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001244{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001245 /**
1246 * Functions triggers appropriate requests on DBus
1247 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001248
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001249 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001250 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001251 .methods(boost::beast::http::verb::get)(
1252 [](const crow::Request&,
1253 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1254 const std::string& processorId) {
1255 asyncResp->res.jsonValue["@odata.type"] =
1256 "#Processor.v1_11_0.Processor";
1257 asyncResp->res.jsonValue["@odata.id"] =
1258 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001259
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001260 getProcessorObject(asyncResp, processorId, getProcessorData);
1261 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001262
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001263 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001264 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001265 .methods(boost::beast::http::verb::patch)(
1266 [](const crow::Request& req,
1267 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1268 const std::string& processorId) {
1269 std::optional<nlohmann::json> appliedConfigJson;
1270 if (!json_util::readJson(req, asyncResp->res,
1271 "AppliedOperatingConfig",
1272 appliedConfigJson))
1273 {
1274 return;
1275 }
1276
1277 std::string appliedConfigUri;
1278 if (appliedConfigJson)
1279 {
1280 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1281 "@odata.id", appliedConfigUri))
1282 {
1283 return;
1284 }
1285 // Check for 404 and find matching D-Bus object, then run
1286 // property patch handlers if that all succeeds.
1287 getProcessorObject(
1288 asyncResp, processorId,
1289 [appliedConfigUri = std::move(appliedConfigUri)](
1290 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1291 const std::string& processorId,
1292 const std::string& objectPath,
1293 const MapperServiceMap& serviceMap) {
1294 patchAppliedOperatingConfig(asyncResp, processorId,
1295 appliedConfigUri,
1296 objectPath, serviceMap);
1297 });
1298 }
1299 });
1300}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001301
1302} // namespace redfish