blob: af0fd123d852e56ed00bb6f9cd0536025e465502 [file] [log] [blame]
Gunnar Millsac6a4442020-10-14 14:55:29 -05001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Jonathan Doman1e1e5982021-06-11 09:36:17 -070018#include "dbus_singleton.hpp"
19#include "error_messages.hpp"
Gunnar Millsac6a4442020-10-14 14:55:29 -050020#include "health.hpp"
21
John Edward Broadbent7e860f12021-04-08 15:57:16 -070022#include <app.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050023#include <boost/container/flat_map.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080024#include <dbus_utility.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070025#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070026#include <sdbusplus/asio/property.hpp>
Jonathan Domandba0c292020-12-02 15:34:13 -080027#include <sdbusplus/message/native_types.hpp>
28#include <sdbusplus/utility/dedup_variant.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050029#include <utils/collection.hpp>
30#include <utils/json_utils.hpp>
31
32namespace redfish
33{
34
35using InterfacesProperties = boost::container::flat_map<
36 std::string,
37 boost::container::flat_map<std::string, dbus::utility::DbusVariantType>>;
38
Jonathan Domanc9514482021-02-24 09:20:51 -080039// Interfaces which imply a D-Bus object represents a Processor
40constexpr std::array<const char*, 2> processorInterfaces = {
41 "xyz.openbmc_project.Inventory.Item.Cpu",
42 "xyz.openbmc_project.Inventory.Item.Accelerator"};
Jonathan Doman2bab9832020-12-02 15:27:40 -080043
Sharad Yadav71b82f22021-05-10 15:11:39 +053044/**
45 * @brief Fill out uuid info of a processor by
46 * requesting data from the given D-Bus object.
47 *
48 * @param[in,out] aResp Async HTTP response.
49 * @param[in] service D-Bus service to query.
50 * @param[in] objPath D-Bus object to query.
51 */
52inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp,
53 const std::string& service,
54 const std::string& objPath)
55{
56 BMCWEB_LOG_DEBUG << "Get Processor UUID";
Jonathan Doman1e1e5982021-06-11 09:36:17 -070057 sdbusplus::asio::getProperty<std::string>(
58 *crow::connections::systemBus, service, objPath,
59 "xyz.openbmc_project.Common.UUID", "UUID",
60 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
61 const std::string& property) {
Sharad Yadav71b82f22021-05-10 15:11:39 +053062 if (ec)
63 {
64 BMCWEB_LOG_DEBUG << "DBUS response error";
65 messages::internalError(aResp->res);
66 return;
67 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -070068 aResp->res.jsonValue["UUID"] = property;
69 });
Sharad Yadav71b82f22021-05-10 15:11:39 +053070}
71
Ed Tanous711ac7a2021-12-20 09:34:41 -080072inline void getCpuDataByInterface(
73 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
74 const dbus::utility::DBusInteracesMap& cpuInterfacesProperties)
Gunnar Millsac6a4442020-10-14 14:55:29 -050075{
76 BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
77
Chicago Duana1649ec2021-03-30 16:54:58 +080078 // Set the default value of state
79 aResp->res.jsonValue["Status"]["State"] = "Enabled";
80 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -050081
82 for (const auto& interface : cpuInterfacesProperties)
83 {
84 for (const auto& property : interface.second)
85 {
Chicago Duana1649ec2021-03-30 16:54:58 +080086 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -050087 {
Chicago Duana1649ec2021-03-30 16:54:58 +080088 const bool* cpuPresent = std::get_if<bool>(&property.second);
89 if (cpuPresent == nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -050090 {
91 // Important property not in desired type
92 messages::internalError(aResp->res);
93 return;
94 }
Chicago Duana1649ec2021-03-30 16:54:58 +080095 if (*cpuPresent == false)
Gunnar Millsac6a4442020-10-14 14:55:29 -050096 {
Chicago Duana1649ec2021-03-30 16:54:58 +080097 // Slot is not populated
Gunnar Millsac6a4442020-10-14 14:55:29 -050098 aResp->res.jsonValue["Status"]["State"] = "Absent";
Chicago Duana1649ec2021-03-30 16:54:58 +080099 }
100 }
101 else if (property.first == "Functional")
102 {
103 const bool* cpuFunctional = std::get_if<bool>(&property.second);
104 if (cpuFunctional == nullptr)
105 {
106 messages::internalError(aResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500107 return;
108 }
Chicago Duana1649ec2021-03-30 16:54:58 +0800109 if (*cpuFunctional == false)
110 {
111 aResp->res.jsonValue["Status"]["Health"] = "Critical";
112 }
113 }
114 else if (property.first == "CoreCount")
115 {
116 const uint16_t* coresCount =
117 std::get_if<uint16_t>(&property.second);
118 if (coresCount == nullptr)
119 {
120 messages::internalError(aResp->res);
121 return;
122 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500123 aResp->res.jsonValue["TotalCores"] = *coresCount;
124 }
Jonathan Domandc3fa662020-10-26 23:10:24 -0700125 else if (property.first == "MaxSpeedInMhz")
126 {
127 const uint32_t* value = std::get_if<uint32_t>(&property.second);
128 if (value != nullptr)
129 {
130 aResp->res.jsonValue["MaxSpeedMHz"] = *value;
131 }
132 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500133 else if (property.first == "Socket")
134 {
135 const std::string* value =
136 std::get_if<std::string>(&property.second);
137 if (value != nullptr)
138 {
139 aResp->res.jsonValue["Socket"] = *value;
140 }
141 }
142 else if (property.first == "ThreadCount")
143 {
Jonathan Domandc3fa662020-10-26 23:10:24 -0700144 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500145 if (value != nullptr)
146 {
147 aResp->res.jsonValue["TotalThreads"] = *value;
148 }
149 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700150 else if (property.first == "EffectiveFamily")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500151 {
Brandon Kim1930fbd2021-09-14 17:52:51 -0700152 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500153 if (value != nullptr)
154 {
155 aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
Brandon Kim1930fbd2021-09-14 17:52:51 -0700156 "0x" + intToHexString(*value);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500157 }
158 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700159 else if (property.first == "EffectiveModel")
160 {
161 const uint16_t* value = std::get_if<uint16_t>(&property.second);
162 if (value == nullptr)
163 {
164 messages::internalError(aResp->res);
165 return;
166 }
167 aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] =
168 "0x" + intToHexString(*value);
169 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500170 else if (property.first == "Id")
171 {
172 const uint64_t* value = std::get_if<uint64_t>(&property.second);
173 if (value != nullptr && *value != 0)
174 {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500175 aResp->res
176 .jsonValue["ProcessorId"]["IdentificationRegisters"] =
Ed Tanousf201ffb2021-10-09 14:49:28 -0700177 "0x" + intToHexString(*value);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500178 }
179 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700180 else if (property.first == "Microcode")
181 {
182 const uint32_t* value = std::get_if<uint32_t>(&property.second);
183 if (value == nullptr)
184 {
185 messages::internalError(aResp->res);
186 return;
187 }
188 aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] =
189 "0x" + intToHexString(*value);
190 }
191 else if (property.first == "Step")
192 {
193 const uint16_t* value = std::get_if<uint16_t>(&property.second);
194 if (value == nullptr)
195 {
196 messages::internalError(aResp->res);
197 return;
198 }
199 aResp->res.jsonValue["ProcessorId"]["Step"] =
200 "0x" + intToHexString(*value);
201 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500202 }
203 }
204
Gunnar Millsac6a4442020-10-14 14:55:29 -0500205 return;
206}
207
zhanghch058d1b46d2021-04-01 11:18:24 +0800208inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500209 const std::string& cpuId,
210 const std::string& service,
211 const std::string& objPath)
212{
213 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
214
215 crow::connections::systemBus->async_method_call(
216 [cpuId, service, objPath, aResp{std::move(aResp)}](
217 const boost::system::error_code ec,
218 const dbus::utility::ManagedObjectType& dbusData) {
219 if (ec)
220 {
221 BMCWEB_LOG_DEBUG << "DBUS response error";
222 messages::internalError(aResp->res);
223 return;
224 }
225 aResp->res.jsonValue["Id"] = cpuId;
226 aResp->res.jsonValue["Name"] = "Processor";
227 aResp->res.jsonValue["ProcessorType"] = "CPU";
228
229 bool slotPresent = false;
230 std::string corePath = objPath + "/core";
231 size_t totalCores = 0;
232 for (const auto& object : dbusData)
233 {
234 if (object.first.str == objPath)
235 {
236 getCpuDataByInterface(aResp, object.second);
237 }
238 else if (boost::starts_with(object.first.str, corePath))
239 {
240 for (const auto& interface : object.second)
241 {
242 if (interface.first ==
243 "xyz.openbmc_project.Inventory.Item")
244 {
245 for (const auto& property : interface.second)
246 {
247 if (property.first == "Present")
248 {
249 const bool* present =
250 std::get_if<bool>(&property.second);
251 if (present != nullptr)
252 {
253 if (*present == true)
254 {
255 slotPresent = true;
256 totalCores++;
257 }
258 }
259 }
260 }
261 }
262 }
263 }
264 }
265 // In getCpuDataByInterface(), state and health are set
266 // based on the present and functional status. If core
267 // count is zero, then it has a higher precedence.
268 if (slotPresent)
269 {
270 if (totalCores == 0)
271 {
272 // Slot is not populated, set status end return
273 aResp->res.jsonValue["Status"]["State"] = "Absent";
274 aResp->res.jsonValue["Status"]["Health"] = "OK";
275 }
276 aResp->res.jsonValue["TotalCores"] = totalCores;
277 }
278 return;
279 },
280 service, "/xyz/openbmc_project/inventory",
281 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
282}
283
zhanghch058d1b46d2021-04-01 11:18:24 +0800284inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500285 const std::string& service,
286 const std::string& objPath)
287{
288 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
289 crow::connections::systemBus->async_method_call(
290 [objPath, aResp{std::move(aResp)}](
291 const boost::system::error_code ec,
292 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800293 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500294 if (ec)
295 {
296 BMCWEB_LOG_DEBUG << "DBUS response error";
297 messages::internalError(aResp->res);
298 return;
299 }
300
301 for (const auto& property : properties)
302 {
303 if (property.first == "SerialNumber")
304 {
305 const std::string* sn =
306 std::get_if<std::string>(&property.second);
307 if (sn != nullptr && !sn->empty())
308 {
309 aResp->res.jsonValue["SerialNumber"] = *sn;
310 }
311 }
312 else if (property.first == "Model")
313 {
314 const std::string* model =
315 std::get_if<std::string>(&property.second);
316 if (model != nullptr && !model->empty())
317 {
318 aResp->res.jsonValue["Model"] = *model;
319 }
320 }
321 else if (property.first == "Manufacturer")
322 {
323
324 const std::string* mfg =
325 std::get_if<std::string>(&property.second);
326 if (mfg != nullptr)
327 {
328 aResp->res.jsonValue["Manufacturer"] = *mfg;
329
330 // Otherwise would be unexpected.
331 if (mfg->find("Intel") != std::string::npos)
332 {
333 aResp->res.jsonValue["ProcessorArchitecture"] =
334 "x86";
335 aResp->res.jsonValue["InstructionSet"] = "x86-64";
336 }
337 else if (mfg->find("IBM") != std::string::npos)
338 {
339 aResp->res.jsonValue["ProcessorArchitecture"] =
340 "Power";
341 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
342 }
343 }
344 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600345 else if (property.first == "PartNumber")
346 {
347 const std::string* partNumber =
348 std::get_if<std::string>(&property.second);
349
350 if (partNumber == nullptr)
351 {
352 messages::internalError(aResp->res);
353 return;
354 }
355 aResp->res.jsonValue["PartNumber"] = *partNumber;
356 }
357 else if (property.first == "SparePartNumber")
358 {
359 const std::string* sparePartNumber =
360 std::get_if<std::string>(&property.second);
361
362 if (sparePartNumber == nullptr)
363 {
364 messages::internalError(aResp->res);
365 return;
366 }
367 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
368 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500369 }
370 },
371 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
372 "xyz.openbmc_project.Inventory.Decorator.Asset");
373}
374
zhanghch058d1b46d2021-04-01 11:18:24 +0800375inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500376 const std::string& service,
377 const std::string& objPath)
378{
379 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
380 crow::connections::systemBus->async_method_call(
381 [objPath, aResp{std::move(aResp)}](
382 const boost::system::error_code ec,
383 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800384 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500385 if (ec)
386 {
387 BMCWEB_LOG_DEBUG << "DBUS response error";
388 messages::internalError(aResp->res);
389 return;
390 }
391
392 for (const auto& property : properties)
393 {
394 if (property.first == "Version")
395 {
396 const std::string* ver =
397 std::get_if<std::string>(&property.second);
398 if (ver != nullptr)
399 {
400 aResp->res.jsonValue["Version"] = *ver;
401 }
402 break;
403 }
404 }
405 },
406 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
407 "xyz.openbmc_project.Inventory.Decorator.Revision");
408}
409
zhanghch058d1b46d2021-04-01 11:18:24 +0800410inline void getAcceleratorDataByService(
411 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
412 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500413{
414 BMCWEB_LOG_DEBUG
415 << "Get available system Accelerator resources by service.";
416 crow::connections::systemBus->async_method_call(
417 [acclrtrId, aResp{std::move(aResp)}](
418 const boost::system::error_code ec,
419 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800420 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500421 if (ec)
422 {
423 BMCWEB_LOG_DEBUG << "DBUS response error";
424 messages::internalError(aResp->res);
425 return;
426 }
427 aResp->res.jsonValue["Id"] = acclrtrId;
428 aResp->res.jsonValue["Name"] = "Processor";
429 const bool* accPresent = nullptr;
430 const bool* accFunctional = nullptr;
431
432 for (const auto& property : properties)
433 {
434 if (property.first == "Functional")
435 {
436 accFunctional = std::get_if<bool>(&property.second);
437 }
438 else if (property.first == "Present")
439 {
440 accPresent = std::get_if<bool>(&property.second);
441 }
442 }
443
444 std::string state = "Enabled";
445 std::string health = "OK";
446
447 if (accPresent != nullptr && *accPresent == false)
448 {
449 state = "Absent";
450 }
451
452 if ((accFunctional != nullptr) && (*accFunctional == false))
453 {
454 if (state == "Enabled")
455 {
456 health = "Critical";
457 }
458 }
459
460 aResp->res.jsonValue["Status"]["State"] = state;
461 aResp->res.jsonValue["Status"]["Health"] = health;
462 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
463 },
464 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
465}
466
Jonathan Domandba0c292020-12-02 15:34:13 -0800467// OperatingConfig D-Bus Types
468using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
469using BaseSpeedPrioritySettingsProperty =
470 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
471// uint32_t and size_t may or may not be the same type, requiring a dedup'd
472// variant
Ed Tanous168e20c2021-12-13 14:39:53 -0800473using OperatingConfigProperties =
474 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>;
Jonathan Domandba0c292020-12-02 15:34:13 -0800475
476/**
477 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
478 * OperatingConfig D-Bus property.
479 *
480 * @param[in,out] aResp Async HTTP response.
481 * @param[in] baseSpeedSettings Full list of base speed priority groups,
482 * to use to determine the list of high
483 * speed cores.
484 */
485inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800486 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800487 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
488{
489 // The D-Bus property does not indicate which bucket is the "high
490 // priority" group, so let's discern that by looking for the one with
491 // highest base frequency.
492 auto highPriorityGroup = baseSpeedSettings.cend();
493 uint32_t highestBaseSpeed = 0;
494 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
495 ++it)
496 {
497 const uint32_t baseFreq = std::get<uint32_t>(*it);
498 if (baseFreq > highestBaseSpeed)
499 {
500 highestBaseSpeed = baseFreq;
501 highPriorityGroup = it;
502 }
503 }
504
505 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
506 jsonCoreIds = nlohmann::json::array();
507
508 // There may not be any entries in the D-Bus property, so only populate
509 // if there was actually something there.
510 if (highPriorityGroup != baseSpeedSettings.cend())
511 {
512 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
513 }
514}
515
516/**
517 * Fill out OperatingConfig related items in a Processor resource by requesting
518 * data from the given D-Bus object.
519 *
520 * @param[in,out] aResp Async HTTP response.
521 * @param[in] cpuId CPU D-Bus name.
522 * @param[in] service D-Bus service to query.
523 * @param[in] objPath D-Bus object to query.
524 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800525inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800526 const std::string& cpuId,
527 const std::string& service,
528 const std::string& objPath)
529{
530 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
531
532 // First, GetAll CurrentOperatingConfig properties on the object
533 crow::connections::systemBus->async_method_call(
534 [aResp, cpuId, service](
535 const boost::system::error_code ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800536 const std::vector<std::pair<
537 std::string, dbus::utility::DbusVariantType>>& properties) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800538 if (ec)
539 {
540 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
541 << ec.message();
542 messages::internalError(aResp->res);
543 return;
544 }
545
546 nlohmann::json& json = aResp->res.jsonValue;
547
548 for (const auto& [dbusPropName, variantVal] : properties)
549 {
550 if (dbusPropName == "AppliedConfig")
551 {
552 const sdbusplus::message::object_path* dbusPathWrapper =
553 std::get_if<sdbusplus::message::object_path>(
554 &variantVal);
555 if (dbusPathWrapper == nullptr)
556 {
557 continue;
558 }
559
560 const std::string& dbusPath = dbusPathWrapper->str;
561 std::string uri = "/redfish/v1/Systems/system/Processors/" +
562 cpuId + "/OperatingConfigs";
563 json["OperatingConfigs"] = {{"@odata.id", uri}};
564
565 // Reuse the D-Bus config object name for the Redfish
566 // URI
567 size_t baseNamePos = dbusPath.rfind('/');
568 if (baseNamePos == std::string::npos ||
569 baseNamePos == (dbusPath.size() - 1))
570 {
571 // If the AppliedConfig was somehow not a valid path,
572 // skip adding any more properties, since everything
573 // else is tied to this applied config.
574 messages::internalError(aResp->res);
575 break;
576 }
577 uri += '/';
578 uri += dbusPath.substr(baseNamePos + 1);
579 json["AppliedOperatingConfig"] = {{"@odata.id", uri}};
580
581 // Once we found the current applied config, queue another
582 // request to read the base freq core ids out of that
583 // config.
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700584 sdbusplus::asio::getProperty<
585 BaseSpeedPrioritySettingsProperty>(
586 *crow::connections::systemBus, service, dbusPath,
587 "xyz.openbmc_project.Inventory.Item.Cpu."
588 "OperatingConfig",
589 "BaseSpeedPrioritySettings",
590 [aResp](const boost::system::error_code ec,
591 const BaseSpeedPrioritySettingsProperty&
592 baseSpeedList) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800593 if (ec)
594 {
595 BMCWEB_LOG_WARNING
596 << "D-Bus Property Get error: " << ec;
597 messages::internalError(aResp->res);
598 return;
599 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700600
601 highSpeedCoreIdsHandler(aResp, baseSpeedList);
602 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800603 }
604 else if (dbusPropName == "BaseSpeedPriorityEnabled")
605 {
606 const bool* state = std::get_if<bool>(&variantVal);
607 if (state != nullptr)
608 {
609 json["BaseSpeedPriorityState"] =
610 *state ? "Enabled" : "Disabled";
611 }
612 }
613 }
614 },
615 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
616 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
617}
618
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600619/**
620 * @brief Fill out location info of a processor by
621 * requesting data from the given D-Bus object.
622 *
623 * @param[in,out] aResp Async HTTP response.
624 * @param[in] service D-Bus service to query.
625 * @param[in] objPath D-Bus object to query.
626 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800627inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600628 const std::string& service,
629 const std::string& objPath)
630{
631 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700632 sdbusplus::asio::getProperty<std::string>(
633 *crow::connections::systemBus, service, objPath,
634 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
635 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
636 const std::string& property) {
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600637 if (ec)
638 {
639 BMCWEB_LOG_DEBUG << "DBUS response error";
640 messages::internalError(aResp->res);
641 return;
642 }
643
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600644 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700645 property;
646 });
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600647}
648
Jonathan Domanc9514482021-02-24 09:20:51 -0800649/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800650 * Populate the unique identifier in a Processor resource by requesting data
651 * from the given D-Bus object.
652 *
653 * @param[in,out] aResp Async HTTP response.
654 * @param[in] service D-Bus service to query.
655 * @param[in] objPath D-Bus object to query.
656 */
657inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
658 const std::string& service,
659 const std::string& objectPath)
660{
661 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700662 sdbusplus::asio::getProperty<std::string>(
663 *crow::connections::systemBus, service, objectPath,
664 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
665 "UniqueIdentifier",
666 [aResp](boost::system::error_code ec, const std::string& id) {
667 if (ec)
Jonathan Doman49e429c2021-03-03 13:11:44 -0800668 {
669 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
670 messages::internalError(aResp->res);
671 return;
672 }
673 aResp->res
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700674 .jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] = id;
675 });
Jonathan Doman49e429c2021-03-03 13:11:44 -0800676}
677
678/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800679 * Find the D-Bus object representing the requested Processor, and call the
680 * handler with the results. If matching object is not found, add 404 error to
681 * response and don't call the handler.
682 *
683 * @param[in,out] resp Async HTTP response.
684 * @param[in] processorId Redfish Processor Id.
685 * @param[in] handler Callback to continue processing request upon
686 * successfully finding object.
687 */
688template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800689inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800690 const std::string& processorId,
691 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500692{
693 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
694
Jonathan Domanc9514482021-02-24 09:20:51 -0800695 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500696 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800697 [resp, processorId, handler = std::forward<Handler>(handler)](
698 boost::system::error_code ec,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600699 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500700 if (ec)
701 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800702 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
703 messages::internalError(resp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500704 return;
705 }
Jonathan Doman2bab9832020-12-02 15:27:40 -0800706 for (const auto& [objectPath, serviceMap] : subtree)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500707 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800708 // Ignore any objects which don't end with our desired cpu name
709 if (!boost::ends_with(objectPath, processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500710 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800711 continue;
712 }
713
Jonathan Domanc9514482021-02-24 09:20:51 -0800714 bool found = false;
715 // Filter out objects that don't have the CPU-specific
716 // interfaces to make sure we can return 404 on non-CPUs
717 // (e.g. /redfish/../Processors/dimm0)
Jonathan Doman2bab9832020-12-02 15:27:40 -0800718 for (const auto& [serviceName, interfaceList] : serviceMap)
719 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800720 if (std::find_first_of(
721 interfaceList.begin(), interfaceList.end(),
722 processorInterfaces.begin(),
723 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500724 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800725 found = true;
726 break;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500727 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500728 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800729
730 if (!found)
731 {
732 continue;
733 }
734
735 // Process the first object which does match our cpu name and
736 // required interfaces, and potentially ignore any other
737 // matching objects. Assume all interfaces we want to process
738 // must be on the same object path.
739
740 handler(resp, processorId, objectPath, serviceMap);
Jonathan Doman2bab9832020-12-02 15:27:40 -0800741 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500742 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800743 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500744 },
745 "xyz.openbmc_project.ObjectMapper",
746 "/xyz/openbmc_project/object_mapper",
747 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800748 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800749 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530750 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800751 "xyz.openbmc_project.Inventory.Decorator.Asset",
752 "xyz.openbmc_project.Inventory.Decorator.Revision",
753 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600754 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800755 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800756 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
757 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500758}
759
zhanghch058d1b46d2021-04-01 11:18:24 +0800760inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800761 const std::string& processorId,
762 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600763 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Domanc9514482021-02-24 09:20:51 -0800764{
765 for (const auto& [serviceName, interfaceList] : serviceMap)
766 {
767 for (const auto& interface : interfaceList)
768 {
769 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
770 {
771 getCpuAssetData(aResp, serviceName, objectPath);
772 }
George Liu0fda0f12021-11-16 10:06:17 +0800773 else if (interface ==
774 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800775 {
776 getCpuRevisionData(aResp, serviceName, objectPath);
777 }
778 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
779 {
780 getCpuDataByService(aResp, processorId, serviceName,
781 objectPath);
782 }
George Liu0fda0f12021-11-16 10:06:17 +0800783 else if (interface ==
784 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800785 {
786 getAcceleratorDataByService(aResp, processorId, serviceName,
787 objectPath);
788 }
George Liu0fda0f12021-11-16 10:06:17 +0800789 else if (
790 interface ==
791 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800792 {
793 getCpuConfigData(aResp, processorId, serviceName, objectPath);
794 }
George Liu0fda0f12021-11-16 10:06:17 +0800795 else if (interface ==
796 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800797 {
798 getCpuLocationCode(aResp, serviceName, objectPath);
799 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530800 else if (interface == "xyz.openbmc_project.Common.UUID")
801 {
802 getProcessorUUID(aResp, serviceName, objectPath);
803 }
George Liu0fda0f12021-11-16 10:06:17 +0800804 else if (interface ==
805 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800806 {
807 getCpuUniqueId(aResp, serviceName, objectPath);
808 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800809 }
810 }
811}
812
Jonathan Domandba0c292020-12-02 15:34:13 -0800813/**
814 * Request all the properties for the given D-Bus object and fill out the
815 * related entries in the Redfish OperatingConfig response.
816 *
817 * @param[in,out] aResp Async HTTP response.
818 * @param[in] service D-Bus service name to query.
819 * @param[in] objPath D-Bus object to query.
820 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800821inline void
822 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
823 const std::string& service,
824 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800825{
826 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -0800827 [aResp](const boost::system::error_code ec,
Jonathan Domandba0c292020-12-02 15:34:13 -0800828 const OperatingConfigProperties& properties) {
829 if (ec)
830 {
831 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
832 << ec.message();
833 messages::internalError(aResp->res);
834 return;
835 }
836
837 nlohmann::json& json = aResp->res.jsonValue;
838 for (const auto& [key, variant] : properties)
839 {
840 if (key == "AvailableCoreCount")
841 {
842 const size_t* cores = std::get_if<size_t>(&variant);
843 if (cores != nullptr)
844 {
845 json["TotalAvailableCoreCount"] = *cores;
846 }
847 }
848 else if (key == "BaseSpeed")
849 {
850 const uint32_t* speed = std::get_if<uint32_t>(&variant);
851 if (speed != nullptr)
852 {
853 json["BaseSpeedMHz"] = *speed;
854 }
855 }
856 else if (key == "MaxJunctionTemperature")
857 {
858 const uint32_t* temp = std::get_if<uint32_t>(&variant);
859 if (temp != nullptr)
860 {
861 json["MaxJunctionTemperatureCelsius"] = *temp;
862 }
863 }
864 else if (key == "MaxSpeed")
865 {
866 const uint32_t* speed = std::get_if<uint32_t>(&variant);
867 if (speed != nullptr)
868 {
869 json["MaxSpeedMHz"] = *speed;
870 }
871 }
872 else if (key == "PowerLimit")
873 {
874 const uint32_t* tdp = std::get_if<uint32_t>(&variant);
875 if (tdp != nullptr)
876 {
877 json["TDPWatts"] = *tdp;
878 }
879 }
880 else if (key == "TurboProfile")
881 {
882 const auto* turboList =
883 std::get_if<TurboProfileProperty>(&variant);
884 if (turboList == nullptr)
885 {
886 continue;
887 }
888
889 nlohmann::json& turboArray = json["TurboProfile"];
890 turboArray = nlohmann::json::array();
891 for (const auto& [turboSpeed, coreCount] : *turboList)
892 {
893 turboArray.push_back({{"ActiveCoreCount", coreCount},
894 {"MaxSpeedMHz", turboSpeed}});
895 }
896 }
897 else if (key == "BaseSpeedPrioritySettings")
898 {
899 const auto* baseSpeedList =
900 std::get_if<BaseSpeedPrioritySettingsProperty>(
901 &variant);
902 if (baseSpeedList == nullptr)
903 {
904 continue;
905 }
906
907 nlohmann::json& baseSpeedArray =
908 json["BaseSpeedPrioritySettings"];
909 baseSpeedArray = nlohmann::json::array();
910 for (const auto& [baseSpeed, coreList] : *baseSpeedList)
911 {
912 baseSpeedArray.push_back(
913 {{"CoreCount", coreList.size()},
914 {"CoreIDs", coreList},
915 {"BaseSpeedMHz", baseSpeed}});
916 }
917 }
918 }
919 },
920 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
921 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig");
922}
923
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800924/**
925 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
926 * property. Main task is to translate error messages into Redfish errors.
927 *
928 * @param[in,out] resp HTTP response.
929 * @param[in] setPropVal Value which we attempted to set.
930 * @param[in] ec D-Bus response error code.
931 * @param[in] msg D-Bus response message.
932 */
933inline void
934 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
935 const std::string& setPropVal,
936 boost::system::error_code ec,
937 const sdbusplus::message::message& msg)
938{
939 if (!ec)
940 {
941 BMCWEB_LOG_DEBUG << "Set Property succeeded";
942 return;
943 }
944
945 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
946
947 const sd_bus_error* dbusError = msg.get_error();
948 if (dbusError == nullptr)
949 {
950 messages::internalError(resp->res);
951 return;
952 }
953
954 // The asio error code doesn't know about our custom errors, so we have to
955 // parse the error string. Some of these D-Bus -> Redfish translations are a
956 // stretch, but it's good to try to communicate something vaguely useful.
957 if (strcmp(dbusError->name,
958 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
959 {
960 // Service did not like the object_path we tried to set.
961 messages::propertyValueIncorrect(
962 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
963 }
964 else if (strcmp(dbusError->name,
965 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
966 {
967 // Service indicates we can never change the config for this processor.
968 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
969 }
970 else if (strcmp(dbusError->name,
971 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
972 {
973 // Service indicates the config cannot be changed right now, but maybe
974 // in a different system state.
975 messages::resourceInStandby(resp->res);
976 }
977 else if (strcmp(dbusError->name,
978 "xyz.openbmc_project.Common.Device.Error.WriteFailure") ==
979 0)
980 {
981 // Service tried to change the config, but it failed.
982 messages::operationFailed(resp->res);
983 }
984 else
985 {
986 messages::internalError(resp->res);
987 }
988}
989
990/**
991 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
992 * validation of the input data, and then set the D-Bus property.
993 *
994 * @param[in,out] resp Async HTTP response.
995 * @param[in] processorId Processor's Id.
996 * @param[in] appliedConfigUri New property value to apply.
997 * @param[in] cpuObjectPath Path of CPU object to modify.
998 * @param[in] serviceMap Service map for CPU object.
999 */
1000inline void patchAppliedOperatingConfig(
1001 const std::shared_ptr<bmcweb::AsyncResp>& resp,
1002 const std::string& processorId, const std::string& appliedConfigUri,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001003 const std::string& cpuObjectPath,
1004 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001005{
1006 // Check that the property even exists by checking for the interface
1007 const std::string* controlService = nullptr;
1008 for (const auto& [serviceName, interfaceList] : serviceMap)
1009 {
1010 if (std::find(interfaceList.begin(), interfaceList.end(),
1011 "xyz.openbmc_project.Control.Processor."
1012 "CurrentOperatingConfig") != interfaceList.end())
1013 {
1014 controlService = &serviceName;
1015 break;
1016 }
1017 }
1018
1019 if (controlService == nullptr)
1020 {
1021 messages::internalError(resp->res);
1022 return;
1023 }
1024
1025 // Check that the config URI is a child of the cpu URI being patched.
1026 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
1027 expectedPrefix += processorId;
1028 expectedPrefix += "/OperatingConfigs/";
1029 if (!boost::starts_with(appliedConfigUri, expectedPrefix) ||
1030 expectedPrefix.size() == appliedConfigUri.size())
1031 {
1032 messages::propertyValueIncorrect(
1033 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1034 return;
1035 }
1036
1037 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1038 // direct child of the CPU object.
1039 // Strip the expectedPrefix from the config URI to get the "filename", and
1040 // append to the CPU's path.
1041 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1042 sdbusplus::message::object_path configPath(cpuObjectPath);
1043 configPath /= configBaseName;
1044
1045 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1046
1047 // Set the property, with handler to check error responses
1048 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -08001049 [resp, appliedConfigUri](const boost::system::error_code ec,
1050 const sdbusplus::message::message& msg) {
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001051 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
1052 },
1053 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1054 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
Ed Tanous168e20c2021-12-13 14:39:53 -08001055 "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001056}
1057
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001058inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001059{
Jonathan Domandba0c292020-12-02 15:34:13 -08001060
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001061 BMCWEB_ROUTE(
1062 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001063 .privileges(redfish::privileges::getOperatingConfigCollection)
George Liu0fda0f12021-11-16 10:06:17 +08001064 .methods(
1065 boost::beast::http::verb::get)([](const crow::Request& req,
1066 const std::shared_ptr<
1067 bmcweb::AsyncResp>& asyncResp,
1068 const std::string& cpuName) {
1069 asyncResp->res.jsonValue["@odata.type"] =
1070 "#OperatingConfigCollection.OperatingConfigCollection";
1071 asyncResp->res.jsonValue["@odata.id"] = req.url;
1072 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
Jonathan Domandba0c292020-12-02 15:34:13 -08001073
George Liu0fda0f12021-11-16 10:06:17 +08001074 // First find the matching CPU object so we know how to
1075 // constrain our search for related Config objects.
1076 crow::connections::systemBus->async_method_call(
1077 [asyncResp, cpuName](const boost::system::error_code ec,
1078 const std::vector<std::string>& objects) {
1079 if (ec)
1080 {
1081 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1082 << ec.message();
1083 messages::internalError(asyncResp->res);
1084 return;
1085 }
1086
1087 for (const std::string& object : objects)
1088 {
1089 if (!boost::ends_with(object, cpuName))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001090 {
George Liu0fda0f12021-11-16 10:06:17 +08001091 continue;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001092 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001093
George Liu0fda0f12021-11-16 10:06:17 +08001094 // Not expected that there will be multiple matching
1095 // CPU objects, but if there are just use the first
1096 // one.
Jonathan Domandba0c292020-12-02 15:34:13 -08001097
George Liu0fda0f12021-11-16 10:06:17 +08001098 // Use the common search routine to construct the
1099 // Collection of all Config objects under this CPU.
1100 collection_util::getCollectionMembers(
1101 asyncResp,
1102 "/redfish/v1/Systems/system/Processors/" + cpuName +
1103 "/OperatingConfigs",
1104 {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1105 object.c_str());
1106 return;
1107 }
1108 },
1109 "xyz.openbmc_project.ObjectMapper",
1110 "/xyz/openbmc_project/object_mapper",
1111 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1112 "/xyz/openbmc_project/inventory", 0,
1113 std::array<const char*, 1>{
1114 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
1115 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001116}
1117
1118inline void requestRoutesOperatingConfig(App& app)
1119{
1120 BMCWEB_ROUTE(
1121 app,
1122 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001123 .privileges(redfish::privileges::getOperatingConfig)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001124 .methods(
1125 boost::beast::http::verb::get)([](const crow::Request& req,
1126 const std::shared_ptr<
1127 bmcweb::AsyncResp>& asyncResp,
1128 const std::string& cpuName,
1129 const std::string& configName) {
1130 // Ask for all objects implementing OperatingConfig so we can search
1131 // for one with a matching name
1132 crow::connections::systemBus->async_method_call(
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001133 [asyncResp, cpuName, configName, reqUrl{req.url}](
1134 boost::system::error_code ec,
1135 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001136 if (ec)
Jonathan Domandba0c292020-12-02 15:34:13 -08001137 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001138 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1139 << ec.message();
1140 messages::internalError(asyncResp->res);
1141 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001142 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001143 const std::string expectedEnding =
1144 cpuName + '/' + configName;
1145 for (const auto& [objectPath, serviceMap] : subtree)
Jonathan Domandba0c292020-12-02 15:34:13 -08001146 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001147 // Ignore any configs without matching cpuX/configY
1148 if (!boost::ends_with(objectPath, expectedEnding) ||
1149 serviceMap.empty())
1150 {
1151 continue;
1152 }
1153
1154 nlohmann::json& json = asyncResp->res.jsonValue;
1155 json["@odata.type"] =
1156 "#OperatingConfig.v1_0_0.OperatingConfig";
1157 json["@odata.id"] = reqUrl;
1158 json["Name"] = "Processor Profile";
1159 json["Id"] = configName;
1160
1161 // Just use the first implementation of the object - not
1162 // expected that there would be multiple matching
1163 // services
1164 getOperatingConfigData(
1165 asyncResp, serviceMap.begin()->first, objectPath);
1166 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001167 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001168 messages::resourceNotFound(asyncResp->res,
1169 "OperatingConfig", configName);
1170 },
1171 "xyz.openbmc_project.ObjectMapper",
1172 "/xyz/openbmc_project/object_mapper",
1173 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1174 "/xyz/openbmc_project/inventory", 0,
1175 std::array<const char*, 1>{
1176 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
1177 });
1178}
Jonathan Domandba0c292020-12-02 15:34:13 -08001179
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001180inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001181{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001182 /**
1183 * Functions triggers appropriate requests on DBus
1184 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001185 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001186 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001187 .methods(boost::beast::http::verb::get)(
1188 [](const crow::Request&,
1189 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1190 asyncResp->res.jsonValue["@odata.type"] =
1191 "#ProcessorCollection.ProcessorCollection";
1192 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001193
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001194 asyncResp->res.jsonValue["@odata.id"] =
1195 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001196
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001197 collection_util::getCollectionMembers(
1198 asyncResp, "/redfish/v1/Systems/system/Processors",
1199 std::vector<const char*>(processorInterfaces.begin(),
1200 processorInterfaces.end()));
1201 });
1202}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001203
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001204inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001205{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001206 /**
1207 * Functions triggers appropriate requests on DBus
1208 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001209
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001210 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001211 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001212 .methods(boost::beast::http::verb::get)(
1213 [](const crow::Request&,
1214 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1215 const std::string& processorId) {
1216 asyncResp->res.jsonValue["@odata.type"] =
1217 "#Processor.v1_11_0.Processor";
1218 asyncResp->res.jsonValue["@odata.id"] =
1219 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001220
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001221 getProcessorObject(asyncResp, processorId, getProcessorData);
1222 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001223
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001224 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001225 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001226 .methods(boost::beast::http::verb::patch)(
1227 [](const crow::Request& req,
1228 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1229 const std::string& processorId) {
1230 std::optional<nlohmann::json> appliedConfigJson;
1231 if (!json_util::readJson(req, asyncResp->res,
1232 "AppliedOperatingConfig",
1233 appliedConfigJson))
1234 {
1235 return;
1236 }
1237
1238 std::string appliedConfigUri;
1239 if (appliedConfigJson)
1240 {
1241 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1242 "@odata.id", appliedConfigUri))
1243 {
1244 return;
1245 }
1246 // Check for 404 and find matching D-Bus object, then run
1247 // property patch handlers if that all succeeds.
1248 getProcessorObject(
1249 asyncResp, processorId,
1250 [appliedConfigUri = std::move(appliedConfigUri)](
1251 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1252 const std::string& processorId,
1253 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001254 const dbus::utility::MapperServiceMap& serviceMap) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001255 patchAppliedOperatingConfig(asyncResp, processorId,
1256 appliedConfigUri,
1257 objectPath, serviceMap);
1258 });
1259 }
1260 });
1261}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001262
1263} // namespace redfish