blob: e0346debc6177ef221d00a5c36f2b2d70b9f4aa8 [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";
Ed Tanous14766872022-03-15 10:44:42 -0700558 nlohmann::json::object_t operatingConfig;
559 operatingConfig["@odata.id"] = uri;
560 json["OperatingConfigs"] = std::move(operatingConfig);
Jonathan Domandba0c292020-12-02 15:34:13 -0800561
562 // Reuse the D-Bus config object name for the Redfish
563 // URI
564 size_t baseNamePos = dbusPath.rfind('/');
565 if (baseNamePos == std::string::npos ||
566 baseNamePos == (dbusPath.size() - 1))
567 {
568 // If the AppliedConfig was somehow not a valid path,
569 // skip adding any more properties, since everything
570 // else is tied to this applied config.
571 messages::internalError(aResp->res);
572 break;
573 }
574 uri += '/';
575 uri += dbusPath.substr(baseNamePos + 1);
Ed Tanous14766872022-03-15 10:44:42 -0700576 nlohmann::json::object_t appliedOperatingConfig;
577 appliedOperatingConfig["@odata.id"] = uri;
578 json["AppliedOperatingConfig"] =
579 std::move(appliedOperatingConfig);
Jonathan Domandba0c292020-12-02 15:34:13 -0800580
581 // Once we found the current applied config, queue another
582 // request to read the base freq core ids out of that
583 // config.
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700584 sdbusplus::asio::getProperty<
585 BaseSpeedPrioritySettingsProperty>(
586 *crow::connections::systemBus, service, dbusPath,
587 "xyz.openbmc_project.Inventory.Item.Cpu."
588 "OperatingConfig",
589 "BaseSpeedPrioritySettings",
590 [aResp](const boost::system::error_code ec,
591 const BaseSpeedPrioritySettingsProperty&
592 baseSpeedList) {
Jonathan Domandba0c292020-12-02 15:34:13 -0800593 if (ec)
594 {
595 BMCWEB_LOG_WARNING
596 << "D-Bus Property Get error: " << ec;
597 messages::internalError(aResp->res);
598 return;
599 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700600
601 highSpeedCoreIdsHandler(aResp, baseSpeedList);
602 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800603 }
604 else if (dbusPropName == "BaseSpeedPriorityEnabled")
605 {
606 const bool* state = std::get_if<bool>(&variantVal);
607 if (state != nullptr)
608 {
609 json["BaseSpeedPriorityState"] =
610 *state ? "Enabled" : "Disabled";
611 }
612 }
613 }
614 },
615 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
616 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig");
617}
618
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600619/**
620 * @brief Fill out location info of a processor by
621 * requesting data from the given D-Bus object.
622 *
623 * @param[in,out] aResp Async HTTP response.
624 * @param[in] service D-Bus service to query.
625 * @param[in] objPath D-Bus object to query.
626 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800627inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600628 const std::string& service,
629 const std::string& objPath)
630{
631 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700632 sdbusplus::asio::getProperty<std::string>(
633 *crow::connections::systemBus, service, objPath,
634 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
635 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
636 const std::string& property) {
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600637 if (ec)
638 {
639 BMCWEB_LOG_DEBUG << "DBUS response error";
640 messages::internalError(aResp->res);
641 return;
642 }
643
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600644 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700645 property;
646 });
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600647}
648
Jonathan Domanc9514482021-02-24 09:20:51 -0800649/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800650 * Populate the unique identifier in a Processor resource by requesting data
651 * from the given D-Bus object.
652 *
653 * @param[in,out] aResp Async HTTP response.
654 * @param[in] service D-Bus service to query.
655 * @param[in] objPath D-Bus object to query.
656 */
657inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
658 const std::string& service,
659 const std::string& objectPath)
660{
661 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700662 sdbusplus::asio::getProperty<std::string>(
663 *crow::connections::systemBus, service, objectPath,
664 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
665 "UniqueIdentifier",
666 [aResp](boost::system::error_code ec, const std::string& id) {
667 if (ec)
Jonathan Doman49e429c2021-03-03 13:11:44 -0800668 {
669 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
670 messages::internalError(aResp->res);
671 return;
672 }
673 aResp->res
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700674 .jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] = id;
675 });
Jonathan Doman49e429c2021-03-03 13:11:44 -0800676}
677
678/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800679 * Find the D-Bus object representing the requested Processor, and call the
680 * handler with the results. If matching object is not found, add 404 error to
681 * response and don't call the handler.
682 *
683 * @param[in,out] resp Async HTTP response.
684 * @param[in] processorId Redfish Processor Id.
685 * @param[in] handler Callback to continue processing request upon
686 * successfully finding object.
687 */
688template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800689inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800690 const std::string& processorId,
691 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500692{
693 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
694
Jonathan Domanc9514482021-02-24 09:20:51 -0800695 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500696 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800697 [resp, processorId, handler = std::forward<Handler>(handler)](
698 boost::system::error_code ec,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600699 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500700 if (ec)
701 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800702 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
703 messages::internalError(resp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500704 return;
705 }
Jonathan Doman2bab9832020-12-02 15:27:40 -0800706 for (const auto& [objectPath, serviceMap] : subtree)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500707 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800708 // Ignore any objects which don't end with our desired cpu name
709 if (!boost::ends_with(objectPath, processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500710 {
Jonathan Doman2bab9832020-12-02 15:27:40 -0800711 continue;
712 }
713
Jonathan Domanc9514482021-02-24 09:20:51 -0800714 bool found = false;
715 // Filter out objects that don't have the CPU-specific
716 // interfaces to make sure we can return 404 on non-CPUs
717 // (e.g. /redfish/../Processors/dimm0)
Jonathan Doman2bab9832020-12-02 15:27:40 -0800718 for (const auto& [serviceName, interfaceList] : serviceMap)
719 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800720 if (std::find_first_of(
721 interfaceList.begin(), interfaceList.end(),
722 processorInterfaces.begin(),
723 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500724 {
Jonathan Domanc9514482021-02-24 09:20:51 -0800725 found = true;
726 break;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500727 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500728 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800729
730 if (!found)
731 {
732 continue;
733 }
734
735 // Process the first object which does match our cpu name and
736 // required interfaces, and potentially ignore any other
737 // matching objects. Assume all interfaces we want to process
738 // must be on the same object path.
739
740 handler(resp, processorId, objectPath, serviceMap);
Jonathan Doman2bab9832020-12-02 15:27:40 -0800741 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500742 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800743 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500744 },
745 "xyz.openbmc_project.ObjectMapper",
746 "/xyz/openbmc_project/object_mapper",
747 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800748 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800749 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530750 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800751 "xyz.openbmc_project.Inventory.Decorator.Asset",
752 "xyz.openbmc_project.Inventory.Decorator.Revision",
753 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600754 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800755 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800756 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
757 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500758}
759
zhanghch058d1b46d2021-04-01 11:18:24 +0800760inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800761 const std::string& processorId,
762 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600763 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Domanc9514482021-02-24 09:20:51 -0800764{
765 for (const auto& [serviceName, interfaceList] : serviceMap)
766 {
767 for (const auto& interface : interfaceList)
768 {
769 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
770 {
771 getCpuAssetData(aResp, serviceName, objectPath);
772 }
George Liu0fda0f12021-11-16 10:06:17 +0800773 else if (interface ==
774 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800775 {
776 getCpuRevisionData(aResp, serviceName, objectPath);
777 }
778 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
779 {
780 getCpuDataByService(aResp, processorId, serviceName,
781 objectPath);
782 }
George Liu0fda0f12021-11-16 10:06:17 +0800783 else if (interface ==
784 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800785 {
786 getAcceleratorDataByService(aResp, processorId, serviceName,
787 objectPath);
788 }
George Liu0fda0f12021-11-16 10:06:17 +0800789 else if (
790 interface ==
791 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800792 {
793 getCpuConfigData(aResp, processorId, serviceName, objectPath);
794 }
George Liu0fda0f12021-11-16 10:06:17 +0800795 else if (interface ==
796 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800797 {
798 getCpuLocationCode(aResp, serviceName, objectPath);
799 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530800 else if (interface == "xyz.openbmc_project.Common.UUID")
801 {
802 getProcessorUUID(aResp, serviceName, objectPath);
803 }
George Liu0fda0f12021-11-16 10:06:17 +0800804 else if (interface ==
805 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800806 {
807 getCpuUniqueId(aResp, serviceName, objectPath);
808 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800809 }
810 }
811}
812
Jonathan Domandba0c292020-12-02 15:34:13 -0800813/**
814 * Request all the properties for the given D-Bus object and fill out the
815 * related entries in the Redfish OperatingConfig response.
816 *
817 * @param[in,out] aResp Async HTTP response.
818 * @param[in] service D-Bus service name to query.
819 * @param[in] objPath D-Bus object to query.
820 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800821inline void
822 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
823 const std::string& service,
824 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800825{
826 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -0800827 [aResp](const boost::system::error_code ec,
Jonathan Domandba0c292020-12-02 15:34:13 -0800828 const OperatingConfigProperties& properties) {
829 if (ec)
830 {
831 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
832 << ec.message();
833 messages::internalError(aResp->res);
834 return;
835 }
836
837 nlohmann::json& json = aResp->res.jsonValue;
838 for (const auto& [key, variant] : properties)
839 {
840 if (key == "AvailableCoreCount")
841 {
842 const size_t* cores = std::get_if<size_t>(&variant);
843 if (cores != nullptr)
844 {
845 json["TotalAvailableCoreCount"] = *cores;
846 }
847 }
848 else if (key == "BaseSpeed")
849 {
850 const uint32_t* speed = std::get_if<uint32_t>(&variant);
851 if (speed != nullptr)
852 {
853 json["BaseSpeedMHz"] = *speed;
854 }
855 }
856 else if (key == "MaxJunctionTemperature")
857 {
858 const uint32_t* temp = std::get_if<uint32_t>(&variant);
859 if (temp != nullptr)
860 {
861 json["MaxJunctionTemperatureCelsius"] = *temp;
862 }
863 }
864 else if (key == "MaxSpeed")
865 {
866 const uint32_t* speed = std::get_if<uint32_t>(&variant);
867 if (speed != nullptr)
868 {
869 json["MaxSpeedMHz"] = *speed;
870 }
871 }
872 else if (key == "PowerLimit")
873 {
874 const uint32_t* tdp = std::get_if<uint32_t>(&variant);
875 if (tdp != nullptr)
876 {
877 json["TDPWatts"] = *tdp;
878 }
879 }
880 else if (key == "TurboProfile")
881 {
882 const auto* turboList =
883 std::get_if<TurboProfileProperty>(&variant);
884 if (turboList == nullptr)
885 {
886 continue;
887 }
888
889 nlohmann::json& turboArray = json["TurboProfile"];
890 turboArray = nlohmann::json::array();
891 for (const auto& [turboSpeed, coreCount] : *turboList)
892 {
Ed Tanous14766872022-03-15 10:44:42 -0700893 nlohmann::json::object_t turbo;
894 turbo["ActiveCoreCount"] = coreCount;
895 turbo["MaxSpeedMHz"] = turboSpeed;
896 turboArray.push_back(std::move(turbo));
Jonathan Domandba0c292020-12-02 15:34:13 -0800897 }
898 }
899 else if (key == "BaseSpeedPrioritySettings")
900 {
901 const auto* baseSpeedList =
902 std::get_if<BaseSpeedPrioritySettingsProperty>(
903 &variant);
904 if (baseSpeedList == nullptr)
905 {
906 continue;
907 }
908
909 nlohmann::json& baseSpeedArray =
910 json["BaseSpeedPrioritySettings"];
911 baseSpeedArray = nlohmann::json::array();
912 for (const auto& [baseSpeed, coreList] : *baseSpeedList)
913 {
Ed Tanous14766872022-03-15 10:44:42 -0700914 nlohmann::json::object_t speed;
915 speed["CoreCount"] = coreList.size();
916 speed["CoreIDs"] = coreList;
917 speed["BaseSpeedMHz"] = baseSpeed;
918 baseSpeedArray.push_back(std::move(speed));
Jonathan Domandba0c292020-12-02 15:34:13 -0800919 }
920 }
921 }
922 },
923 service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
924 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig");
925}
926
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800927/**
928 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
929 * property. Main task is to translate error messages into Redfish errors.
930 *
931 * @param[in,out] resp HTTP response.
932 * @param[in] setPropVal Value which we attempted to set.
933 * @param[in] ec D-Bus response error code.
934 * @param[in] msg D-Bus response message.
935 */
936inline void
937 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
938 const std::string& setPropVal,
939 boost::system::error_code ec,
940 const sdbusplus::message::message& msg)
941{
942 if (!ec)
943 {
944 BMCWEB_LOG_DEBUG << "Set Property succeeded";
945 return;
946 }
947
948 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
949
950 const sd_bus_error* dbusError = msg.get_error();
951 if (dbusError == nullptr)
952 {
953 messages::internalError(resp->res);
954 return;
955 }
956
957 // The asio error code doesn't know about our custom errors, so we have to
958 // parse the error string. Some of these D-Bus -> Redfish translations are a
959 // stretch, but it's good to try to communicate something vaguely useful.
960 if (strcmp(dbusError->name,
961 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
962 {
963 // Service did not like the object_path we tried to set.
964 messages::propertyValueIncorrect(
965 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
966 }
967 else if (strcmp(dbusError->name,
968 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
969 {
970 // Service indicates we can never change the config for this processor.
971 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
972 }
973 else if (strcmp(dbusError->name,
974 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
975 {
976 // Service indicates the config cannot be changed right now, but maybe
977 // in a different system state.
978 messages::resourceInStandby(resp->res);
979 }
980 else if (strcmp(dbusError->name,
981 "xyz.openbmc_project.Common.Device.Error.WriteFailure") ==
982 0)
983 {
984 // Service tried to change the config, but it failed.
985 messages::operationFailed(resp->res);
986 }
987 else
988 {
989 messages::internalError(resp->res);
990 }
991}
992
993/**
994 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
995 * validation of the input data, and then set the D-Bus property.
996 *
997 * @param[in,out] resp Async HTTP response.
998 * @param[in] processorId Processor's Id.
999 * @param[in] appliedConfigUri New property value to apply.
1000 * @param[in] cpuObjectPath Path of CPU object to modify.
1001 * @param[in] serviceMap Service map for CPU object.
1002 */
1003inline void patchAppliedOperatingConfig(
1004 const std::shared_ptr<bmcweb::AsyncResp>& resp,
1005 const std::string& processorId, const std::string& appliedConfigUri,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001006 const std::string& cpuObjectPath,
1007 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001008{
1009 // Check that the property even exists by checking for the interface
1010 const std::string* controlService = nullptr;
1011 for (const auto& [serviceName, interfaceList] : serviceMap)
1012 {
1013 if (std::find(interfaceList.begin(), interfaceList.end(),
1014 "xyz.openbmc_project.Control.Processor."
1015 "CurrentOperatingConfig") != interfaceList.end())
1016 {
1017 controlService = &serviceName;
1018 break;
1019 }
1020 }
1021
1022 if (controlService == nullptr)
1023 {
1024 messages::internalError(resp->res);
1025 return;
1026 }
1027
1028 // Check that the config URI is a child of the cpu URI being patched.
1029 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
1030 expectedPrefix += processorId;
1031 expectedPrefix += "/OperatingConfigs/";
1032 if (!boost::starts_with(appliedConfigUri, expectedPrefix) ||
1033 expectedPrefix.size() == appliedConfigUri.size())
1034 {
1035 messages::propertyValueIncorrect(
1036 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1037 return;
1038 }
1039
1040 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1041 // direct child of the CPU object.
1042 // Strip the expectedPrefix from the config URI to get the "filename", and
1043 // append to the CPU's path.
1044 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1045 sdbusplus::message::object_path configPath(cpuObjectPath);
1046 configPath /= configBaseName;
1047
1048 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1049
1050 // Set the property, with handler to check error responses
1051 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -08001052 [resp, appliedConfigUri](const boost::system::error_code ec,
1053 const sdbusplus::message::message& msg) {
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001054 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
1055 },
1056 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1057 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
Ed Tanous168e20c2021-12-13 14:39:53 -08001058 "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001059}
1060
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001061inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001062{
Jonathan Domandba0c292020-12-02 15:34:13 -08001063
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001064 BMCWEB_ROUTE(
1065 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001066 .privileges(redfish::privileges::getOperatingConfigCollection)
George Liu0fda0f12021-11-16 10:06:17 +08001067 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001068 boost::beast::http::verb::
1069 get)([&app](const crow::Request& req,
1070 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1071 const std::string& cpuName) {
1072 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1073 {
1074 return;
1075 }
George Liu0fda0f12021-11-16 10:06:17 +08001076 asyncResp->res.jsonValue["@odata.type"] =
1077 "#OperatingConfigCollection.OperatingConfigCollection";
1078 asyncResp->res.jsonValue["@odata.id"] = req.url;
1079 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
Jonathan Domandba0c292020-12-02 15:34:13 -08001080
George Liu0fda0f12021-11-16 10:06:17 +08001081 // First find the matching CPU object so we know how to
1082 // constrain our search for related Config objects.
1083 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -08001084 [asyncResp,
1085 cpuName](const boost::system::error_code ec,
1086 const dbus::utility::MapperGetSubTreePathsResponse&
1087 objects) {
George Liu0fda0f12021-11-16 10:06:17 +08001088 if (ec)
1089 {
1090 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1091 << ec.message();
1092 messages::internalError(asyncResp->res);
1093 return;
1094 }
1095
1096 for (const std::string& object : objects)
1097 {
1098 if (!boost::ends_with(object, cpuName))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001099 {
George Liu0fda0f12021-11-16 10:06:17 +08001100 continue;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001101 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001102
George Liu0fda0f12021-11-16 10:06:17 +08001103 // Not expected that there will be multiple matching
1104 // CPU objects, but if there are just use the first
1105 // one.
Jonathan Domandba0c292020-12-02 15:34:13 -08001106
George Liu0fda0f12021-11-16 10:06:17 +08001107 // Use the common search routine to construct the
1108 // Collection of all Config objects under this CPU.
1109 collection_util::getCollectionMembers(
1110 asyncResp,
1111 "/redfish/v1/Systems/system/Processors/" + cpuName +
1112 "/OperatingConfigs",
1113 {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1114 object.c_str());
1115 return;
1116 }
1117 },
1118 "xyz.openbmc_project.ObjectMapper",
1119 "/xyz/openbmc_project/object_mapper",
1120 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1121 "/xyz/openbmc_project/inventory", 0,
1122 std::array<const char*, 1>{
1123 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
1124 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001125}
1126
1127inline void requestRoutesOperatingConfig(App& app)
1128{
1129 BMCWEB_ROUTE(
1130 app,
1131 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001132 .privileges(redfish::privileges::getOperatingConfig)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001133 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001134 boost::beast::http::verb::
1135 get)([&app](const crow::Request& req,
1136 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1137 const std::string& cpuName,
1138 const std::string& configName) {
1139 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1140 {
1141 return;
1142 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001143 // Ask for all objects implementing OperatingConfig so we can search
1144 // for one with a matching name
1145 crow::connections::systemBus->async_method_call(
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001146 [asyncResp, cpuName, configName, reqUrl{req.url}](
1147 boost::system::error_code ec,
1148 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001149 if (ec)
Jonathan Domandba0c292020-12-02 15:34:13 -08001150 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001151 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1152 << ec.message();
1153 messages::internalError(asyncResp->res);
1154 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001155 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001156 const std::string expectedEnding =
1157 cpuName + '/' + configName;
1158 for (const auto& [objectPath, serviceMap] : subtree)
Jonathan Domandba0c292020-12-02 15:34:13 -08001159 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001160 // Ignore any configs without matching cpuX/configY
1161 if (!boost::ends_with(objectPath, expectedEnding) ||
1162 serviceMap.empty())
1163 {
1164 continue;
1165 }
1166
1167 nlohmann::json& json = asyncResp->res.jsonValue;
1168 json["@odata.type"] =
1169 "#OperatingConfig.v1_0_0.OperatingConfig";
1170 json["@odata.id"] = reqUrl;
1171 json["Name"] = "Processor Profile";
1172 json["Id"] = configName;
1173
1174 // Just use the first implementation of the object - not
1175 // expected that there would be multiple matching
1176 // services
1177 getOperatingConfigData(
1178 asyncResp, serviceMap.begin()->first, objectPath);
1179 return;
Jonathan Domandba0c292020-12-02 15:34:13 -08001180 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001181 messages::resourceNotFound(asyncResp->res,
1182 "OperatingConfig", configName);
1183 },
1184 "xyz.openbmc_project.ObjectMapper",
1185 "/xyz/openbmc_project/object_mapper",
1186 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1187 "/xyz/openbmc_project/inventory", 0,
1188 std::array<const char*, 1>{
1189 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
1190 });
1191}
Jonathan Domandba0c292020-12-02 15:34:13 -08001192
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001193inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001194{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001195 /**
1196 * Functions triggers appropriate requests on DBus
1197 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001198 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001199 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001200 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001201 [&app](const crow::Request& req,
1202 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1203 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1204 {
1205 return;
1206 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001207 asyncResp->res.jsonValue["@odata.type"] =
1208 "#ProcessorCollection.ProcessorCollection";
1209 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001210
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001211 asyncResp->res.jsonValue["@odata.id"] =
1212 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001213
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001214 collection_util::getCollectionMembers(
1215 asyncResp, "/redfish/v1/Systems/system/Processors",
1216 std::vector<const char*>(processorInterfaces.begin(),
1217 processorInterfaces.end()));
1218 });
1219}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001220
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001221inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001222{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001223 /**
1224 * Functions triggers appropriate requests on DBus
1225 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001226
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001227 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001228 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001229 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001230 [&app](const crow::Request& req,
1231 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1232 const std::string& processorId) {
1233 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1234 {
1235 return;
1236 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001237 asyncResp->res.jsonValue["@odata.type"] =
1238 "#Processor.v1_11_0.Processor";
1239 asyncResp->res.jsonValue["@odata.id"] =
1240 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001241
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001242 getProcessorObject(asyncResp, processorId, getProcessorData);
1243 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001244
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001245 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001246 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001247 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001248 [&app](const crow::Request& req,
1249 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1250 const std::string& processorId) {
1251 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1252 {
1253 return;
1254 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001255 std::optional<nlohmann::json> appliedConfigJson;
Willy Tu15ed6782021-12-14 11:03:16 -08001256 if (!json_util::readJsonPatch(req, asyncResp->res,
1257 "AppliedOperatingConfig",
1258 appliedConfigJson))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001259 {
1260 return;
1261 }
1262
1263 std::string appliedConfigUri;
1264 if (appliedConfigJson)
1265 {
1266 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1267 "@odata.id", appliedConfigUri))
1268 {
1269 return;
1270 }
1271 // Check for 404 and find matching D-Bus object, then run
1272 // property patch handlers if that all succeeds.
1273 getProcessorObject(
1274 asyncResp, processorId,
1275 [appliedConfigUri = std::move(appliedConfigUri)](
1276 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1277 const std::string& processorId,
1278 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -06001279 const dbus::utility::MapperServiceMap& serviceMap) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001280 patchAppliedOperatingConfig(asyncResp, processorId,
1281 appliedConfigUri,
1282 objectPath, serviceMap);
1283 });
1284 }
1285 });
1286}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001287
1288} // namespace redfish