blob: b51a9015666c6d1ac06d2fd95a3e7b239c2a8aa7 [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 }
Ed Tanouse05aec52022-01-25 10:28:56 -080095 if (!*cpuPresent)
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 }
Ed Tanouse05aec52022-01-25 10:28:56 -0800109 if (!*cpuFunctional)
Chicago Duana1649ec2021-03-30 16:54:58 +0800110 {
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 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500204}
205
zhanghch058d1b46d2021-04-01 11:18:24 +0800206inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500207 const std::string& cpuId,
208 const std::string& service,
209 const std::string& objPath)
210{
211 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
212
213 crow::connections::systemBus->async_method_call(
214 [cpuId, service, objPath, aResp{std::move(aResp)}](
215 const boost::system::error_code ec,
216 const dbus::utility::ManagedObjectType& dbusData) {
217 if (ec)
218 {
219 BMCWEB_LOG_DEBUG << "DBUS response error";
220 messages::internalError(aResp->res);
221 return;
222 }
223 aResp->res.jsonValue["Id"] = cpuId;
224 aResp->res.jsonValue["Name"] = "Processor";
225 aResp->res.jsonValue["ProcessorType"] = "CPU";
226
227 bool slotPresent = false;
228 std::string corePath = objPath + "/core";
229 size_t totalCores = 0;
230 for (const auto& object : dbusData)
231 {
232 if (object.first.str == objPath)
233 {
234 getCpuDataByInterface(aResp, object.second);
235 }
236 else if (boost::starts_with(object.first.str, corePath))
237 {
238 for (const auto& interface : object.second)
239 {
240 if (interface.first ==
241 "xyz.openbmc_project.Inventory.Item")
242 {
243 for (const auto& property : interface.second)
244 {
245 if (property.first == "Present")
246 {
247 const bool* present =
248 std::get_if<bool>(&property.second);
249 if (present != nullptr)
250 {
Ed Tanouse05aec52022-01-25 10:28:56 -0800251 if (*present)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500252 {
253 slotPresent = true;
254 totalCores++;
255 }
256 }
257 }
258 }
259 }
260 }
261 }
262 }
263 // In getCpuDataByInterface(), state and health are set
264 // based on the present and functional status. If core
265 // count is zero, then it has a higher precedence.
266 if (slotPresent)
267 {
268 if (totalCores == 0)
269 {
270 // Slot is not populated, set status end return
271 aResp->res.jsonValue["Status"]["State"] = "Absent";
272 aResp->res.jsonValue["Status"]["Health"] = "OK";
273 }
274 aResp->res.jsonValue["TotalCores"] = totalCores;
275 }
276 return;
277 },
278 service, "/xyz/openbmc_project/inventory",
279 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
280}
281
zhanghch058d1b46d2021-04-01 11:18:24 +0800282inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500283 const std::string& service,
284 const std::string& objPath)
285{
286 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
287 crow::connections::systemBus->async_method_call(
288 [objPath, aResp{std::move(aResp)}](
289 const boost::system::error_code ec,
290 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800291 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500292 if (ec)
293 {
294 BMCWEB_LOG_DEBUG << "DBUS response error";
295 messages::internalError(aResp->res);
296 return;
297 }
298
299 for (const auto& property : properties)
300 {
301 if (property.first == "SerialNumber")
302 {
303 const std::string* sn =
304 std::get_if<std::string>(&property.second);
305 if (sn != nullptr && !sn->empty())
306 {
307 aResp->res.jsonValue["SerialNumber"] = *sn;
308 }
309 }
310 else if (property.first == "Model")
311 {
312 const std::string* model =
313 std::get_if<std::string>(&property.second);
314 if (model != nullptr && !model->empty())
315 {
316 aResp->res.jsonValue["Model"] = *model;
317 }
318 }
319 else if (property.first == "Manufacturer")
320 {
321
322 const std::string* mfg =
323 std::get_if<std::string>(&property.second);
324 if (mfg != nullptr)
325 {
326 aResp->res.jsonValue["Manufacturer"] = *mfg;
327
328 // Otherwise would be unexpected.
329 if (mfg->find("Intel") != std::string::npos)
330 {
331 aResp->res.jsonValue["ProcessorArchitecture"] =
332 "x86";
333 aResp->res.jsonValue["InstructionSet"] = "x86-64";
334 }
335 else if (mfg->find("IBM") != std::string::npos)
336 {
337 aResp->res.jsonValue["ProcessorArchitecture"] =
338 "Power";
339 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
340 }
341 }
342 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600343 else if (property.first == "PartNumber")
344 {
345 const std::string* partNumber =
346 std::get_if<std::string>(&property.second);
347
348 if (partNumber == nullptr)
349 {
350 messages::internalError(aResp->res);
351 return;
352 }
353 aResp->res.jsonValue["PartNumber"] = *partNumber;
354 }
355 else if (property.first == "SparePartNumber")
356 {
357 const std::string* sparePartNumber =
358 std::get_if<std::string>(&property.second);
359
360 if (sparePartNumber == nullptr)
361 {
362 messages::internalError(aResp->res);
363 return;
364 }
365 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
366 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500367 }
368 },
369 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
370 "xyz.openbmc_project.Inventory.Decorator.Asset");
371}
372
zhanghch058d1b46d2021-04-01 11:18:24 +0800373inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500374 const std::string& service,
375 const std::string& objPath)
376{
377 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
378 crow::connections::systemBus->async_method_call(
379 [objPath, aResp{std::move(aResp)}](
380 const boost::system::error_code ec,
381 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800382 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500383 if (ec)
384 {
385 BMCWEB_LOG_DEBUG << "DBUS response error";
386 messages::internalError(aResp->res);
387 return;
388 }
389
390 for (const auto& property : properties)
391 {
392 if (property.first == "Version")
393 {
394 const std::string* ver =
395 std::get_if<std::string>(&property.second);
396 if (ver != nullptr)
397 {
398 aResp->res.jsonValue["Version"] = *ver;
399 }
400 break;
401 }
402 }
403 },
404 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
405 "xyz.openbmc_project.Inventory.Decorator.Revision");
406}
407
zhanghch058d1b46d2021-04-01 11:18:24 +0800408inline void getAcceleratorDataByService(
409 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
410 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500411{
412 BMCWEB_LOG_DEBUG
413 << "Get available system Accelerator resources by service.";
414 crow::connections::systemBus->async_method_call(
415 [acclrtrId, aResp{std::move(aResp)}](
416 const boost::system::error_code ec,
417 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800418 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500419 if (ec)
420 {
421 BMCWEB_LOG_DEBUG << "DBUS response error";
422 messages::internalError(aResp->res);
423 return;
424 }
425 aResp->res.jsonValue["Id"] = acclrtrId;
426 aResp->res.jsonValue["Name"] = "Processor";
427 const bool* accPresent = nullptr;
428 const bool* accFunctional = nullptr;
429
430 for (const auto& property : properties)
431 {
432 if (property.first == "Functional")
433 {
434 accFunctional = std::get_if<bool>(&property.second);
435 }
436 else if (property.first == "Present")
437 {
438 accPresent = std::get_if<bool>(&property.second);
439 }
440 }
441
442 std::string state = "Enabled";
443 std::string health = "OK";
444
Ed Tanouse05aec52022-01-25 10:28:56 -0800445 if (accPresent != nullptr && !*accPresent)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500446 {
447 state = "Absent";
448 }
449
Ed Tanouse05aec52022-01-25 10:28:56 -0800450 if ((accFunctional != nullptr) && !*accFunctional)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500451 {
452 if (state == "Enabled")
453 {
454 health = "Critical";
455 }
456 }
457
458 aResp->res.jsonValue["Status"]["State"] = state;
459 aResp->res.jsonValue["Status"]["Health"] = health;
460 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
461 },
462 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
463}
464
Jonathan Domandba0c292020-12-02 15:34:13 -0800465// OperatingConfig D-Bus Types
466using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
467using BaseSpeedPrioritySettingsProperty =
468 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
469// uint32_t and size_t may or may not be the same type, requiring a dedup'd
470// variant
Ed Tanous168e20c2021-12-13 14:39:53 -0800471using OperatingConfigProperties =
472 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>;
Jonathan Domandba0c292020-12-02 15:34:13 -0800473
474/**
475 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
476 * OperatingConfig D-Bus property.
477 *
478 * @param[in,out] aResp Async HTTP response.
479 * @param[in] baseSpeedSettings Full list of base speed priority groups,
480 * to use to determine the list of high
481 * speed cores.
482 */
483inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800484 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800485 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
486{
487 // The D-Bus property does not indicate which bucket is the "high
488 // priority" group, so let's discern that by looking for the one with
489 // highest base frequency.
490 auto highPriorityGroup = baseSpeedSettings.cend();
491 uint32_t highestBaseSpeed = 0;
492 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
493 ++it)
494 {
495 const uint32_t baseFreq = std::get<uint32_t>(*it);
496 if (baseFreq > highestBaseSpeed)
497 {
498 highestBaseSpeed = baseFreq;
499 highPriorityGroup = it;
500 }
501 }
502
503 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
504 jsonCoreIds = nlohmann::json::array();
505
506 // There may not be any entries in the D-Bus property, so only populate
507 // if there was actually something there.
508 if (highPriorityGroup != baseSpeedSettings.cend())
509 {
510 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
511 }
512}
513
514/**
515 * Fill out OperatingConfig related items in a Processor resource by requesting
516 * data from the given D-Bus object.
517 *
518 * @param[in,out] aResp Async HTTP response.
519 * @param[in] cpuId CPU D-Bus name.
520 * @param[in] service D-Bus service to query.
521 * @param[in] objPath D-Bus object to query.
522 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800523inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800524 const std::string& cpuId,
525 const std::string& service,
526 const std::string& objPath)
527{
528 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
529
530 // First, GetAll CurrentOperatingConfig properties on the object
531 crow::connections::systemBus->async_method_call(
532 [aResp, cpuId, service](
533 const boost::system::error_code ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800534 const std::vector<std::pair<
535 std::string, dbus::utility::DbusVariantType>>& properties) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800536 if (ec)
537 {
538 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
539 << ec.message();
540 messages::internalError(aResp->res);
541 return;
542 }
543
544 nlohmann::json& json = aResp->res.jsonValue;
545
546 for (const auto& [dbusPropName, variantVal] : properties)
547 {
548 if (dbusPropName == "AppliedConfig")
549 {
550 const sdbusplus::message::object_path* dbusPathWrapper =
551 std::get_if<sdbusplus::message::object_path>(
552 &variantVal);
553 if (dbusPathWrapper == nullptr)
554 {
555 continue;
556 }
557
558 const std::string& dbusPath = dbusPathWrapper->str;
559 std::string uri = "/redfish/v1/Systems/system/Processors/" +
560 cpuId + "/OperatingConfigs";
561 json["OperatingConfigs"] = {{"@odata.id", uri}};
562
563 // Reuse the D-Bus config object name for the Redfish
564 // URI
565 size_t baseNamePos = dbusPath.rfind('/');
566 if (baseNamePos == std::string::npos ||
567 baseNamePos == (dbusPath.size() - 1))
568 {
569 // If the AppliedConfig was somehow not a valid path,
570 // skip adding any more properties, since everything
571 // else is tied to this applied config.
572 messages::internalError(aResp->res);
573 break;
574 }
575 uri += '/';
576 uri += dbusPath.substr(baseNamePos + 1);
577 json["AppliedOperatingConfig"] = {{"@odata.id", uri}};
578
579 // Once we found the current applied config, queue another
580 // request to read the base freq core ids out of that
581 // config.
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700582 sdbusplus::asio::getProperty<
583 BaseSpeedPrioritySettingsProperty>(
584 *crow::connections::systemBus, service, dbusPath,
585 "xyz.openbmc_project.Inventory.Item.Cpu."
586 "OperatingConfig",
587 "BaseSpeedPrioritySettings",
588 [aResp](const boost::system::error_code ec,
589 const BaseSpeedPrioritySettingsProperty&
590 baseSpeedList) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800591 if (ec)
592 {
593 BMCWEB_LOG_WARNING
594 << "D-Bus Property Get error: " << ec;
595 messages::internalError(aResp->res);
596 return;
597 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700598
599 highSpeedCoreIdsHandler(aResp, baseSpeedList);
600 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800601 }
602 else if (dbusPropName == "BaseSpeedPriorityEnabled")
603 {
604 const bool* state = std::get_if<bool>(&variantVal);
605 if (state != nullptr)
606 {
607 json["BaseSpeedPriorityState"] =
608 *state ? "Enabled" : "Disabled";
609 }
610 }
611 }
612 },
613 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
614 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
615}
616
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600617/**
618 * @brief Fill out location info of a processor by
619 * requesting data from the given D-Bus object.
620 *
621 * @param[in,out] aResp Async HTTP response.
622 * @param[in] service D-Bus service to query.
623 * @param[in] objPath D-Bus object to query.
624 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800625inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600626 const std::string& service,
627 const std::string& objPath)
628{
629 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700630 sdbusplus::asio::getProperty<std::string>(
631 *crow::connections::systemBus, service, objPath,
632 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
633 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
634 const std::string& property) {
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600635 if (ec)
636 {
637 BMCWEB_LOG_DEBUG << "DBUS response error";
638 messages::internalError(aResp->res);
639 return;
640 }
641
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600642 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700643 property;
644 });
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600645}
646
Jonathan Domanc9514482021-02-24 09:20:51 -0800647/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800648 * Populate the unique identifier in a Processor resource by requesting data
649 * from the given D-Bus object.
650 *
651 * @param[in,out] aResp Async HTTP response.
652 * @param[in] service D-Bus service to query.
653 * @param[in] objPath D-Bus object to query.
654 */
655inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
656 const std::string& service,
657 const std::string& objectPath)
658{
659 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700660 sdbusplus::asio::getProperty<std::string>(
661 *crow::connections::systemBus, service, objectPath,
662 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
663 "UniqueIdentifier",
664 [aResp](boost::system::error_code ec, const std::string& id) {
665 if (ec)
Jonathan Doman49e429c2021-03-03 13:11:44 -0800666 {
667 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
668 messages::internalError(aResp->res);
669 return;
670 }
671 aResp->res
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700672 .jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] = id;
673 });
Jonathan Doman49e429c2021-03-03 13:11:44 -0800674}
675
676/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800677 * Find the D-Bus object representing the requested Processor, and call the
678 * handler with the results. If matching object is not found, add 404 error to
679 * response and don't call the handler.
680 *
681 * @param[in,out] resp Async HTTP response.
682 * @param[in] processorId Redfish Processor Id.
683 * @param[in] handler Callback to continue processing request upon
684 * successfully finding object.
685 */
686template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800687inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800688 const std::string& processorId,
689 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500690{
691 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
692
Jonathan Domanc9514482021-02-24 09:20:51 -0800693 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500694 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800695 [resp, processorId, handler = std::forward<Handler>(handler)](
696 boost::system::error_code ec,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600697 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500698 if (ec)
699 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800700 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
701 messages::internalError(resp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500702 return;
703 }
Jonathan Doman2bab9832020-12-02 15:27:40 -0800704 for (const auto& [objectPath, serviceMap] : subtree)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500705 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800706 // Ignore any objects which don't end with our desired cpu name
707 if (!boost::ends_with(objectPath, processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500708 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800709 continue;
710 }
711
Jonathan Domanc9514482021-02-24 09:20:51 -0800712 bool found = false;
713 // Filter out objects that don't have the CPU-specific
714 // interfaces to make sure we can return 404 on non-CPUs
715 // (e.g. /redfish/../Processors/dimm0)
Jonathan Doman2bab9832020-12-02 15:27:40 -0800716 for (const auto& [serviceName, interfaceList] : serviceMap)
717 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800718 if (std::find_first_of(
719 interfaceList.begin(), interfaceList.end(),
720 processorInterfaces.begin(),
721 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500722 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800723 found = true;
724 break;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500725 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500726 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800727
728 if (!found)
729 {
730 continue;
731 }
732
733 // Process the first object which does match our cpu name and
734 // required interfaces, and potentially ignore any other
735 // matching objects. Assume all interfaces we want to process
736 // must be on the same object path.
737
738 handler(resp, processorId, objectPath, serviceMap);
Jonathan Doman2bab9832020-12-02 15:27:40 -0800739 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500740 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800741 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500742 },
743 "xyz.openbmc_project.ObjectMapper",
744 "/xyz/openbmc_project/object_mapper",
745 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800746 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800747 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530748 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800749 "xyz.openbmc_project.Inventory.Decorator.Asset",
750 "xyz.openbmc_project.Inventory.Decorator.Revision",
751 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600752 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800753 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800754 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
755 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500756}
757
zhanghch058d1b46d2021-04-01 11:18:24 +0800758inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800759 const std::string& processorId,
760 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600761 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Domanc9514482021-02-24 09:20:51 -0800762{
763 for (const auto& [serviceName, interfaceList] : serviceMap)
764 {
765 for (const auto& interface : interfaceList)
766 {
767 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
768 {
769 getCpuAssetData(aResp, serviceName, objectPath);
770 }
George Liu0fda0f12021-11-16 10:06:17 +0800771 else if (interface ==
772 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800773 {
774 getCpuRevisionData(aResp, serviceName, objectPath);
775 }
776 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
777 {
778 getCpuDataByService(aResp, processorId, serviceName,
779 objectPath);
780 }
George Liu0fda0f12021-11-16 10:06:17 +0800781 else if (interface ==
782 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800783 {
784 getAcceleratorDataByService(aResp, processorId, serviceName,
785 objectPath);
786 }
George Liu0fda0f12021-11-16 10:06:17 +0800787 else if (
788 interface ==
789 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800790 {
791 getCpuConfigData(aResp, processorId, serviceName, objectPath);
792 }
George Liu0fda0f12021-11-16 10:06:17 +0800793 else if (interface ==
794 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800795 {
796 getCpuLocationCode(aResp, serviceName, objectPath);
797 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530798 else if (interface == "xyz.openbmc_project.Common.UUID")
799 {
800 getProcessorUUID(aResp, serviceName, objectPath);
801 }
George Liu0fda0f12021-11-16 10:06:17 +0800802 else if (interface ==
803 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800804 {
805 getCpuUniqueId(aResp, serviceName, objectPath);
806 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800807 }
808 }
809}
810
Jonathan Domandba0c292020-12-02 15:34:13 -0800811/**
812 * Request all the properties for the given D-Bus object and fill out the
813 * related entries in the Redfish OperatingConfig response.
814 *
815 * @param[in,out] aResp Async HTTP response.
816 * @param[in] service D-Bus service name to query.
817 * @param[in] objPath D-Bus object to query.
818 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800819inline void
820 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
821 const std::string& service,
822 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800823{
824 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -0800825 [aResp](const boost::system::error_code ec,
Jonathan Domandba0c292020-12-02 15:34:13 -0800826 const OperatingConfigProperties& properties) {
827 if (ec)
828 {
829 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
830 << ec.message();
831 messages::internalError(aResp->res);
832 return;
833 }
834
835 nlohmann::json& json = aResp->res.jsonValue;
836 for (const auto& [key, variant] : properties)
837 {
838 if (key == "AvailableCoreCount")
839 {
840 const size_t* cores = std::get_if<size_t>(&variant);
841 if (cores != nullptr)
842 {
843 json["TotalAvailableCoreCount"] = *cores;
844 }
845 }
846 else if (key == "BaseSpeed")
847 {
848 const uint32_t* speed = std::get_if<uint32_t>(&variant);
849 if (speed != nullptr)
850 {
851 json["BaseSpeedMHz"] = *speed;
852 }
853 }
854 else if (key == "MaxJunctionTemperature")
855 {
856 const uint32_t* temp = std::get_if<uint32_t>(&variant);
857 if (temp != nullptr)
858 {
859 json["MaxJunctionTemperatureCelsius"] = *temp;
860 }
861 }
862 else if (key == "MaxSpeed")
863 {
864 const uint32_t* speed = std::get_if<uint32_t>(&variant);
865 if (speed != nullptr)
866 {
867 json["MaxSpeedMHz"] = *speed;
868 }
869 }
870 else if (key == "PowerLimit")
871 {
872 const uint32_t* tdp = std::get_if<uint32_t>(&variant);
873 if (tdp != nullptr)
874 {
875 json["TDPWatts"] = *tdp;
876 }
877 }
878 else if (key == "TurboProfile")
879 {
880 const auto* turboList =
881 std::get_if<TurboProfileProperty>(&variant);
882 if (turboList == nullptr)
883 {
884 continue;
885 }
886
887 nlohmann::json& turboArray = json["TurboProfile"];
888 turboArray = nlohmann::json::array();
889 for (const auto& [turboSpeed, coreCount] : *turboList)
890 {
891 turboArray.push_back({{"ActiveCoreCount", coreCount},
892 {"MaxSpeedMHz", turboSpeed}});
893 }
894 }
895 else if (key == "BaseSpeedPrioritySettings")
896 {
897 const auto* baseSpeedList =
898 std::get_if<BaseSpeedPrioritySettingsProperty>(
899 &variant);
900 if (baseSpeedList == nullptr)
901 {
902 continue;
903 }
904
905 nlohmann::json& baseSpeedArray =
906 json["BaseSpeedPrioritySettings"];
907 baseSpeedArray = nlohmann::json::array();
908 for (const auto& [baseSpeed, coreList] : *baseSpeedList)
909 {
910 baseSpeedArray.push_back(
911 {{"CoreCount", coreList.size()},
912 {"CoreIDs", coreList},
913 {"BaseSpeedMHz", baseSpeed}});
914 }
915 }
916 }
917 },
918 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
919 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig");
920}
921
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800922/**
923 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
924 * property. Main task is to translate error messages into Redfish errors.
925 *
926 * @param[in,out] resp HTTP response.
927 * @param[in] setPropVal Value which we attempted to set.
928 * @param[in] ec D-Bus response error code.
929 * @param[in] msg D-Bus response message.
930 */
931inline void
932 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
933 const std::string& setPropVal,
934 boost::system::error_code ec,
935 const sdbusplus::message::message& msg)
936{
937 if (!ec)
938 {
939 BMCWEB_LOG_DEBUG << "Set Property succeeded";
940 return;
941 }
942
943 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
944
945 const sd_bus_error* dbusError = msg.get_error();
946 if (dbusError == nullptr)
947 {
948 messages::internalError(resp->res);
949 return;
950 }
951
952 // The asio error code doesn't know about our custom errors, so we have to
953 // parse the error string. Some of these D-Bus -> Redfish translations are a
954 // stretch, but it's good to try to communicate something vaguely useful.
955 if (strcmp(dbusError->name,
956 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
957 {
958 // Service did not like the object_path we tried to set.
959 messages::propertyValueIncorrect(
960 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
961 }
962 else if (strcmp(dbusError->name,
963 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
964 {
965 // Service indicates we can never change the config for this processor.
966 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
967 }
968 else if (strcmp(dbusError->name,
969 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
970 {
971 // Service indicates the config cannot be changed right now, but maybe
972 // in a different system state.
973 messages::resourceInStandby(resp->res);
974 }
975 else if (strcmp(dbusError->name,
976 "xyz.openbmc_project.Common.Device.Error.WriteFailure") ==
977 0)
978 {
979 // Service tried to change the config, but it failed.
980 messages::operationFailed(resp->res);
981 }
982 else
983 {
984 messages::internalError(resp->res);
985 }
986}
987
988/**
989 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
990 * validation of the input data, and then set the D-Bus property.
991 *
992 * @param[in,out] resp Async HTTP response.
993 * @param[in] processorId Processor's Id.
994 * @param[in] appliedConfigUri New property value to apply.
995 * @param[in] cpuObjectPath Path of CPU object to modify.
996 * @param[in] serviceMap Service map for CPU object.
997 */
998inline void patchAppliedOperatingConfig(
999 const std::shared_ptr<bmcweb::AsyncResp>& resp,
1000 const std::string& processorId, const std::string& appliedConfigUri,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001001 const std::string& cpuObjectPath,
1002 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001003{
1004 // Check that the property even exists by checking for the interface
1005 const std::string* controlService = nullptr;
1006 for (const auto& [serviceName, interfaceList] : serviceMap)
1007 {
1008 if (std::find(interfaceList.begin(), interfaceList.end(),
1009 "xyz.openbmc_project.Control.Processor."
1010 "CurrentOperatingConfig") != interfaceList.end())
1011 {
1012 controlService = &serviceName;
1013 break;
1014 }
1015 }
1016
1017 if (controlService == nullptr)
1018 {
1019 messages::internalError(resp->res);
1020 return;
1021 }
1022
1023 // Check that the config URI is a child of the cpu URI being patched.
1024 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
1025 expectedPrefix += processorId;
1026 expectedPrefix += "/OperatingConfigs/";
1027 if (!boost::starts_with(appliedConfigUri, expectedPrefix) ||
1028 expectedPrefix.size() == appliedConfigUri.size())
1029 {
1030 messages::propertyValueIncorrect(
1031 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1032 return;
1033 }
1034
1035 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1036 // direct child of the CPU object.
1037 // Strip the expectedPrefix from the config URI to get the "filename", and
1038 // append to the CPU's path.
1039 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1040 sdbusplus::message::object_path configPath(cpuObjectPath);
1041 configPath /= configBaseName;
1042
1043 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1044
1045 // Set the property, with handler to check error responses
1046 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -08001047 [resp, appliedConfigUri](const boost::system::error_code ec,
1048 const sdbusplus::message::message& msg) {
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001049 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
1050 },
1051 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1052 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
Ed Tanous168e20c2021-12-13 14:39:53 -08001053 "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001054}
1055
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001056inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001057{
Jonathan Domandba0c292020-12-02 15:34:13 -08001058
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001059 BMCWEB_ROUTE(
1060 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001061 .privileges(redfish::privileges::getOperatingConfigCollection)
George Liu0fda0f12021-11-16 10:06:17 +08001062 .methods(
1063 boost::beast::http::verb::get)([](const crow::Request& req,
1064 const std::shared_ptr<
1065 bmcweb::AsyncResp>& asyncResp,
1066 const std::string& cpuName) {
1067 asyncResp->res.jsonValue["@odata.type"] =
1068 "#OperatingConfigCollection.OperatingConfigCollection";
1069 asyncResp->res.jsonValue["@odata.id"] = req.url;
1070 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
Jonathan Domandba0c292020-12-02 15:34:13 -08001071
George Liu0fda0f12021-11-16 10:06:17 +08001072 // First find the matching CPU object so we know how to
1073 // constrain our search for related Config objects.
1074 crow::connections::systemBus->async_method_call(
1075 [asyncResp, cpuName](const boost::system::error_code ec,
1076 const std::vector<std::string>& objects) {
1077 if (ec)
1078 {
1079 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1080 << ec.message();
1081 messages::internalError(asyncResp->res);
1082 return;
1083 }
1084
1085 for (const std::string& object : objects)
1086 {
1087 if (!boost::ends_with(object, cpuName))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001088 {
George Liu0fda0f12021-11-16 10:06:17 +08001089 continue;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001090 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001091
George Liu0fda0f12021-11-16 10:06:17 +08001092 // Not expected that there will be multiple matching
1093 // CPU objects, but if there are just use the first
1094 // one.
Jonathan Domandba0c292020-12-02 15:34:13 -08001095
George Liu0fda0f12021-11-16 10:06:17 +08001096 // Use the common search routine to construct the
1097 // Collection of all Config objects under this CPU.
1098 collection_util::getCollectionMembers(
1099 asyncResp,
1100 "/redfish/v1/Systems/system/Processors/" + cpuName +
1101 "/OperatingConfigs",
1102 {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1103 object.c_str());
1104 return;
1105 }
1106 },
1107 "xyz.openbmc_project.ObjectMapper",
1108 "/xyz/openbmc_project/object_mapper",
1109 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1110 "/xyz/openbmc_project/inventory", 0,
1111 std::array<const char*, 1>{
1112 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
1113 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001114}
1115
1116inline void requestRoutesOperatingConfig(App& app)
1117{
1118 BMCWEB_ROUTE(
1119 app,
1120 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001121 .privileges(redfish::privileges::getOperatingConfig)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001122 .methods(
1123 boost::beast::http::verb::get)([](const crow::Request& req,
1124 const std::shared_ptr<
1125 bmcweb::AsyncResp>& asyncResp,
1126 const std::string& cpuName,
1127 const std::string& configName) {
1128 // Ask for all objects implementing OperatingConfig so we can search
1129 // for one with a matching name
1130 crow::connections::systemBus->async_method_call(
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001131 [asyncResp, cpuName, configName, reqUrl{req.url}](
1132 boost::system::error_code ec,
1133 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001134 if (ec)
Jonathan Domandba0c292020-12-02 15:34:13 -08001135 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001136 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1137 << ec.message();
1138 messages::internalError(asyncResp->res);
1139 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001140 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001141 const std::string expectedEnding =
1142 cpuName + '/' + configName;
1143 for (const auto& [objectPath, serviceMap] : subtree)
Jonathan Domandba0c292020-12-02 15:34:13 -08001144 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001145 // Ignore any configs without matching cpuX/configY
1146 if (!boost::ends_with(objectPath, expectedEnding) ||
1147 serviceMap.empty())
1148 {
1149 continue;
1150 }
1151
1152 nlohmann::json& json = asyncResp->res.jsonValue;
1153 json["@odata.type"] =
1154 "#OperatingConfig.v1_0_0.OperatingConfig";
1155 json["@odata.id"] = reqUrl;
1156 json["Name"] = "Processor Profile";
1157 json["Id"] = configName;
1158
1159 // Just use the first implementation of the object - not
1160 // expected that there would be multiple matching
1161 // services
1162 getOperatingConfigData(
1163 asyncResp, serviceMap.begin()->first, objectPath);
1164 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001165 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001166 messages::resourceNotFound(asyncResp->res,
1167 "OperatingConfig", configName);
1168 },
1169 "xyz.openbmc_project.ObjectMapper",
1170 "/xyz/openbmc_project/object_mapper",
1171 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1172 "/xyz/openbmc_project/inventory", 0,
1173 std::array<const char*, 1>{
1174 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
1175 });
1176}
Jonathan Domandba0c292020-12-02 15:34:13 -08001177
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001178inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001179{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001180 /**
1181 * Functions triggers appropriate requests on DBus
1182 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001183 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001184 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001185 .methods(boost::beast::http::verb::get)(
1186 [](const crow::Request&,
1187 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1188 asyncResp->res.jsonValue["@odata.type"] =
1189 "#ProcessorCollection.ProcessorCollection";
1190 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001191
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001192 asyncResp->res.jsonValue["@odata.id"] =
1193 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001194
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001195 collection_util::getCollectionMembers(
1196 asyncResp, "/redfish/v1/Systems/system/Processors",
1197 std::vector<const char*>(processorInterfaces.begin(),
1198 processorInterfaces.end()));
1199 });
1200}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001201
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001202inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001203{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001204 /**
1205 * Functions triggers appropriate requests on DBus
1206 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001207
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001208 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001209 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001210 .methods(boost::beast::http::verb::get)(
1211 [](const crow::Request&,
1212 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1213 const std::string& processorId) {
1214 asyncResp->res.jsonValue["@odata.type"] =
1215 "#Processor.v1_11_0.Processor";
1216 asyncResp->res.jsonValue["@odata.id"] =
1217 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001218
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219 getProcessorObject(asyncResp, processorId, getProcessorData);
1220 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001221
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001222 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001223 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001224 .methods(boost::beast::http::verb::patch)(
1225 [](const crow::Request& req,
1226 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1227 const std::string& processorId) {
1228 std::optional<nlohmann::json> appliedConfigJson;
1229 if (!json_util::readJson(req, asyncResp->res,
1230 "AppliedOperatingConfig",
1231 appliedConfigJson))
1232 {
1233 return;
1234 }
1235
1236 std::string appliedConfigUri;
1237 if (appliedConfigJson)
1238 {
1239 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1240 "@odata.id", appliedConfigUri))
1241 {
1242 return;
1243 }
1244 // Check for 404 and find matching D-Bus object, then run
1245 // property patch handlers if that all succeeds.
1246 getProcessorObject(
1247 asyncResp, processorId,
1248 [appliedConfigUri = std::move(appliedConfigUri)](
1249 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1250 const std::string& processorId,
1251 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001252 const dbus::utility::MapperServiceMap& serviceMap) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001253 patchAppliedOperatingConfig(asyncResp, processorId,
1254 appliedConfigUri,
1255 objectPath, serviceMap);
1256 });
1257 }
1258 });
1259}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001260
1261} // namespace redfish