blob: 2a0e028b87c800a81adbcb554a3c304ee546eb11 [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 Tanous45ca1b82022-03-25 13:07:27 -070025#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070026#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070027#include <sdbusplus/asio/property.hpp>
Jonathan Domandba0c292020-12-02 15:34:13 -080028#include <sdbusplus/message/native_types.hpp>
29#include <sdbusplus/utility/dedup_variant.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050030#include <utils/collection.hpp>
31#include <utils/json_utils.hpp>
32
33namespace redfish
34{
35
Jonathan Domanc9514482021-02-24 09:20:51 -080036// Interfaces which imply a D-Bus object represents a Processor
37constexpr std::array<const char*, 2> processorInterfaces = {
38 "xyz.openbmc_project.Inventory.Item.Cpu",
39 "xyz.openbmc_project.Inventory.Item.Accelerator"};
Jonathan Doman2bab9832020-12-02 15:27:40 -080040
Sharad Yadav71b82f22021-05-10 15:11:39 +053041/**
42 * @brief Fill out uuid info of a processor by
43 * requesting data from the given D-Bus object.
44 *
45 * @param[in,out] aResp Async HTTP response.
46 * @param[in] service D-Bus service to query.
47 * @param[in] objPath D-Bus object to query.
48 */
49inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp,
50 const std::string& service,
51 const std::string& objPath)
52{
53 BMCWEB_LOG_DEBUG << "Get Processor UUID";
Jonathan Doman1e1e5982021-06-11 09:36:17 -070054 sdbusplus::asio::getProperty<std::string>(
55 *crow::connections::systemBus, service, objPath,
56 "xyz.openbmc_project.Common.UUID", "UUID",
57 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
58 const std::string& property) {
Sharad Yadav71b82f22021-05-10 15:11:39 +053059 if (ec)
60 {
61 BMCWEB_LOG_DEBUG << "DBUS response error";
62 messages::internalError(aResp->res);
63 return;
64 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -070065 aResp->res.jsonValue["UUID"] = property;
66 });
Sharad Yadav71b82f22021-05-10 15:11:39 +053067}
68
Ed Tanous711ac7a2021-12-20 09:34:41 -080069inline void getCpuDataByInterface(
70 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
71 const dbus::utility::DBusInteracesMap& cpuInterfacesProperties)
Gunnar Millsac6a4442020-10-14 14:55:29 -050072{
73 BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
74
Chicago Duana1649ec2021-03-30 16:54:58 +080075 // Set the default value of state
76 aResp->res.jsonValue["Status"]["State"] = "Enabled";
77 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -050078
79 for (const auto& interface : cpuInterfacesProperties)
80 {
81 for (const auto& property : interface.second)
82 {
Chicago Duana1649ec2021-03-30 16:54:58 +080083 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -050084 {
Chicago Duana1649ec2021-03-30 16:54:58 +080085 const bool* cpuPresent = std::get_if<bool>(&property.second);
86 if (cpuPresent == nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -050087 {
88 // Important property not in desired type
89 messages::internalError(aResp->res);
90 return;
91 }
Ed Tanouse05aec52022-01-25 10:28:56 -080092 if (!*cpuPresent)
Gunnar Millsac6a4442020-10-14 14:55:29 -050093 {
Chicago Duana1649ec2021-03-30 16:54:58 +080094 // Slot is not populated
Gunnar Millsac6a4442020-10-14 14:55:29 -050095 aResp->res.jsonValue["Status"]["State"] = "Absent";
Chicago Duana1649ec2021-03-30 16:54:58 +080096 }
97 }
98 else if (property.first == "Functional")
99 {
100 const bool* cpuFunctional = std::get_if<bool>(&property.second);
101 if (cpuFunctional == nullptr)
102 {
103 messages::internalError(aResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500104 return;
105 }
Ed Tanouse05aec52022-01-25 10:28:56 -0800106 if (!*cpuFunctional)
Chicago Duana1649ec2021-03-30 16:54:58 +0800107 {
108 aResp->res.jsonValue["Status"]["Health"] = "Critical";
109 }
110 }
111 else if (property.first == "CoreCount")
112 {
113 const uint16_t* coresCount =
114 std::get_if<uint16_t>(&property.second);
115 if (coresCount == nullptr)
116 {
117 messages::internalError(aResp->res);
118 return;
119 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500120 aResp->res.jsonValue["TotalCores"] = *coresCount;
121 }
Jonathan Domandc3fa662020-10-26 23:10:24 -0700122 else if (property.first == "MaxSpeedInMhz")
123 {
124 const uint32_t* value = std::get_if<uint32_t>(&property.second);
125 if (value != nullptr)
126 {
127 aResp->res.jsonValue["MaxSpeedMHz"] = *value;
128 }
129 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500130 else if (property.first == "Socket")
131 {
132 const std::string* value =
133 std::get_if<std::string>(&property.second);
134 if (value != nullptr)
135 {
136 aResp->res.jsonValue["Socket"] = *value;
137 }
138 }
139 else if (property.first == "ThreadCount")
140 {
Jonathan Domandc3fa662020-10-26 23:10:24 -0700141 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500142 if (value != nullptr)
143 {
144 aResp->res.jsonValue["TotalThreads"] = *value;
145 }
146 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700147 else if (property.first == "EffectiveFamily")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500148 {
Brandon Kim1930fbd2021-09-14 17:52:51 -0700149 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500150 if (value != nullptr)
151 {
152 aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800153 "0x" + intToHexString(*value, 4);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500154 }
155 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700156 else if (property.first == "EffectiveModel")
157 {
158 const uint16_t* value = std::get_if<uint16_t>(&property.second);
159 if (value == nullptr)
160 {
161 messages::internalError(aResp->res);
162 return;
163 }
164 aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800165 "0x" + intToHexString(*value, 4);
Brandon Kim1930fbd2021-09-14 17:52:51 -0700166 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500167 else if (property.first == "Id")
168 {
169 const uint64_t* value = std::get_if<uint64_t>(&property.second);
170 if (value != nullptr && *value != 0)
171 {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500172 aResp->res
173 .jsonValue["ProcessorId"]["IdentificationRegisters"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800174 "0x" + intToHexString(*value, 16);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500175 }
176 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700177 else if (property.first == "Microcode")
178 {
179 const uint32_t* value = std::get_if<uint32_t>(&property.second);
180 if (value == nullptr)
181 {
182 messages::internalError(aResp->res);
183 return;
184 }
185 aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800186 "0x" + intToHexString(*value, 8);
Brandon Kim1930fbd2021-09-14 17:52:51 -0700187 }
188 else if (property.first == "Step")
189 {
190 const uint16_t* value = std::get_if<uint16_t>(&property.second);
191 if (value == nullptr)
192 {
193 messages::internalError(aResp->res);
194 return;
195 }
196 aResp->res.jsonValue["ProcessorId"]["Step"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800197 "0x" + intToHexString(*value, 4);
Brandon Kim1930fbd2021-09-14 17:52:51 -0700198 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500199 }
200 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500201}
202
zhanghch058d1b46d2021-04-01 11:18:24 +0800203inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500204 const std::string& cpuId,
205 const std::string& service,
206 const std::string& objPath)
207{
208 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
209
210 crow::connections::systemBus->async_method_call(
211 [cpuId, service, objPath, aResp{std::move(aResp)}](
212 const boost::system::error_code ec,
213 const dbus::utility::ManagedObjectType& dbusData) {
214 if (ec)
215 {
216 BMCWEB_LOG_DEBUG << "DBUS response error";
217 messages::internalError(aResp->res);
218 return;
219 }
220 aResp->res.jsonValue["Id"] = cpuId;
221 aResp->res.jsonValue["Name"] = "Processor";
222 aResp->res.jsonValue["ProcessorType"] = "CPU";
223
224 bool slotPresent = false;
225 std::string corePath = objPath + "/core";
226 size_t totalCores = 0;
227 for (const auto& object : dbusData)
228 {
229 if (object.first.str == objPath)
230 {
231 getCpuDataByInterface(aResp, object.second);
232 }
233 else if (boost::starts_with(object.first.str, corePath))
234 {
235 for (const auto& interface : object.second)
236 {
237 if (interface.first ==
238 "xyz.openbmc_project.Inventory.Item")
239 {
240 for (const auto& property : interface.second)
241 {
242 if (property.first == "Present")
243 {
244 const bool* present =
245 std::get_if<bool>(&property.second);
246 if (present != nullptr)
247 {
Ed Tanouse05aec52022-01-25 10:28:56 -0800248 if (*present)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500249 {
250 slotPresent = true;
251 totalCores++;
252 }
253 }
254 }
255 }
256 }
257 }
258 }
259 }
260 // In getCpuDataByInterface(), state and health are set
261 // based on the present and functional status. If core
262 // count is zero, then it has a higher precedence.
263 if (slotPresent)
264 {
265 if (totalCores == 0)
266 {
267 // Slot is not populated, set status end return
268 aResp->res.jsonValue["Status"]["State"] = "Absent";
269 aResp->res.jsonValue["Status"]["Health"] = "OK";
270 }
271 aResp->res.jsonValue["TotalCores"] = totalCores;
272 }
273 return;
274 },
275 service, "/xyz/openbmc_project/inventory",
276 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
277}
278
zhanghch058d1b46d2021-04-01 11:18:24 +0800279inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500280 const std::string& service,
281 const std::string& objPath)
282{
283 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
284 crow::connections::systemBus->async_method_call(
285 [objPath, aResp{std::move(aResp)}](
286 const boost::system::error_code ec,
287 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800288 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500289 if (ec)
290 {
291 BMCWEB_LOG_DEBUG << "DBUS response error";
292 messages::internalError(aResp->res);
293 return;
294 }
295
296 for (const auto& property : properties)
297 {
298 if (property.first == "SerialNumber")
299 {
300 const std::string* sn =
301 std::get_if<std::string>(&property.second);
302 if (sn != nullptr && !sn->empty())
303 {
304 aResp->res.jsonValue["SerialNumber"] = *sn;
305 }
306 }
307 else if (property.first == "Model")
308 {
309 const std::string* model =
310 std::get_if<std::string>(&property.second);
311 if (model != nullptr && !model->empty())
312 {
313 aResp->res.jsonValue["Model"] = *model;
314 }
315 }
316 else if (property.first == "Manufacturer")
317 {
318
319 const std::string* mfg =
320 std::get_if<std::string>(&property.second);
321 if (mfg != nullptr)
322 {
323 aResp->res.jsonValue["Manufacturer"] = *mfg;
324
325 // Otherwise would be unexpected.
326 if (mfg->find("Intel") != std::string::npos)
327 {
328 aResp->res.jsonValue["ProcessorArchitecture"] =
329 "x86";
330 aResp->res.jsonValue["InstructionSet"] = "x86-64";
331 }
332 else if (mfg->find("IBM") != std::string::npos)
333 {
334 aResp->res.jsonValue["ProcessorArchitecture"] =
335 "Power";
336 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
337 }
338 }
339 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600340 else if (property.first == "PartNumber")
341 {
342 const std::string* partNumber =
343 std::get_if<std::string>(&property.second);
344
345 if (partNumber == nullptr)
346 {
347 messages::internalError(aResp->res);
348 return;
349 }
350 aResp->res.jsonValue["PartNumber"] = *partNumber;
351 }
352 else if (property.first == "SparePartNumber")
353 {
354 const std::string* sparePartNumber =
355 std::get_if<std::string>(&property.second);
356
357 if (sparePartNumber == nullptr)
358 {
359 messages::internalError(aResp->res);
360 return;
361 }
362 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
363 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500364 }
365 },
366 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
367 "xyz.openbmc_project.Inventory.Decorator.Asset");
368}
369
zhanghch058d1b46d2021-04-01 11:18:24 +0800370inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500371 const std::string& service,
372 const std::string& objPath)
373{
374 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
375 crow::connections::systemBus->async_method_call(
376 [objPath, aResp{std::move(aResp)}](
377 const boost::system::error_code ec,
378 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800379 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500380 if (ec)
381 {
382 BMCWEB_LOG_DEBUG << "DBUS response error";
383 messages::internalError(aResp->res);
384 return;
385 }
386
387 for (const auto& property : properties)
388 {
389 if (property.first == "Version")
390 {
391 const std::string* ver =
392 std::get_if<std::string>(&property.second);
393 if (ver != nullptr)
394 {
395 aResp->res.jsonValue["Version"] = *ver;
396 }
397 break;
398 }
399 }
400 },
401 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
402 "xyz.openbmc_project.Inventory.Decorator.Revision");
403}
404
zhanghch058d1b46d2021-04-01 11:18:24 +0800405inline void getAcceleratorDataByService(
406 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
407 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500408{
409 BMCWEB_LOG_DEBUG
410 << "Get available system Accelerator resources by service.";
411 crow::connections::systemBus->async_method_call(
412 [acclrtrId, aResp{std::move(aResp)}](
413 const boost::system::error_code ec,
414 const boost::container::flat_map<
Ed Tanous168e20c2021-12-13 14:39:53 -0800415 std::string, dbus::utility::DbusVariantType>& properties) {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500416 if (ec)
417 {
418 BMCWEB_LOG_DEBUG << "DBUS response error";
419 messages::internalError(aResp->res);
420 return;
421 }
422 aResp->res.jsonValue["Id"] = acclrtrId;
423 aResp->res.jsonValue["Name"] = "Processor";
424 const bool* accPresent = nullptr;
425 const bool* accFunctional = nullptr;
426
427 for (const auto& property : properties)
428 {
429 if (property.first == "Functional")
430 {
431 accFunctional = std::get_if<bool>(&property.second);
432 }
433 else if (property.first == "Present")
434 {
435 accPresent = std::get_if<bool>(&property.second);
436 }
437 }
438
439 std::string state = "Enabled";
440 std::string health = "OK";
441
Ed Tanouse05aec52022-01-25 10:28:56 -0800442 if (accPresent != nullptr && !*accPresent)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500443 {
444 state = "Absent";
445 }
446
Ed Tanouse05aec52022-01-25 10:28:56 -0800447 if ((accFunctional != nullptr) && !*accFunctional)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500448 {
449 if (state == "Enabled")
450 {
451 health = "Critical";
452 }
453 }
454
455 aResp->res.jsonValue["Status"]["State"] = state;
456 aResp->res.jsonValue["Status"]["Health"] = health;
457 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
458 },
459 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
460}
461
Jonathan Domandba0c292020-12-02 15:34:13 -0800462// OperatingConfig D-Bus Types
463using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
464using BaseSpeedPrioritySettingsProperty =
465 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
466// uint32_t and size_t may or may not be the same type, requiring a dedup'd
467// variant
Ed Tanous168e20c2021-12-13 14:39:53 -0800468using OperatingConfigProperties =
469 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>;
Jonathan Domandba0c292020-12-02 15:34:13 -0800470
471/**
472 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
473 * OperatingConfig D-Bus property.
474 *
475 * @param[in,out] aResp Async HTTP response.
476 * @param[in] baseSpeedSettings Full list of base speed priority groups,
477 * to use to determine the list of high
478 * speed cores.
479 */
480inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800481 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800482 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
483{
484 // The D-Bus property does not indicate which bucket is the "high
485 // priority" group, so let's discern that by looking for the one with
486 // highest base frequency.
487 auto highPriorityGroup = baseSpeedSettings.cend();
488 uint32_t highestBaseSpeed = 0;
489 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
490 ++it)
491 {
492 const uint32_t baseFreq = std::get<uint32_t>(*it);
493 if (baseFreq > highestBaseSpeed)
494 {
495 highestBaseSpeed = baseFreq;
496 highPriorityGroup = it;
497 }
498 }
499
500 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
501 jsonCoreIds = nlohmann::json::array();
502
503 // There may not be any entries in the D-Bus property, so only populate
504 // if there was actually something there.
505 if (highPriorityGroup != baseSpeedSettings.cend())
506 {
507 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
508 }
509}
510
511/**
512 * Fill out OperatingConfig related items in a Processor resource by requesting
513 * data from the given D-Bus object.
514 *
515 * @param[in,out] aResp Async HTTP response.
516 * @param[in] cpuId CPU D-Bus name.
517 * @param[in] service D-Bus service to query.
518 * @param[in] objPath D-Bus object to query.
519 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800520inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800521 const std::string& cpuId,
522 const std::string& service,
523 const std::string& objPath)
524{
525 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
526
527 // First, GetAll CurrentOperatingConfig properties on the object
528 crow::connections::systemBus->async_method_call(
529 [aResp, cpuId, service](
530 const boost::system::error_code ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800531 const std::vector<std::pair<
532 std::string, dbus::utility::DbusVariantType>>& properties) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800533 if (ec)
534 {
535 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
536 << ec.message();
537 messages::internalError(aResp->res);
538 return;
539 }
540
541 nlohmann::json& json = aResp->res.jsonValue;
542
543 for (const auto& [dbusPropName, variantVal] : properties)
544 {
545 if (dbusPropName == "AppliedConfig")
546 {
547 const sdbusplus::message::object_path* dbusPathWrapper =
548 std::get_if<sdbusplus::message::object_path>(
549 &variantVal);
550 if (dbusPathWrapper == nullptr)
551 {
552 continue;
553 }
554
555 const std::string& dbusPath = dbusPathWrapper->str;
556 std::string uri = "/redfish/v1/Systems/system/Processors/" +
557 cpuId + "/OperatingConfigs";
558 json["OperatingConfigs"] = {{"@odata.id", uri}};
559
560 // Reuse the D-Bus config object name for the Redfish
561 // URI
562 size_t baseNamePos = dbusPath.rfind('/');
563 if (baseNamePos == std::string::npos ||
564 baseNamePos == (dbusPath.size() - 1))
565 {
566 // If the AppliedConfig was somehow not a valid path,
567 // skip adding any more properties, since everything
568 // else is tied to this applied config.
569 messages::internalError(aResp->res);
570 break;
571 }
572 uri += '/';
573 uri += dbusPath.substr(baseNamePos + 1);
574 json["AppliedOperatingConfig"] = {{"@odata.id", uri}};
575
576 // Once we found the current applied config, queue another
577 // request to read the base freq core ids out of that
578 // config.
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700579 sdbusplus::asio::getProperty<
580 BaseSpeedPrioritySettingsProperty>(
581 *crow::connections::systemBus, service, dbusPath,
582 "xyz.openbmc_project.Inventory.Item.Cpu."
583 "OperatingConfig",
584 "BaseSpeedPrioritySettings",
585 [aResp](const boost::system::error_code ec,
586 const BaseSpeedPrioritySettingsProperty&
587 baseSpeedList) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800588 if (ec)
589 {
590 BMCWEB_LOG_WARNING
591 << "D-Bus Property Get error: " << ec;
592 messages::internalError(aResp->res);
593 return;
594 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700595
596 highSpeedCoreIdsHandler(aResp, baseSpeedList);
597 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800598 }
599 else if (dbusPropName == "BaseSpeedPriorityEnabled")
600 {
601 const bool* state = std::get_if<bool>(&variantVal);
602 if (state != nullptr)
603 {
604 json["BaseSpeedPriorityState"] =
605 *state ? "Enabled" : "Disabled";
606 }
607 }
608 }
609 },
610 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
611 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
612}
613
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600614/**
615 * @brief Fill out location info of a processor by
616 * requesting data from the given D-Bus object.
617 *
618 * @param[in,out] aResp Async HTTP response.
619 * @param[in] service D-Bus service to query.
620 * @param[in] objPath D-Bus object to query.
621 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800622inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600623 const std::string& service,
624 const std::string& objPath)
625{
626 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700627 sdbusplus::asio::getProperty<std::string>(
628 *crow::connections::systemBus, service, objPath,
629 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
630 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
631 const std::string& property) {
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600632 if (ec)
633 {
634 BMCWEB_LOG_DEBUG << "DBUS response error";
635 messages::internalError(aResp->res);
636 return;
637 }
638
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600639 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700640 property;
641 });
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600642}
643
Jonathan Domanc9514482021-02-24 09:20:51 -0800644/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800645 * Populate the unique identifier in a Processor resource by requesting data
646 * from the given D-Bus object.
647 *
648 * @param[in,out] aResp Async HTTP response.
649 * @param[in] service D-Bus service to query.
650 * @param[in] objPath D-Bus object to query.
651 */
652inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
653 const std::string& service,
654 const std::string& objectPath)
655{
656 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700657 sdbusplus::asio::getProperty<std::string>(
658 *crow::connections::systemBus, service, objectPath,
659 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
660 "UniqueIdentifier",
661 [aResp](boost::system::error_code ec, const std::string& id) {
662 if (ec)
Jonathan Doman49e429c2021-03-03 13:11:44 -0800663 {
664 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
665 messages::internalError(aResp->res);
666 return;
667 }
668 aResp->res
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700669 .jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] = id;
670 });
Jonathan Doman49e429c2021-03-03 13:11:44 -0800671}
672
673/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800674 * Find the D-Bus object representing the requested Processor, and call the
675 * handler with the results. If matching object is not found, add 404 error to
676 * response and don't call the handler.
677 *
678 * @param[in,out] resp Async HTTP response.
679 * @param[in] processorId Redfish Processor Id.
680 * @param[in] handler Callback to continue processing request upon
681 * successfully finding object.
682 */
683template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800684inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800685 const std::string& processorId,
686 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500687{
688 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
689
Jonathan Domanc9514482021-02-24 09:20:51 -0800690 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500691 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800692 [resp, processorId, handler = std::forward<Handler>(handler)](
693 boost::system::error_code ec,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600694 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500695 if (ec)
696 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800697 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
698 messages::internalError(resp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500699 return;
700 }
Jonathan Doman2bab9832020-12-02 15:27:40 -0800701 for (const auto& [objectPath, serviceMap] : subtree)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500702 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800703 // Ignore any objects which don't end with our desired cpu name
704 if (!boost::ends_with(objectPath, processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500705 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800706 continue;
707 }
708
Jonathan Domanc9514482021-02-24 09:20:51 -0800709 bool found = false;
710 // Filter out objects that don't have the CPU-specific
711 // interfaces to make sure we can return 404 on non-CPUs
712 // (e.g. /redfish/../Processors/dimm0)
Jonathan Doman2bab9832020-12-02 15:27:40 -0800713 for (const auto& [serviceName, interfaceList] : serviceMap)
714 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800715 if (std::find_first_of(
716 interfaceList.begin(), interfaceList.end(),
717 processorInterfaces.begin(),
718 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500719 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800720 found = true;
721 break;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500722 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500723 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800724
725 if (!found)
726 {
727 continue;
728 }
729
730 // Process the first object which does match our cpu name and
731 // required interfaces, and potentially ignore any other
732 // matching objects. Assume all interfaces we want to process
733 // must be on the same object path.
734
735 handler(resp, processorId, objectPath, serviceMap);
Jonathan Doman2bab9832020-12-02 15:27:40 -0800736 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500737 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800738 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500739 },
740 "xyz.openbmc_project.ObjectMapper",
741 "/xyz/openbmc_project/object_mapper",
742 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800743 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800744 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530745 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800746 "xyz.openbmc_project.Inventory.Decorator.Asset",
747 "xyz.openbmc_project.Inventory.Decorator.Revision",
748 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600749 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800750 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800751 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
752 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500753}
754
zhanghch058d1b46d2021-04-01 11:18:24 +0800755inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800756 const std::string& processorId,
757 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600758 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Domanc9514482021-02-24 09:20:51 -0800759{
760 for (const auto& [serviceName, interfaceList] : serviceMap)
761 {
762 for (const auto& interface : interfaceList)
763 {
764 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
765 {
766 getCpuAssetData(aResp, serviceName, objectPath);
767 }
George Liu0fda0f12021-11-16 10:06:17 +0800768 else if (interface ==
769 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800770 {
771 getCpuRevisionData(aResp, serviceName, objectPath);
772 }
773 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
774 {
775 getCpuDataByService(aResp, processorId, serviceName,
776 objectPath);
777 }
George Liu0fda0f12021-11-16 10:06:17 +0800778 else if (interface ==
779 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800780 {
781 getAcceleratorDataByService(aResp, processorId, serviceName,
782 objectPath);
783 }
George Liu0fda0f12021-11-16 10:06:17 +0800784 else if (
785 interface ==
786 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800787 {
788 getCpuConfigData(aResp, processorId, serviceName, objectPath);
789 }
George Liu0fda0f12021-11-16 10:06:17 +0800790 else if (interface ==
791 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800792 {
793 getCpuLocationCode(aResp, serviceName, objectPath);
794 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530795 else if (interface == "xyz.openbmc_project.Common.UUID")
796 {
797 getProcessorUUID(aResp, serviceName, objectPath);
798 }
George Liu0fda0f12021-11-16 10:06:17 +0800799 else if (interface ==
800 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800801 {
802 getCpuUniqueId(aResp, serviceName, objectPath);
803 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800804 }
805 }
806}
807
Jonathan Domandba0c292020-12-02 15:34:13 -0800808/**
809 * Request all the properties for the given D-Bus object and fill out the
810 * related entries in the Redfish OperatingConfig response.
811 *
812 * @param[in,out] aResp Async HTTP response.
813 * @param[in] service D-Bus service name to query.
814 * @param[in] objPath D-Bus object to query.
815 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800816inline void
817 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
818 const std::string& service,
819 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800820{
821 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -0800822 [aResp](const boost::system::error_code ec,
Jonathan Domandba0c292020-12-02 15:34:13 -0800823 const OperatingConfigProperties& properties) {
824 if (ec)
825 {
826 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
827 << ec.message();
828 messages::internalError(aResp->res);
829 return;
830 }
831
832 nlohmann::json& json = aResp->res.jsonValue;
833 for (const auto& [key, variant] : properties)
834 {
835 if (key == "AvailableCoreCount")
836 {
837 const size_t* cores = std::get_if<size_t>(&variant);
838 if (cores != nullptr)
839 {
840 json["TotalAvailableCoreCount"] = *cores;
841 }
842 }
843 else if (key == "BaseSpeed")
844 {
845 const uint32_t* speed = std::get_if<uint32_t>(&variant);
846 if (speed != nullptr)
847 {
848 json["BaseSpeedMHz"] = *speed;
849 }
850 }
851 else if (key == "MaxJunctionTemperature")
852 {
853 const uint32_t* temp = std::get_if<uint32_t>(&variant);
854 if (temp != nullptr)
855 {
856 json["MaxJunctionTemperatureCelsius"] = *temp;
857 }
858 }
859 else if (key == "MaxSpeed")
860 {
861 const uint32_t* speed = std::get_if<uint32_t>(&variant);
862 if (speed != nullptr)
863 {
864 json["MaxSpeedMHz"] = *speed;
865 }
866 }
867 else if (key == "PowerLimit")
868 {
869 const uint32_t* tdp = std::get_if<uint32_t>(&variant);
870 if (tdp != nullptr)
871 {
872 json["TDPWatts"] = *tdp;
873 }
874 }
875 else if (key == "TurboProfile")
876 {
877 const auto* turboList =
878 std::get_if<TurboProfileProperty>(&variant);
879 if (turboList == nullptr)
880 {
881 continue;
882 }
883
884 nlohmann::json& turboArray = json["TurboProfile"];
885 turboArray = nlohmann::json::array();
886 for (const auto& [turboSpeed, coreCount] : *turboList)
887 {
888 turboArray.push_back({{"ActiveCoreCount", coreCount},
889 {"MaxSpeedMHz", turboSpeed}});
890 }
891 }
892 else if (key == "BaseSpeedPrioritySettings")
893 {
894 const auto* baseSpeedList =
895 std::get_if<BaseSpeedPrioritySettingsProperty>(
896 &variant);
897 if (baseSpeedList == nullptr)
898 {
899 continue;
900 }
901
902 nlohmann::json& baseSpeedArray =
903 json["BaseSpeedPrioritySettings"];
904 baseSpeedArray = nlohmann::json::array();
905 for (const auto& [baseSpeed, coreList] : *baseSpeedList)
906 {
907 baseSpeedArray.push_back(
908 {{"CoreCount", coreList.size()},
909 {"CoreIDs", coreList},
910 {"BaseSpeedMHz", baseSpeed}});
911 }
912 }
913 }
914 },
915 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
916 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig");
917}
918
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800919/**
920 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
921 * property. Main task is to translate error messages into Redfish errors.
922 *
923 * @param[in,out] resp HTTP response.
924 * @param[in] setPropVal Value which we attempted to set.
925 * @param[in] ec D-Bus response error code.
926 * @param[in] msg D-Bus response message.
927 */
928inline void
929 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
930 const std::string& setPropVal,
931 boost::system::error_code ec,
932 const sdbusplus::message::message& msg)
933{
934 if (!ec)
935 {
936 BMCWEB_LOG_DEBUG << "Set Property succeeded";
937 return;
938 }
939
940 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
941
942 const sd_bus_error* dbusError = msg.get_error();
943 if (dbusError == nullptr)
944 {
945 messages::internalError(resp->res);
946 return;
947 }
948
949 // The asio error code doesn't know about our custom errors, so we have to
950 // parse the error string. Some of these D-Bus -> Redfish translations are a
951 // stretch, but it's good to try to communicate something vaguely useful.
952 if (strcmp(dbusError->name,
953 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
954 {
955 // Service did not like the object_path we tried to set.
956 messages::propertyValueIncorrect(
957 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
958 }
959 else if (strcmp(dbusError->name,
960 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
961 {
962 // Service indicates we can never change the config for this processor.
963 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
964 }
965 else if (strcmp(dbusError->name,
966 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
967 {
968 // Service indicates the config cannot be changed right now, but maybe
969 // in a different system state.
970 messages::resourceInStandby(resp->res);
971 }
972 else if (strcmp(dbusError->name,
973 "xyz.openbmc_project.Common.Device.Error.WriteFailure") ==
974 0)
975 {
976 // Service tried to change the config, but it failed.
977 messages::operationFailed(resp->res);
978 }
979 else
980 {
981 messages::internalError(resp->res);
982 }
983}
984
985/**
986 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
987 * validation of the input data, and then set the D-Bus property.
988 *
989 * @param[in,out] resp Async HTTP response.
990 * @param[in] processorId Processor's Id.
991 * @param[in] appliedConfigUri New property value to apply.
992 * @param[in] cpuObjectPath Path of CPU object to modify.
993 * @param[in] serviceMap Service map for CPU object.
994 */
995inline void patchAppliedOperatingConfig(
996 const std::shared_ptr<bmcweb::AsyncResp>& resp,
997 const std::string& processorId, const std::string& appliedConfigUri,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600998 const std::string& cpuObjectPath,
999 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001000{
1001 // Check that the property even exists by checking for the interface
1002 const std::string* controlService = nullptr;
1003 for (const auto& [serviceName, interfaceList] : serviceMap)
1004 {
1005 if (std::find(interfaceList.begin(), interfaceList.end(),
1006 "xyz.openbmc_project.Control.Processor."
1007 "CurrentOperatingConfig") != interfaceList.end())
1008 {
1009 controlService = &serviceName;
1010 break;
1011 }
1012 }
1013
1014 if (controlService == nullptr)
1015 {
1016 messages::internalError(resp->res);
1017 return;
1018 }
1019
1020 // Check that the config URI is a child of the cpu URI being patched.
1021 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
1022 expectedPrefix += processorId;
1023 expectedPrefix += "/OperatingConfigs/";
1024 if (!boost::starts_with(appliedConfigUri, expectedPrefix) ||
1025 expectedPrefix.size() == appliedConfigUri.size())
1026 {
1027 messages::propertyValueIncorrect(
1028 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1029 return;
1030 }
1031
1032 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1033 // direct child of the CPU object.
1034 // Strip the expectedPrefix from the config URI to get the "filename", and
1035 // append to the CPU's path.
1036 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1037 sdbusplus::message::object_path configPath(cpuObjectPath);
1038 configPath /= configBaseName;
1039
1040 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1041
1042 // Set the property, with handler to check error responses
1043 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -08001044 [resp, appliedConfigUri](const boost::system::error_code ec,
1045 const sdbusplus::message::message& msg) {
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001046 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
1047 },
1048 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1049 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
Ed Tanous168e20c2021-12-13 14:39:53 -08001050 "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001051}
1052
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001053inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001054{
Jonathan Domandba0c292020-12-02 15:34:13 -08001055
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001056 BMCWEB_ROUTE(
1057 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001058 .privileges(redfish::privileges::getOperatingConfigCollection)
George Liu0fda0f12021-11-16 10:06:17 +08001059 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001060 boost::beast::http::verb::
1061 get)([&app](const crow::Request& req,
1062 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1063 const std::string& cpuName) {
1064 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1065 {
1066 return;
1067 }
George Liu0fda0f12021-11-16 10:06:17 +08001068 asyncResp->res.jsonValue["@odata.type"] =
1069 "#OperatingConfigCollection.OperatingConfigCollection";
1070 asyncResp->res.jsonValue["@odata.id"] = req.url;
1071 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
Jonathan Domandba0c292020-12-02 15:34:13 -08001072
George Liu0fda0f12021-11-16 10:06:17 +08001073 // First find the matching CPU object so we know how to
1074 // constrain our search for related Config objects.
1075 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001076 [asyncResp,
1077 cpuName](const boost::system::error_code ec,
1078 const dbus::utility::MapperGetSubTreePathsResponse&
1079 objects) {
George Liu0fda0f12021-11-16 10:06:17 +08001080 if (ec)
1081 {
1082 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1083 << ec.message();
1084 messages::internalError(asyncResp->res);
1085 return;
1086 }
1087
1088 for (const std::string& object : objects)
1089 {
1090 if (!boost::ends_with(object, cpuName))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001091 {
George Liu0fda0f12021-11-16 10:06:17 +08001092 continue;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001093 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001094
George Liu0fda0f12021-11-16 10:06:17 +08001095 // Not expected that there will be multiple matching
1096 // CPU objects, but if there are just use the first
1097 // one.
Jonathan Domandba0c292020-12-02 15:34:13 -08001098
George Liu0fda0f12021-11-16 10:06:17 +08001099 // Use the common search routine to construct the
1100 // Collection of all Config objects under this CPU.
1101 collection_util::getCollectionMembers(
1102 asyncResp,
1103 "/redfish/v1/Systems/system/Processors/" + cpuName +
1104 "/OperatingConfigs",
1105 {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1106 object.c_str());
1107 return;
1108 }
1109 },
1110 "xyz.openbmc_project.ObjectMapper",
1111 "/xyz/openbmc_project/object_mapper",
1112 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1113 "/xyz/openbmc_project/inventory", 0,
1114 std::array<const char*, 1>{
1115 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
1116 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001117}
1118
1119inline void requestRoutesOperatingConfig(App& app)
1120{
1121 BMCWEB_ROUTE(
1122 app,
1123 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001124 .privileges(redfish::privileges::getOperatingConfig)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001125 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001126 boost::beast::http::verb::
1127 get)([&app](const crow::Request& req,
1128 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1129 const std::string& cpuName,
1130 const std::string& configName) {
1131 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1132 {
1133 return;
1134 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001135 // Ask for all objects implementing OperatingConfig so we can search
1136 // for one with a matching name
1137 crow::connections::systemBus->async_method_call(
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001138 [asyncResp, cpuName, configName, reqUrl{req.url}](
1139 boost::system::error_code ec,
1140 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001141 if (ec)
Jonathan Domandba0c292020-12-02 15:34:13 -08001142 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001143 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1144 << ec.message();
1145 messages::internalError(asyncResp->res);
1146 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001147 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001148 const std::string expectedEnding =
1149 cpuName + '/' + configName;
1150 for (const auto& [objectPath, serviceMap] : subtree)
Jonathan Domandba0c292020-12-02 15:34:13 -08001151 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001152 // Ignore any configs without matching cpuX/configY
1153 if (!boost::ends_with(objectPath, expectedEnding) ||
1154 serviceMap.empty())
1155 {
1156 continue;
1157 }
1158
1159 nlohmann::json& json = asyncResp->res.jsonValue;
1160 json["@odata.type"] =
1161 "#OperatingConfig.v1_0_0.OperatingConfig";
1162 json["@odata.id"] = reqUrl;
1163 json["Name"] = "Processor Profile";
1164 json["Id"] = configName;
1165
1166 // Just use the first implementation of the object - not
1167 // expected that there would be multiple matching
1168 // services
1169 getOperatingConfigData(
1170 asyncResp, serviceMap.begin()->first, objectPath);
1171 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001172 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001173 messages::resourceNotFound(asyncResp->res,
1174 "OperatingConfig", configName);
1175 },
1176 "xyz.openbmc_project.ObjectMapper",
1177 "/xyz/openbmc_project/object_mapper",
1178 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1179 "/xyz/openbmc_project/inventory", 0,
1180 std::array<const char*, 1>{
1181 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
1182 });
1183}
Jonathan Domandba0c292020-12-02 15:34:13 -08001184
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001185inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001186{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001187 /**
1188 * Functions triggers appropriate requests on DBus
1189 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001190 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001191 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001192 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001193 [&app](const crow::Request& req,
1194 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1195 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1196 {
1197 return;
1198 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001199 asyncResp->res.jsonValue["@odata.type"] =
1200 "#ProcessorCollection.ProcessorCollection";
1201 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001202
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001203 asyncResp->res.jsonValue["@odata.id"] =
1204 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001205
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001206 collection_util::getCollectionMembers(
1207 asyncResp, "/redfish/v1/Systems/system/Processors",
1208 std::vector<const char*>(processorInterfaces.begin(),
1209 processorInterfaces.end()));
1210 });
1211}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001212
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001213inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001214{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001215 /**
1216 * Functions triggers appropriate requests on DBus
1217 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001218
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001220 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001221 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001222 [&app](const crow::Request& req,
1223 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1224 const std::string& processorId) {
1225 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1226 {
1227 return;
1228 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001229 asyncResp->res.jsonValue["@odata.type"] =
1230 "#Processor.v1_11_0.Processor";
1231 asyncResp->res.jsonValue["@odata.id"] =
1232 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001233
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001234 getProcessorObject(asyncResp, processorId, getProcessorData);
1235 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001236
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001237 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001238 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001239 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001240 [&app](const crow::Request& req,
1241 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1242 const std::string& processorId) {
1243 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1244 {
1245 return;
1246 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001247 std::optional<nlohmann::json> appliedConfigJson;
Willy Tu15ed6782021-12-14 11:03:16 -08001248 if (!json_util::readJsonPatch(req, asyncResp->res,
1249 "AppliedOperatingConfig",
1250 appliedConfigJson))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001251 {
1252 return;
1253 }
1254
1255 std::string appliedConfigUri;
1256 if (appliedConfigJson)
1257 {
1258 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1259 "@odata.id", appliedConfigUri))
1260 {
1261 return;
1262 }
1263 // Check for 404 and find matching D-Bus object, then run
1264 // property patch handlers if that all succeeds.
1265 getProcessorObject(
1266 asyncResp, processorId,
1267 [appliedConfigUri = std::move(appliedConfigUri)](
1268 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1269 const std::string& processorId,
1270 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001271 const dbus::utility::MapperServiceMap& serviceMap) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001272 patchAppliedOperatingConfig(asyncResp, processorId,
1273 appliedConfigUri,
1274 objectPath, serviceMap);
1275 });
1276 }
1277 });
1278}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001279
1280} // namespace redfish