blob: bd1870711cf166d4639b15b9f991d02aad9f0e50 [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 Domanc9514482021-02-24 09:20:51 -080034// Map of service name to list of interfaces
35using MapperServiceMap =
36 std::vector<std::pair<std::string, std::vector<std::string>>>;
37
38// Map of object paths to MapperServiceMaps
39using MapperGetSubTreeResponse =
40 std::vector<std::pair<std::string, MapperServiceMap>>;
41
42// Interfaces which imply a D-Bus object represents a Processor
43constexpr std::array<const char*, 2> processorInterfaces = {
44 "xyz.openbmc_project.Inventory.Item.Cpu",
45 "xyz.openbmc_project.Inventory.Item.Accelerator"};
Jonathan Doman2bab9832020-12-02 15:27:40 -080046
Gunnar Millsac6a4442020-10-14 14:55:29 -050047inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080048 getCpuDataByInterface(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -050049 const InterfacesProperties& cpuInterfacesProperties)
50{
51 BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
52
Chicago Duana1649ec2021-03-30 16:54:58 +080053 // Set the default value of state
54 aResp->res.jsonValue["Status"]["State"] = "Enabled";
55 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -050056
57 for (const auto& interface : cpuInterfacesProperties)
58 {
59 for (const auto& property : interface.second)
60 {
Chicago Duana1649ec2021-03-30 16:54:58 +080061 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -050062 {
Chicago Duana1649ec2021-03-30 16:54:58 +080063 const bool* cpuPresent = std::get_if<bool>(&property.second);
64 if (cpuPresent == nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -050065 {
66 // Important property not in desired type
67 messages::internalError(aResp->res);
68 return;
69 }
Chicago Duana1649ec2021-03-30 16:54:58 +080070 if (*cpuPresent == false)
Gunnar Millsac6a4442020-10-14 14:55:29 -050071 {
Chicago Duana1649ec2021-03-30 16:54:58 +080072 // Slot is not populated
Gunnar Millsac6a4442020-10-14 14:55:29 -050073 aResp->res.jsonValue["Status"]["State"] = "Absent";
Chicago Duana1649ec2021-03-30 16:54:58 +080074 }
75 }
76 else if (property.first == "Functional")
77 {
78 const bool* cpuFunctional = std::get_if<bool>(&property.second);
79 if (cpuFunctional == nullptr)
80 {
81 messages::internalError(aResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -050082 return;
83 }
Chicago Duana1649ec2021-03-30 16:54:58 +080084 if (*cpuFunctional == false)
85 {
86 aResp->res.jsonValue["Status"]["Health"] = "Critical";
87 }
88 }
89 else if (property.first == "CoreCount")
90 {
91 const uint16_t* coresCount =
92 std::get_if<uint16_t>(&property.second);
93 if (coresCount == nullptr)
94 {
95 messages::internalError(aResp->res);
96 return;
97 }
Gunnar Millsac6a4442020-10-14 14:55:29 -050098 aResp->res.jsonValue["TotalCores"] = *coresCount;
99 }
Jonathan Domandc3fa662020-10-26 23:10:24 -0700100 else if (property.first == "MaxSpeedInMhz")
101 {
102 const uint32_t* value = std::get_if<uint32_t>(&property.second);
103 if (value != nullptr)
104 {
105 aResp->res.jsonValue["MaxSpeedMHz"] = *value;
106 }
107 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500108 else if (property.first == "Socket")
109 {
110 const std::string* value =
111 std::get_if<std::string>(&property.second);
112 if (value != nullptr)
113 {
114 aResp->res.jsonValue["Socket"] = *value;
115 }
116 }
117 else if (property.first == "ThreadCount")
118 {
Jonathan Domandc3fa662020-10-26 23:10:24 -0700119 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500120 if (value != nullptr)
121 {
122 aResp->res.jsonValue["TotalThreads"] = *value;
123 }
124 }
125 else if (property.first == "Family")
126 {
127 const std::string* value =
128 std::get_if<std::string>(&property.second);
129 if (value != nullptr)
130 {
131 aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
132 *value;
133 }
134 }
135 else if (property.first == "Id")
136 {
137 const uint64_t* value = std::get_if<uint64_t>(&property.second);
138 if (value != nullptr && *value != 0)
139 {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500140 aResp->res
141 .jsonValue["ProcessorId"]["IdentificationRegisters"] =
142 boost::lexical_cast<std::string>(*value);
143 }
144 }
145 }
146 }
147
Gunnar Millsac6a4442020-10-14 14:55:29 -0500148 return;
149}
150
zhanghch058d1b46d2021-04-01 11:18:24 +0800151inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500152 const std::string& cpuId,
153 const std::string& service,
154 const std::string& objPath)
155{
156 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
157
158 crow::connections::systemBus->async_method_call(
159 [cpuId, service, objPath, aResp{std::move(aResp)}](
160 const boost::system::error_code ec,
161 const dbus::utility::ManagedObjectType& dbusData) {
162 if (ec)
163 {
164 BMCWEB_LOG_DEBUG << "DBUS response error";
165 messages::internalError(aResp->res);
166 return;
167 }
168 aResp->res.jsonValue["Id"] = cpuId;
169 aResp->res.jsonValue["Name"] = "Processor";
170 aResp->res.jsonValue["ProcessorType"] = "CPU";
171
172 bool slotPresent = false;
173 std::string corePath = objPath + "/core";
174 size_t totalCores = 0;
175 for (const auto& object : dbusData)
176 {
177 if (object.first.str == objPath)
178 {
179 getCpuDataByInterface(aResp, object.second);
180 }
181 else if (boost::starts_with(object.first.str, corePath))
182 {
183 for (const auto& interface : object.second)
184 {
185 if (interface.first ==
186 "xyz.openbmc_project.Inventory.Item")
187 {
188 for (const auto& property : interface.second)
189 {
190 if (property.first == "Present")
191 {
192 const bool* present =
193 std::get_if<bool>(&property.second);
194 if (present != nullptr)
195 {
196 if (*present == true)
197 {
198 slotPresent = true;
199 totalCores++;
200 }
201 }
202 }
203 }
204 }
205 }
206 }
207 }
208 // In getCpuDataByInterface(), state and health are set
209 // based on the present and functional status. If core
210 // count is zero, then it has a higher precedence.
211 if (slotPresent)
212 {
213 if (totalCores == 0)
214 {
215 // Slot is not populated, set status end return
216 aResp->res.jsonValue["Status"]["State"] = "Absent";
217 aResp->res.jsonValue["Status"]["Health"] = "OK";
218 }
219 aResp->res.jsonValue["TotalCores"] = totalCores;
220 }
221 return;
222 },
223 service, "/xyz/openbmc_project/inventory",
224 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
225}
226
zhanghch058d1b46d2021-04-01 11:18:24 +0800227inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500228 const std::string& service,
229 const std::string& objPath)
230{
231 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
232 crow::connections::systemBus->async_method_call(
233 [objPath, aResp{std::move(aResp)}](
234 const boost::system::error_code ec,
235 const boost::container::flat_map<
236 std::string, std::variant<std::string, uint32_t, uint16_t,
237 bool>>& properties) {
238 if (ec)
239 {
240 BMCWEB_LOG_DEBUG << "DBUS response error";
241 messages::internalError(aResp->res);
242 return;
243 }
244
245 for (const auto& property : properties)
246 {
247 if (property.first == "SerialNumber")
248 {
249 const std::string* sn =
250 std::get_if<std::string>(&property.second);
251 if (sn != nullptr && !sn->empty())
252 {
253 aResp->res.jsonValue["SerialNumber"] = *sn;
254 }
255 }
256 else if (property.first == "Model")
257 {
258 const std::string* model =
259 std::get_if<std::string>(&property.second);
260 if (model != nullptr && !model->empty())
261 {
262 aResp->res.jsonValue["Model"] = *model;
263 }
264 }
265 else if (property.first == "Manufacturer")
266 {
267
268 const std::string* mfg =
269 std::get_if<std::string>(&property.second);
270 if (mfg != nullptr)
271 {
272 aResp->res.jsonValue["Manufacturer"] = *mfg;
273
274 // Otherwise would be unexpected.
275 if (mfg->find("Intel") != std::string::npos)
276 {
277 aResp->res.jsonValue["ProcessorArchitecture"] =
278 "x86";
279 aResp->res.jsonValue["InstructionSet"] = "x86-64";
280 }
281 else if (mfg->find("IBM") != std::string::npos)
282 {
283 aResp->res.jsonValue["ProcessorArchitecture"] =
284 "Power";
285 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
286 }
287 }
288 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600289 else if (property.first == "PartNumber")
290 {
291 const std::string* partNumber =
292 std::get_if<std::string>(&property.second);
293
294 if (partNumber == nullptr)
295 {
296 messages::internalError(aResp->res);
297 return;
298 }
299 aResp->res.jsonValue["PartNumber"] = *partNumber;
300 }
301 else if (property.first == "SparePartNumber")
302 {
303 const std::string* sparePartNumber =
304 std::get_if<std::string>(&property.second);
305
306 if (sparePartNumber == nullptr)
307 {
308 messages::internalError(aResp->res);
309 return;
310 }
311 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
312 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500313 }
314 },
315 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
316 "xyz.openbmc_project.Inventory.Decorator.Asset");
317}
318
zhanghch058d1b46d2021-04-01 11:18:24 +0800319inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500320 const std::string& service,
321 const std::string& objPath)
322{
323 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
324 crow::connections::systemBus->async_method_call(
325 [objPath, aResp{std::move(aResp)}](
326 const boost::system::error_code ec,
327 const boost::container::flat_map<
328 std::string, std::variant<std::string, uint32_t, uint16_t,
329 bool>>& properties) {
330 if (ec)
331 {
332 BMCWEB_LOG_DEBUG << "DBUS response error";
333 messages::internalError(aResp->res);
334 return;
335 }
336
337 for (const auto& property : properties)
338 {
339 if (property.first == "Version")
340 {
341 const std::string* ver =
342 std::get_if<std::string>(&property.second);
343 if (ver != nullptr)
344 {
345 aResp->res.jsonValue["Version"] = *ver;
346 }
347 break;
348 }
349 }
350 },
351 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
352 "xyz.openbmc_project.Inventory.Decorator.Revision");
353}
354
zhanghch058d1b46d2021-04-01 11:18:24 +0800355inline void getAcceleratorDataByService(
356 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
357 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500358{
359 BMCWEB_LOG_DEBUG
360 << "Get available system Accelerator resources by service.";
361 crow::connections::systemBus->async_method_call(
362 [acclrtrId, aResp{std::move(aResp)}](
363 const boost::system::error_code ec,
364 const boost::container::flat_map<
365 std::string, std::variant<std::string, uint32_t, uint16_t,
366 bool>>& properties) {
367 if (ec)
368 {
369 BMCWEB_LOG_DEBUG << "DBUS response error";
370 messages::internalError(aResp->res);
371 return;
372 }
373 aResp->res.jsonValue["Id"] = acclrtrId;
374 aResp->res.jsonValue["Name"] = "Processor";
375 const bool* accPresent = nullptr;
376 const bool* accFunctional = nullptr;
377
378 for (const auto& property : properties)
379 {
380 if (property.first == "Functional")
381 {
382 accFunctional = std::get_if<bool>(&property.second);
383 }
384 else if (property.first == "Present")
385 {
386 accPresent = std::get_if<bool>(&property.second);
387 }
388 }
389
390 std::string state = "Enabled";
391 std::string health = "OK";
392
393 if (accPresent != nullptr && *accPresent == false)
394 {
395 state = "Absent";
396 }
397
398 if ((accFunctional != nullptr) && (*accFunctional == false))
399 {
400 if (state == "Enabled")
401 {
402 health = "Critical";
403 }
404 }
405
406 aResp->res.jsonValue["Status"]["State"] = state;
407 aResp->res.jsonValue["Status"]["Health"] = health;
408 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
409 },
410 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
411}
412
Jonathan Domandba0c292020-12-02 15:34:13 -0800413// OperatingConfig D-Bus Types
414using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
415using BaseSpeedPrioritySettingsProperty =
416 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
417// uint32_t and size_t may or may not be the same type, requiring a dedup'd
418// variant
419using OperatingConfigProperties = std::vector<std::pair<
420 std::string,
421 sdbusplus::utility::dedup_variant<uint32_t, size_t, TurboProfileProperty,
422 BaseSpeedPrioritySettingsProperty>>>;
423
424/**
425 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
426 * OperatingConfig D-Bus property.
427 *
428 * @param[in,out] aResp Async HTTP response.
429 * @param[in] baseSpeedSettings Full list of base speed priority groups,
430 * to use to determine the list of high
431 * speed cores.
432 */
433inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800434 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800435 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
436{
437 // The D-Bus property does not indicate which bucket is the "high
438 // priority" group, so let's discern that by looking for the one with
439 // highest base frequency.
440 auto highPriorityGroup = baseSpeedSettings.cend();
441 uint32_t highestBaseSpeed = 0;
442 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
443 ++it)
444 {
445 const uint32_t baseFreq = std::get<uint32_t>(*it);
446 if (baseFreq > highestBaseSpeed)
447 {
448 highestBaseSpeed = baseFreq;
449 highPriorityGroup = it;
450 }
451 }
452
453 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
454 jsonCoreIds = nlohmann::json::array();
455
456 // There may not be any entries in the D-Bus property, so only populate
457 // if there was actually something there.
458 if (highPriorityGroup != baseSpeedSettings.cend())
459 {
460 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
461 }
462}
463
464/**
465 * Fill out OperatingConfig related items in a Processor resource by requesting
466 * data from the given D-Bus object.
467 *
468 * @param[in,out] aResp Async HTTP response.
469 * @param[in] cpuId CPU D-Bus name.
470 * @param[in] service D-Bus service to query.
471 * @param[in] objPath D-Bus object to query.
472 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800473inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800474 const std::string& cpuId,
475 const std::string& service,
476 const std::string& objPath)
477{
478 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
479
480 // First, GetAll CurrentOperatingConfig properties on the object
481 crow::connections::systemBus->async_method_call(
482 [aResp, cpuId, service](
483 const boost::system::error_code ec,
484 const std::vector<
485 std::pair<std::string,
486 std::variant<sdbusplus::message::object_path, bool>>>&
487 properties) {
488 if (ec)
489 {
490 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
491 << ec.message();
492 messages::internalError(aResp->res);
493 return;
494 }
495
496 nlohmann::json& json = aResp->res.jsonValue;
497
498 for (const auto& [dbusPropName, variantVal] : properties)
499 {
500 if (dbusPropName == "AppliedConfig")
501 {
502 const sdbusplus::message::object_path* dbusPathWrapper =
503 std::get_if<sdbusplus::message::object_path>(
504 &variantVal);
505 if (dbusPathWrapper == nullptr)
506 {
507 continue;
508 }
509
510 const std::string& dbusPath = dbusPathWrapper->str;
511 std::string uri = "/redfish/v1/Systems/system/Processors/" +
512 cpuId + "/OperatingConfigs";
513 json["OperatingConfigs"] = {{"@odata.id", uri}};
514
515 // Reuse the D-Bus config object name for the Redfish
516 // URI
517 size_t baseNamePos = dbusPath.rfind('/');
518 if (baseNamePos == std::string::npos ||
519 baseNamePos == (dbusPath.size() - 1))
520 {
521 // If the AppliedConfig was somehow not a valid path,
522 // skip adding any more properties, since everything
523 // else is tied to this applied config.
524 messages::internalError(aResp->res);
525 break;
526 }
527 uri += '/';
528 uri += dbusPath.substr(baseNamePos + 1);
529 json["AppliedOperatingConfig"] = {{"@odata.id", uri}};
530
531 // Once we found the current applied config, queue another
532 // request to read the base freq core ids out of that
533 // config.
534 crow::connections::systemBus->async_method_call(
535 [aResp](
536 const boost::system::error_code ec,
537 const std::variant<
538 BaseSpeedPrioritySettingsProperty>& property) {
539 if (ec)
540 {
541 BMCWEB_LOG_WARNING
542 << "D-Bus Property Get error: " << ec;
543 messages::internalError(aResp->res);
544 return;
545 }
546 auto baseSpeedList =
547 std::get_if<BaseSpeedPrioritySettingsProperty>(
548 &property);
549 if (baseSpeedList != nullptr)
550 {
551 highSpeedCoreIdsHandler(aResp, *baseSpeedList);
552 }
553 },
554 service, dbusPath, "org.freedesktop.DBus.Properties",
555 "Get",
556 "xyz.openbmc_project.Inventory.Item.Cpu."
557 "OperatingConfig",
558 "BaseSpeedPrioritySettings");
559 }
560 else if (dbusPropName == "BaseSpeedPriorityEnabled")
561 {
562 const bool* state = std::get_if<bool>(&variantVal);
563 if (state != nullptr)
564 {
565 json["BaseSpeedPriorityState"] =
566 *state ? "Enabled" : "Disabled";
567 }
568 }
569 }
570 },
571 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
572 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
573}
574
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600575/**
576 * @brief Fill out location info of a processor by
577 * requesting data from the given D-Bus object.
578 *
579 * @param[in,out] aResp Async HTTP response.
580 * @param[in] service D-Bus service to query.
581 * @param[in] objPath D-Bus object to query.
582 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800583inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600584 const std::string& service,
585 const std::string& objPath)
586{
587 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
588 crow::connections::systemBus->async_method_call(
589 [objPath,
590 aResp{std::move(aResp)}](const boost::system::error_code ec,
591 const std::variant<std::string>& property) {
592 if (ec)
593 {
594 BMCWEB_LOG_DEBUG << "DBUS response error";
595 messages::internalError(aResp->res);
596 return;
597 }
598
599 const std::string* value = std::get_if<std::string>(&property);
600
601 if (value == nullptr)
602 {
603 // illegal value
604 BMCWEB_LOG_DEBUG << "Location code value error";
605 messages::internalError(aResp->res);
606 return;
607 }
608
609 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
610 *value;
611 },
612 service, objPath, "org.freedesktop.DBus.Properties", "Get",
613 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode");
614}
615
Jonathan Domanc9514482021-02-24 09:20:51 -0800616/**
617 * Find the D-Bus object representing the requested Processor, and call the
618 * handler with the results. If matching object is not found, add 404 error to
619 * response and don't call the handler.
620 *
621 * @param[in,out] resp Async HTTP response.
622 * @param[in] processorId Redfish Processor Id.
623 * @param[in] handler Callback to continue processing request upon
624 * successfully finding object.
625 */
626template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800627inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800628 const std::string& processorId,
629 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500630{
631 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
632
Jonathan Domanc9514482021-02-24 09:20:51 -0800633 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500634 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800635 [resp, processorId, handler = std::forward<Handler>(handler)](
636 boost::system::error_code ec,
637 const MapperGetSubTreeResponse& subtree) mutable {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500638 if (ec)
639 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800640 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
641 messages::internalError(resp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500642 return;
643 }
Jonathan Doman2bab9832020-12-02 15:27:40 -0800644 for (const auto& [objectPath, serviceMap] : subtree)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500645 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800646 // Ignore any objects which don't end with our desired cpu name
647 if (!boost::ends_with(objectPath, processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500648 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800649 continue;
650 }
651
Jonathan Domanc9514482021-02-24 09:20:51 -0800652 bool found = false;
653 // Filter out objects that don't have the CPU-specific
654 // interfaces to make sure we can return 404 on non-CPUs
655 // (e.g. /redfish/../Processors/dimm0)
Jonathan Doman2bab9832020-12-02 15:27:40 -0800656 for (const auto& [serviceName, interfaceList] : serviceMap)
657 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800658 if (std::find_first_of(
659 interfaceList.begin(), interfaceList.end(),
660 processorInterfaces.begin(),
661 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500662 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800663 found = true;
664 break;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500665 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500666 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800667
668 if (!found)
669 {
670 continue;
671 }
672
673 // Process the first object which does match our cpu name and
674 // required interfaces, and potentially ignore any other
675 // matching objects. Assume all interfaces we want to process
676 // must be on the same object path.
677
678 handler(resp, processorId, objectPath, serviceMap);
Jonathan Doman2bab9832020-12-02 15:27:40 -0800679 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500680 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800681 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500682 },
683 "xyz.openbmc_project.ObjectMapper",
684 "/xyz/openbmc_project/object_mapper",
685 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800686 "/xyz/openbmc_project/inventory", 0,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600687 std::array<const char*, 6>{
Jonathan Doman2bab9832020-12-02 15:27:40 -0800688 "xyz.openbmc_project.Inventory.Decorator.Asset",
689 "xyz.openbmc_project.Inventory.Decorator.Revision",
690 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600691 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800692 "xyz.openbmc_project.Inventory.Item.Accelerator",
693 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500694}
695
zhanghch058d1b46d2021-04-01 11:18:24 +0800696inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800697 const std::string& processorId,
698 const std::string& objectPath,
699 const MapperServiceMap& serviceMap)
700{
701 for (const auto& [serviceName, interfaceList] : serviceMap)
702 {
703 for (const auto& interface : interfaceList)
704 {
705 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
706 {
707 getCpuAssetData(aResp, serviceName, objectPath);
708 }
709 else if (interface == "xyz.openbmc_project.Inventory."
710 "Decorator.Revision")
711 {
712 getCpuRevisionData(aResp, serviceName, objectPath);
713 }
714 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
715 {
716 getCpuDataByService(aResp, processorId, serviceName,
717 objectPath);
718 }
719 else if (interface == "xyz.openbmc_project.Inventory."
720 "Item.Accelerator")
721 {
722 getAcceleratorDataByService(aResp, processorId, serviceName,
723 objectPath);
724 }
725 else if (interface == "xyz.openbmc_project.Control.Processor."
726 "CurrentOperatingConfig")
727 {
728 getCpuConfigData(aResp, processorId, serviceName, objectPath);
729 }
730 else if (interface == "xyz.openbmc_project.Inventory."
731 "Decorator.LocationCode")
732 {
733 getCpuLocationCode(aResp, serviceName, objectPath);
734 }
735 }
736 }
737}
738
Jonathan Domandba0c292020-12-02 15:34:13 -0800739/**
740 * Request all the properties for the given D-Bus object and fill out the
741 * related entries in the Redfish OperatingConfig response.
742 *
743 * @param[in,out] aResp Async HTTP response.
744 * @param[in] service D-Bus service name to query.
745 * @param[in] objPath D-Bus object to query.
746 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800747inline void
748 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
749 const std::string& service,
750 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800751{
752 crow::connections::systemBus->async_method_call(
753 [aResp](boost::system::error_code ec,
754 const OperatingConfigProperties& properties) {
755 if (ec)
756 {
757 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
758 << ec.message();
759 messages::internalError(aResp->res);
760 return;
761 }
762
763 nlohmann::json& json = aResp->res.jsonValue;
764 for (const auto& [key, variant] : properties)
765 {
766 if (key == "AvailableCoreCount")
767 {
768 const size_t* cores = std::get_if<size_t>(&variant);
769 if (cores != nullptr)
770 {
771 json["TotalAvailableCoreCount"] = *cores;
772 }
773 }
774 else if (key == "BaseSpeed")
775 {
776 const uint32_t* speed = std::get_if<uint32_t>(&variant);
777 if (speed != nullptr)
778 {
779 json["BaseSpeedMHz"] = *speed;
780 }
781 }
782 else if (key == "MaxJunctionTemperature")
783 {
784 const uint32_t* temp = std::get_if<uint32_t>(&variant);
785 if (temp != nullptr)
786 {
787 json["MaxJunctionTemperatureCelsius"] = *temp;
788 }
789 }
790 else if (key == "MaxSpeed")
791 {
792 const uint32_t* speed = std::get_if<uint32_t>(&variant);
793 if (speed != nullptr)
794 {
795 json["MaxSpeedMHz"] = *speed;
796 }
797 }
798 else if (key == "PowerLimit")
799 {
800 const uint32_t* tdp = std::get_if<uint32_t>(&variant);
801 if (tdp != nullptr)
802 {
803 json["TDPWatts"] = *tdp;
804 }
805 }
806 else if (key == "TurboProfile")
807 {
808 const auto* turboList =
809 std::get_if<TurboProfileProperty>(&variant);
810 if (turboList == nullptr)
811 {
812 continue;
813 }
814
815 nlohmann::json& turboArray = json["TurboProfile"];
816 turboArray = nlohmann::json::array();
817 for (const auto& [turboSpeed, coreCount] : *turboList)
818 {
819 turboArray.push_back({{"ActiveCoreCount", coreCount},
820 {"MaxSpeedMHz", turboSpeed}});
821 }
822 }
823 else if (key == "BaseSpeedPrioritySettings")
824 {
825 const auto* baseSpeedList =
826 std::get_if<BaseSpeedPrioritySettingsProperty>(
827 &variant);
828 if (baseSpeedList == nullptr)
829 {
830 continue;
831 }
832
833 nlohmann::json& baseSpeedArray =
834 json["BaseSpeedPrioritySettings"];
835 baseSpeedArray = nlohmann::json::array();
836 for (const auto& [baseSpeed, coreList] : *baseSpeedList)
837 {
838 baseSpeedArray.push_back(
839 {{"CoreCount", coreList.size()},
840 {"CoreIDs", coreList},
841 {"BaseSpeedMHz", baseSpeed}});
842 }
843 }
844 }
845 },
846 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
847 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig");
848}
849
850class OperatingConfigCollection : public Node
851{
852 public:
853 OperatingConfigCollection(App& app) :
854 Node(app,
855 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/",
856 std::string())
857 {
858 // Defined by Redfish spec privilege registry
859 entityPrivileges = {
860 {boost::beast::http::verb::get, {{"Login"}}},
861 {boost::beast::http::verb::head, {{"Login"}}},
862 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
863 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
864 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
865 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
866 }
867
868 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800869 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
870 const crow::Request& req,
Jonathan Domandba0c292020-12-02 15:34:13 -0800871 const std::vector<std::string>& params) override
872 {
873 if (params.size() != 1)
874 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800875 messages::internalError(asyncResp->res);
Jonathan Domandba0c292020-12-02 15:34:13 -0800876 return;
877 }
878
879 const std::string& cpuName = params[0];
zhanghch058d1b46d2021-04-01 11:18:24 +0800880 asyncResp->res.jsonValue["@odata.type"] =
Jonathan Domandba0c292020-12-02 15:34:13 -0800881 "#OperatingConfigCollection.OperatingConfigCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +0800882 asyncResp->res.jsonValue["@odata.id"] = req.url;
883 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
Jonathan Domandba0c292020-12-02 15:34:13 -0800884
885 // First find the matching CPU object so we know how to constrain our
886 // search for related Config objects.
887 crow::connections::systemBus->async_method_call(
888 [asyncResp, cpuName](const boost::system::error_code ec,
889 const std::vector<std::string>& objects) {
890 if (ec)
891 {
892 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
893 << ec.message();
894 messages::internalError(asyncResp->res);
895 return;
896 }
897
898 for (const std::string& object : objects)
899 {
900 if (!boost::ends_with(object, cpuName))
901 {
902 continue;
903 }
904
905 // Not expected that there will be multiple matching CPU
906 // objects, but if there are just use the first one.
907
908 // Use the common search routine to construct the Collection
909 // of all Config objects under this CPU.
910 collection_util::getCollectionMembers(
911 asyncResp,
912 "/redfish/v1/Systems/system/Processors/" + cpuName +
913 "/OperatingConfigs",
914 {"xyz.openbmc_project.Inventory.Item.Cpu."
915 "OperatingConfig"},
916 object.c_str());
917 return;
918 }
919 },
920 "xyz.openbmc_project.ObjectMapper",
921 "/xyz/openbmc_project/object_mapper",
922 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
923 "/xyz/openbmc_project/inventory", 0,
924 std::array<const char*, 1>{"xyz.openbmc_project.Control.Processor."
925 "CurrentOperatingConfig"});
926 }
927};
928
929class OperatingConfig : public Node
930{
931 public:
932 OperatingConfig(App& app) :
933 Node(app,
934 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/"
935 "<str>/",
936 std::string(), std::string())
937 {
938 // Defined by Redfish spec privilege registry
939 entityPrivileges = {
940 {boost::beast::http::verb::get, {{"Login"}}},
941 {boost::beast::http::verb::head, {{"Login"}}},
942 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
943 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
944 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
945 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
946 }
947
948 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800949 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
950 const crow::Request& req,
Jonathan Domandba0c292020-12-02 15:34:13 -0800951 const std::vector<std::string>& params) override
952 {
953 if (params.size() != 2)
954 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800955 messages::internalError(asyncResp->res);
Jonathan Domandba0c292020-12-02 15:34:13 -0800956 return;
957 }
958
959 const std::string& cpuName = params[0];
960 const std::string& configName = params[1];
961
Jonathan Domandba0c292020-12-02 15:34:13 -0800962 // Ask for all objects implementing OperatingConfig so we can search for
963 // one with a matching name
964 crow::connections::systemBus->async_method_call(
965 [asyncResp, cpuName, configName,
966 reqUrl{req.url}](boost::system::error_code ec,
967 const MapperGetSubTreeResponse& subtree) {
968 if (ec)
969 {
970 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
971 << ec.message();
972 messages::internalError(asyncResp->res);
973 return;
974 }
975 const std::string expectedEnding = cpuName + '/' + configName;
976 for (const auto& [objectPath, serviceMap] : subtree)
977 {
978 // Ignore any configs without matching cpuX/configY
979 if (!boost::ends_with(objectPath, expectedEnding) ||
980 serviceMap.empty())
981 {
982 continue;
983 }
984
985 nlohmann::json& json = asyncResp->res.jsonValue;
986 json["@odata.type"] =
987 "#OperatingConfig.v1_0_0.OperatingConfig";
988 json["@odata.id"] = reqUrl;
989 json["Name"] = "Processor Profile";
990 json["Id"] = configName;
991
992 // Just use the first implementation of the object - not
993 // expected that there would be multiple matching services
994 getOperatingConfigData(asyncResp, serviceMap.begin()->first,
995 objectPath);
996 return;
997 }
998 messages::resourceNotFound(asyncResp->res, "OperatingConfig",
999 configName);
1000 },
1001 "xyz.openbmc_project.ObjectMapper",
1002 "/xyz/openbmc_project/object_mapper",
1003 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1004 "/xyz/openbmc_project/inventory", 0,
1005 std::array<const char*, 1>{
1006 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
1007 }
1008};
1009
Gunnar Millsac6a4442020-10-14 14:55:29 -05001010class ProcessorCollection : public Node
1011{
1012 public:
1013 /*
1014 * Default Constructor
1015 */
1016 ProcessorCollection(App& app) :
1017 Node(app, "/redfish/v1/Systems/system/Processors/")
1018 {
1019 entityPrivileges = {
1020 {boost::beast::http::verb::get, {{"Login"}}},
1021 {boost::beast::http::verb::head, {{"Login"}}},
1022 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1023 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1024 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1025 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1026 }
1027
1028 private:
1029 /**
1030 * Functions triggers appropriate requests on DBus
1031 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001032 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1033 const crow::Request&, const std::vector<std::string>&) override
Gunnar Millsac6a4442020-10-14 14:55:29 -05001034 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001035 asyncResp->res.jsonValue["@odata.type"] =
Gunnar Millsac6a4442020-10-14 14:55:29 -05001036 "#ProcessorCollection.ProcessorCollection";
zhanghch058d1b46d2021-04-01 11:18:24 +08001037 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001038
zhanghch058d1b46d2021-04-01 11:18:24 +08001039 asyncResp->res.jsonValue["@odata.id"] =
1040 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001041
Gunnar Mills05030b82020-10-14 15:51:31 -05001042 collection_util::getCollectionMembers(
1043 asyncResp, "/redfish/v1/Systems/system/Processors",
Jonathan Domanc9514482021-02-24 09:20:51 -08001044 std::vector<const char*>(processorInterfaces.begin(),
1045 processorInterfaces.end()));
Gunnar Millsac6a4442020-10-14 14:55:29 -05001046 }
1047};
1048
1049class Processor : public Node
1050{
1051 public:
1052 /*
1053 * Default Constructor
1054 */
1055 Processor(App& app) :
1056 Node(app, "/redfish/v1/Systems/system/Processors/<str>/", std::string())
1057 {
1058 entityPrivileges = {
1059 {boost::beast::http::verb::get, {{"Login"}}},
1060 {boost::beast::http::verb::head, {{"Login"}}},
1061 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1062 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1063 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1064 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1065 }
1066
1067 private:
1068 /**
1069 * Functions triggers appropriate requests on DBus
1070 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001071 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1072 const crow::Request&,
Gunnar Millsac6a4442020-10-14 14:55:29 -05001073 const std::vector<std::string>& params) override
1074 {
1075 // Check if there is required param, truly entering this shall be
1076 // impossible
1077 if (params.size() != 1)
1078 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001079 messages::internalError(asyncResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -05001080 return;
1081 }
1082 const std::string& processorId = params[0];
zhanghch058d1b46d2021-04-01 11:18:24 +08001083 asyncResp->res.jsonValue["@odata.type"] =
1084 "#Processor.v1_11_0.Processor";
1085 asyncResp->res.jsonValue["@odata.id"] =
Gunnar Millsac6a4442020-10-14 14:55:29 -05001086 "/redfish/v1/Systems/system/Processors/" + processorId;
1087
Jonathan Domanc9514482021-02-24 09:20:51 -08001088 getProcessorObject(asyncResp, processorId, getProcessorData);
Gunnar Millsac6a4442020-10-14 14:55:29 -05001089 }
1090};
1091
1092} // namespace redfish