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