blob: d9c26f3d86a891f64b9c9b1588d44dd092da240f [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>
Krzysztof Grobelny351053f2022-07-28 15:44:22 +020029#include <sdbusplus/unpack_properties.hpp>
Jonathan Domandba0c292020-12-02 15:34:13 -080030#include <sdbusplus/utility/dedup_variant.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050031#include <utils/collection.hpp>
Krzysztof Grobelny351053f2022-07-28 15:44:22 +020032#include <utils/dbus_utils.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050033#include <utils/json_utils.hpp>
34
35namespace redfish
36{
37
Jonathan Domanc9514482021-02-24 09:20:51 -080038// Interfaces which imply a D-Bus object represents a Processor
39constexpr std::array<const char*, 2> processorInterfaces = {
40 "xyz.openbmc_project.Inventory.Item.Cpu",
41 "xyz.openbmc_project.Inventory.Item.Accelerator"};
Jonathan Doman2bab9832020-12-02 15:27:40 -080042
Sharad Yadav71b82f22021-05-10 15:11:39 +053043/**
44 * @brief Fill out uuid info of a processor by
45 * requesting data from the given D-Bus object.
46 *
47 * @param[in,out] aResp Async HTTP response.
48 * @param[in] service D-Bus service to query.
49 * @param[in] objPath D-Bus object to query.
50 */
51inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp,
52 const std::string& service,
53 const std::string& objPath)
54{
55 BMCWEB_LOG_DEBUG << "Get Processor UUID";
Jonathan Doman1e1e5982021-06-11 09:36:17 -070056 sdbusplus::asio::getProperty<std::string>(
57 *crow::connections::systemBus, service, objPath,
58 "xyz.openbmc_project.Common.UUID", "UUID",
59 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
60 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -070061 if (ec)
62 {
63 BMCWEB_LOG_DEBUG << "DBUS response error";
64 messages::internalError(aResp->res);
65 return;
66 }
67 aResp->res.jsonValue["UUID"] = property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -070068 });
Sharad Yadav71b82f22021-05-10 15:11:39 +053069}
70
Ed Tanous711ac7a2021-12-20 09:34:41 -080071inline void getCpuDataByInterface(
72 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
73 const dbus::utility::DBusInteracesMap& cpuInterfacesProperties)
Gunnar Millsac6a4442020-10-14 14:55:29 -050074{
75 BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
76
Chicago Duana1649ec2021-03-30 16:54:58 +080077 // Set the default value of state
78 aResp->res.jsonValue["Status"]["State"] = "Enabled";
79 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -050080
81 for (const auto& interface : cpuInterfacesProperties)
82 {
83 for (const auto& property : interface.second)
84 {
Chicago Duana1649ec2021-03-30 16:54:58 +080085 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -050086 {
Chicago Duana1649ec2021-03-30 16:54:58 +080087 const bool* cpuPresent = std::get_if<bool>(&property.second);
88 if (cpuPresent == nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -050089 {
90 // Important property not in desired type
91 messages::internalError(aResp->res);
92 return;
93 }
Ed Tanouse05aec52022-01-25 10:28:56 -080094 if (!*cpuPresent)
Gunnar Millsac6a4442020-10-14 14:55:29 -050095 {
Chicago Duana1649ec2021-03-30 16:54:58 +080096 // Slot is not populated
Gunnar Millsac6a4442020-10-14 14:55:29 -050097 aResp->res.jsonValue["Status"]["State"] = "Absent";
Chicago Duana1649ec2021-03-30 16:54:58 +080098 }
99 }
100 else if (property.first == "Functional")
101 {
102 const bool* cpuFunctional = std::get_if<bool>(&property.second);
103 if (cpuFunctional == nullptr)
104 {
105 messages::internalError(aResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500106 return;
107 }
Ed Tanouse05aec52022-01-25 10:28:56 -0800108 if (!*cpuFunctional)
Chicago Duana1649ec2021-03-30 16:54:58 +0800109 {
110 aResp->res.jsonValue["Status"]["Health"] = "Critical";
111 }
112 }
113 else if (property.first == "CoreCount")
114 {
115 const uint16_t* coresCount =
116 std::get_if<uint16_t>(&property.second);
117 if (coresCount == nullptr)
118 {
119 messages::internalError(aResp->res);
120 return;
121 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500122 aResp->res.jsonValue["TotalCores"] = *coresCount;
123 }
Jonathan Domandc3fa662020-10-26 23:10:24 -0700124 else if (property.first == "MaxSpeedInMhz")
125 {
126 const uint32_t* value = std::get_if<uint32_t>(&property.second);
127 if (value != nullptr)
128 {
129 aResp->res.jsonValue["MaxSpeedMHz"] = *value;
130 }
131 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500132 else if (property.first == "Socket")
133 {
134 const std::string* value =
135 std::get_if<std::string>(&property.second);
136 if (value != nullptr)
137 {
138 aResp->res.jsonValue["Socket"] = *value;
139 }
140 }
141 else if (property.first == "ThreadCount")
142 {
Jonathan Domandc3fa662020-10-26 23:10:24 -0700143 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500144 if (value != nullptr)
145 {
146 aResp->res.jsonValue["TotalThreads"] = *value;
147 }
148 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700149 else if (property.first == "EffectiveFamily")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500150 {
Brandon Kim1930fbd2021-09-14 17:52:51 -0700151 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Brad Bishop6169de22022-09-14 13:08:32 -0400152 if (value != nullptr && *value != 2)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500153 {
154 aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800155 "0x" + intToHexString(*value, 4);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500156 }
157 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700158 else if (property.first == "EffectiveModel")
159 {
160 const uint16_t* value = std::get_if<uint16_t>(&property.second);
161 if (value == nullptr)
162 {
163 messages::internalError(aResp->res);
164 return;
165 }
Brad Bishop6169de22022-09-14 13:08:32 -0400166 if (*value != 0)
167 {
168 aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] =
169 "0x" + intToHexString(*value, 4);
170 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700171 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500172 else if (property.first == "Id")
173 {
174 const uint64_t* value = std::get_if<uint64_t>(&property.second);
175 if (value != nullptr && *value != 0)
176 {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500177 aResp->res
178 .jsonValue["ProcessorId"]["IdentificationRegisters"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800179 "0x" + intToHexString(*value, 16);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500180 }
181 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700182 else if (property.first == "Microcode")
183 {
184 const uint32_t* value = std::get_if<uint32_t>(&property.second);
185 if (value == nullptr)
186 {
187 messages::internalError(aResp->res);
188 return;
189 }
Brad Bishop6169de22022-09-14 13:08:32 -0400190 if (*value != 0)
191 {
192 aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] =
193 "0x" + intToHexString(*value, 8);
194 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700195 }
196 else if (property.first == "Step")
197 {
198 const uint16_t* value = std::get_if<uint16_t>(&property.second);
199 if (value == nullptr)
200 {
201 messages::internalError(aResp->res);
202 return;
203 }
Brad Bishop6169de22022-09-14 13:08:32 -0400204 if (*value != 0)
205 {
206 aResp->res.jsonValue["ProcessorId"]["Step"] =
207 "0x" + intToHexString(*value, 4);
208 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700209 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500210 }
211 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500212}
213
zhanghch058d1b46d2021-04-01 11:18:24 +0800214inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500215 const std::string& cpuId,
216 const std::string& service,
217 const std::string& objPath)
218{
219 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
220
221 crow::connections::systemBus->async_method_call(
222 [cpuId, service, objPath, aResp{std::move(aResp)}](
223 const boost::system::error_code ec,
224 const dbus::utility::ManagedObjectType& dbusData) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700225 if (ec)
226 {
227 BMCWEB_LOG_DEBUG << "DBUS response error";
228 messages::internalError(aResp->res);
229 return;
230 }
231 aResp->res.jsonValue["Id"] = cpuId;
232 aResp->res.jsonValue["Name"] = "Processor";
233 aResp->res.jsonValue["ProcessorType"] = "CPU";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500234
Ed Tanous002d39b2022-05-31 08:59:27 -0700235 bool slotPresent = false;
236 std::string corePath = objPath + "/core";
237 size_t totalCores = 0;
238 for (const auto& object : dbusData)
239 {
240 if (object.first.str == objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500241 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700242 getCpuDataByInterface(aResp, object.second);
243 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700244 else if (object.first.str.starts_with(corePath))
Ed Tanous002d39b2022-05-31 08:59:27 -0700245 {
246 for (const auto& interface : object.second)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500247 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700248 if (interface.first == "xyz.openbmc_project.Inventory.Item")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500249 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700250 for (const auto& property : interface.second)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500251 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700252 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500253 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700254 const bool* present =
255 std::get_if<bool>(&property.second);
256 if (present != nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500257 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700258 if (*present)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500259 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700260 slotPresent = true;
261 totalCores++;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500262 }
263 }
264 }
265 }
266 }
267 }
268 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700269 }
270 // In getCpuDataByInterface(), state and health are set
271 // based on the present and functional status. If core
272 // count is zero, then it has a higher precedence.
273 if (slotPresent)
274 {
275 if (totalCores == 0)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500276 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700277 // Slot is not populated, set status end return
278 aResp->res.jsonValue["Status"]["State"] = "Absent";
279 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500280 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700281 aResp->res.jsonValue["TotalCores"] = totalCores;
282 }
283 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500284 },
285 service, "/xyz/openbmc_project/inventory",
286 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
287}
288
zhanghch058d1b46d2021-04-01 11:18:24 +0800289inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500290 const std::string& service,
291 const std::string& objPath)
292{
293 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200294 sdbusplus::asio::getAllProperties(
295 *crow::connections::systemBus, service, objPath,
296 "xyz.openbmc_project.Inventory.Decorator.Asset",
Gunnar Millsac6a4442020-10-14 14:55:29 -0500297 [objPath, aResp{std::move(aResp)}](
298 const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200299 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700300 if (ec)
301 {
302 BMCWEB_LOG_DEBUG << "DBUS response error";
303 messages::internalError(aResp->res);
304 return;
305 }
306
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200307 const std::string* serialNumber = nullptr;
308 const std::string* model = nullptr;
309 const std::string* manufacturer = nullptr;
310 const std::string* partNumber = nullptr;
311 const std::string* sparePartNumber = nullptr;
312
313 const bool success = sdbusplus::unpackPropertiesNoThrow(
314 dbus_utils::UnpackErrorPrinter(), properties, "SerialNumber",
315 serialNumber, "Model", model, "Manufacturer", manufacturer,
316 "PartNumber", partNumber, "SparePartNumber", sparePartNumber);
317
318 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700319 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200320 messages::internalError(aResp->res);
321 return;
322 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700323
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200324 if (serialNumber != nullptr && !serialNumber->empty())
325 {
326 aResp->res.jsonValue["SerialNumber"] = *serialNumber;
327 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700328
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200329 if ((model != nullptr) && !model->empty())
330 {
331 aResp->res.jsonValue["Model"] = *model;
332 }
333
334 if (manufacturer != nullptr)
335 {
336 aResp->res.jsonValue["Manufacturer"] = *manufacturer;
337
338 // Otherwise would be unexpected.
339 if (manufacturer->find("Intel") != std::string::npos)
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200341 aResp->res.jsonValue["ProcessorArchitecture"] = "x86";
342 aResp->res.jsonValue["InstructionSet"] = "x86-64";
Ed Tanous002d39b2022-05-31 08:59:27 -0700343 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200344 else if (manufacturer->find("IBM") != std::string::npos)
Ed Tanous002d39b2022-05-31 08:59:27 -0700345 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200346 aResp->res.jsonValue["ProcessorArchitecture"] = "Power";
347 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 }
349 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200350
351 if (partNumber != nullptr)
352 {
353 aResp->res.jsonValue["PartNumber"] = *partNumber;
354 }
355
Brad Bishop6169de22022-09-14 13:08:32 -0400356 if (sparePartNumber != nullptr && !sparePartNumber->empty())
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200357 {
358 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
359 }
360 });
Gunnar Millsac6a4442020-10-14 14:55:29 -0500361}
362
zhanghch058d1b46d2021-04-01 11:18:24 +0800363inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500364 const std::string& service,
365 const std::string& objPath)
366{
367 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200368 sdbusplus::asio::getAllProperties(
369 *crow::connections::systemBus, service, objPath,
370 "xyz.openbmc_project.Inventory.Decorator.Revision",
Gunnar Millsac6a4442020-10-14 14:55:29 -0500371 [objPath, aResp{std::move(aResp)}](
372 const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200373 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700374 if (ec)
375 {
376 BMCWEB_LOG_DEBUG << "DBUS response error";
377 messages::internalError(aResp->res);
378 return;
379 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500380
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200381 const std::string* version = nullptr;
382
383 const bool success = sdbusplus::unpackPropertiesNoThrow(
384 dbus_utils::UnpackErrorPrinter(), properties, "Version", version);
385
386 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700387 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200388 messages::internalError(aResp->res);
389 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200391
392 if (version != nullptr)
393 {
394 aResp->res.jsonValue["Version"] = *version;
395 }
396 });
Gunnar Millsac6a4442020-10-14 14:55:29 -0500397}
398
zhanghch058d1b46d2021-04-01 11:18:24 +0800399inline void getAcceleratorDataByService(
400 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
401 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500402{
403 BMCWEB_LOG_DEBUG
404 << "Get available system Accelerator resources by service.";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200405 sdbusplus::asio::getAllProperties(
406 *crow::connections::systemBus, service, objPath, "",
Gunnar Millsac6a4442020-10-14 14:55:29 -0500407 [acclrtrId, aResp{std::move(aResp)}](
408 const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200409 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700410 if (ec)
411 {
412 BMCWEB_LOG_DEBUG << "DBUS response error";
413 messages::internalError(aResp->res);
414 return;
415 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700416
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200417 const bool* functional = nullptr;
418 const bool* present = nullptr;
419
420 const bool success = sdbusplus::unpackPropertiesNoThrow(
421 dbus_utils::UnpackErrorPrinter(), properties, "Functional",
422 functional, "Present", present);
423
424 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700425 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200426 messages::internalError(aResp->res);
427 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700428 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500429
Ed Tanous002d39b2022-05-31 08:59:27 -0700430 std::string state = "Enabled";
431 std::string health = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500432
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200433 if (present != nullptr && !*present)
Ed Tanous002d39b2022-05-31 08:59:27 -0700434 {
435 state = "Absent";
436 }
437
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200438 if (functional != nullptr && !*functional)
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 {
440 if (state == "Enabled")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500441 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 health = "Critical";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500443 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700444 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500445
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200446 aResp->res.jsonValue["Id"] = acclrtrId;
447 aResp->res.jsonValue["Name"] = "Processor";
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 aResp->res.jsonValue["Status"]["State"] = state;
449 aResp->res.jsonValue["Status"]["Health"] = health;
450 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200451 });
Gunnar Millsac6a4442020-10-14 14:55:29 -0500452}
453
Jonathan Domandba0c292020-12-02 15:34:13 -0800454// OperatingConfig D-Bus Types
455using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
456using BaseSpeedPrioritySettingsProperty =
457 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
458// uint32_t and size_t may or may not be the same type, requiring a dedup'd
459// variant
Jonathan Domandba0c292020-12-02 15:34:13 -0800460
461/**
462 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
463 * OperatingConfig D-Bus property.
464 *
465 * @param[in,out] aResp Async HTTP response.
466 * @param[in] baseSpeedSettings Full list of base speed priority groups,
467 * to use to determine the list of high
468 * speed cores.
469 */
470inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800471 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800472 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
473{
474 // The D-Bus property does not indicate which bucket is the "high
475 // priority" group, so let's discern that by looking for the one with
476 // highest base frequency.
477 auto highPriorityGroup = baseSpeedSettings.cend();
478 uint32_t highestBaseSpeed = 0;
479 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
480 ++it)
481 {
482 const uint32_t baseFreq = std::get<uint32_t>(*it);
483 if (baseFreq > highestBaseSpeed)
484 {
485 highestBaseSpeed = baseFreq;
486 highPriorityGroup = it;
487 }
488 }
489
490 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
491 jsonCoreIds = nlohmann::json::array();
492
493 // There may not be any entries in the D-Bus property, so only populate
494 // if there was actually something there.
495 if (highPriorityGroup != baseSpeedSettings.cend())
496 {
497 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
498 }
499}
500
501/**
502 * Fill out OperatingConfig related items in a Processor resource by requesting
503 * data from the given D-Bus object.
504 *
505 * @param[in,out] aResp Async HTTP response.
506 * @param[in] cpuId CPU D-Bus name.
507 * @param[in] service D-Bus service to query.
508 * @param[in] objPath D-Bus object to query.
509 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800510inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800511 const std::string& cpuId,
512 const std::string& service,
513 const std::string& objPath)
514{
515 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
516
517 // First, GetAll CurrentOperatingConfig properties on the object
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200518 sdbusplus::asio::getAllProperties(
519 *crow::connections::systemBus, service, objPath,
520 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
521 [aResp, cpuId,
522 service](const boost::system::error_code ec,
523 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700524 if (ec)
525 {
526 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message();
527 messages::internalError(aResp->res);
528 return;
529 }
Jonathan Domandba0c292020-12-02 15:34:13 -0800530
Ed Tanous002d39b2022-05-31 08:59:27 -0700531 nlohmann::json& json = aResp->res.jsonValue;
Jonathan Domandba0c292020-12-02 15:34:13 -0800532
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200533 const sdbusplus::message::object_path* appliedConfig = nullptr;
534 const bool* baseSpeedPriorityEnabled = nullptr;
535
536 const bool success = sdbusplus::unpackPropertiesNoThrow(
537 dbus_utils::UnpackErrorPrinter(), properties, "AppliedConfig",
538 appliedConfig, "BaseSpeedPriorityEnabled",
539 baseSpeedPriorityEnabled);
540
541 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700542 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200543 messages::internalError(aResp->res);
544 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700545 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200546
547 if (appliedConfig != nullptr)
548 {
549 const std::string& dbusPath = appliedConfig->str;
550 std::string uri = "/redfish/v1/Systems/system/Processors/" + cpuId +
551 "/OperatingConfigs";
552 nlohmann::json::object_t operatingConfig;
553 operatingConfig["@odata.id"] = uri;
554 json["OperatingConfigs"] = std::move(operatingConfig);
555
556 // Reuse the D-Bus config object name for the Redfish
557 // URI
558 size_t baseNamePos = dbusPath.rfind('/');
559 if (baseNamePos == std::string::npos ||
560 baseNamePos == (dbusPath.size() - 1))
561 {
562 // If the AppliedConfig was somehow not a valid path,
563 // skip adding any more properties, since everything
564 // else is tied to this applied config.
565 messages::internalError(aResp->res);
566 return;
567 }
568 uri += '/';
569 uri += dbusPath.substr(baseNamePos + 1);
570 nlohmann::json::object_t appliedOperatingConfig;
571 appliedOperatingConfig["@odata.id"] = uri;
572 json["AppliedOperatingConfig"] = std::move(appliedOperatingConfig);
573
574 // Once we found the current applied config, queue another
575 // request to read the base freq core ids out of that
576 // config.
577 sdbusplus::asio::getProperty<BaseSpeedPrioritySettingsProperty>(
578 *crow::connections::systemBus, service, dbusPath,
579 "xyz.openbmc_project.Inventory.Item.Cpu."
580 "OperatingConfig",
581 "BaseSpeedPrioritySettings",
582 [aResp](
583 const boost::system::error_code ec2,
584 const BaseSpeedPrioritySettingsProperty& baseSpeedList) {
585 if (ec2)
586 {
587 BMCWEB_LOG_WARNING << "D-Bus Property Get error: " << ec2;
588 messages::internalError(aResp->res);
589 return;
590 }
591
592 highSpeedCoreIdsHandler(aResp, baseSpeedList);
593 });
594 }
595
596 if (baseSpeedPriorityEnabled != nullptr)
597 {
598 json["BaseSpeedPriorityState"] =
599 *baseSpeedPriorityEnabled ? "Enabled" : "Disabled";
600 }
601 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800602}
603
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600604/**
605 * @brief Fill out location info of a processor by
606 * requesting data from the given D-Bus object.
607 *
608 * @param[in,out] aResp Async HTTP response.
609 * @param[in] service D-Bus service to query.
610 * @param[in] objPath D-Bus object to query.
611 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800612inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600613 const std::string& service,
614 const std::string& objPath)
615{
616 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700617 sdbusplus::asio::getProperty<std::string>(
618 *crow::connections::systemBus, service, objPath,
619 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
620 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
621 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700622 if (ec)
623 {
624 BMCWEB_LOG_DEBUG << "DBUS response error";
625 messages::internalError(aResp->res);
626 return;
627 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600628
Ed Tanous002d39b2022-05-31 08:59:27 -0700629 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
630 property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700631 });
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600632}
633
Jonathan Domanc9514482021-02-24 09:20:51 -0800634/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800635 * Populate the unique identifier in a Processor resource by requesting data
636 * from the given D-Bus object.
637 *
638 * @param[in,out] aResp Async HTTP response.
639 * @param[in] service D-Bus service to query.
640 * @param[in] objPath D-Bus object to query.
641 */
642inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
643 const std::string& service,
644 const std::string& objectPath)
645{
646 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700647 sdbusplus::asio::getProperty<std::string>(
648 *crow::connections::systemBus, service, objectPath,
649 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
650 "UniqueIdentifier",
651 [aResp](boost::system::error_code ec, const std::string& id) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700652 if (ec)
653 {
654 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
655 messages::internalError(aResp->res);
656 return;
657 }
658 aResp->res.jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] =
659 id;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700660 });
Jonathan Doman49e429c2021-03-03 13:11:44 -0800661}
662
663/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800664 * Find the D-Bus object representing the requested Processor, and call the
665 * handler with the results. If matching object is not found, add 404 error to
666 * response and don't call the handler.
667 *
668 * @param[in,out] resp Async HTTP response.
669 * @param[in] processorId Redfish Processor Id.
670 * @param[in] handler Callback to continue processing request upon
671 * successfully finding object.
672 */
673template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800674inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800675 const std::string& processorId,
676 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500677{
678 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
679
Jonathan Domanc9514482021-02-24 09:20:51 -0800680 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500681 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800682 [resp, processorId, handler = std::forward<Handler>(handler)](
683 boost::system::error_code ec,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600684 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700685 if (ec)
686 {
687 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
688 messages::internalError(resp->res);
689 return;
690 }
691 for (const auto& [objectPath, serviceMap] : subtree)
692 {
693 // Ignore any objects which don't end with our desired cpu name
Ed Tanous11ba3972022-07-11 09:50:41 -0700694 if (!objectPath.ends_with(processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500695 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700696 continue;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500697 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700698
699 bool found = false;
700 // Filter out objects that don't have the CPU-specific
701 // interfaces to make sure we can return 404 on non-CPUs
702 // (e.g. /redfish/../Processors/dimm0)
703 for (const auto& [serviceName, interfaceList] : serviceMap)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500704 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700705 if (std::find_first_of(
706 interfaceList.begin(), interfaceList.end(),
707 processorInterfaces.begin(),
708 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500709 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700710 found = true;
711 break;
Jonathan Doman2bab9832020-12-02 15:27:40 -0800712 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500713 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700714
715 if (!found)
716 {
717 continue;
718 }
719
720 // Process the first object which does match our cpu name and
721 // required interfaces, and potentially ignore any other
722 // matching objects. Assume all interfaces we want to process
723 // must be on the same object path.
724
Ed Tanous8a592812022-06-04 09:06:59 -0700725 handler(objectPath, serviceMap);
Ed Tanous002d39b2022-05-31 08:59:27 -0700726 return;
727 }
728 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500729 },
730 "xyz.openbmc_project.ObjectMapper",
731 "/xyz/openbmc_project/object_mapper",
732 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800733 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800734 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530735 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800736 "xyz.openbmc_project.Inventory.Decorator.Asset",
737 "xyz.openbmc_project.Inventory.Decorator.Revision",
738 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600739 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800740 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800741 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
742 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500743}
744
zhanghch058d1b46d2021-04-01 11:18:24 +0800745inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800746 const std::string& processorId,
747 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600748 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Domanc9514482021-02-24 09:20:51 -0800749{
750 for (const auto& [serviceName, interfaceList] : serviceMap)
751 {
752 for (const auto& interface : interfaceList)
753 {
754 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
755 {
756 getCpuAssetData(aResp, serviceName, objectPath);
757 }
George Liu0fda0f12021-11-16 10:06:17 +0800758 else if (interface ==
759 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800760 {
761 getCpuRevisionData(aResp, serviceName, objectPath);
762 }
763 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
764 {
765 getCpuDataByService(aResp, processorId, serviceName,
766 objectPath);
767 }
George Liu0fda0f12021-11-16 10:06:17 +0800768 else if (interface ==
769 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800770 {
771 getAcceleratorDataByService(aResp, processorId, serviceName,
772 objectPath);
773 }
George Liu0fda0f12021-11-16 10:06:17 +0800774 else if (
775 interface ==
776 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800777 {
778 getCpuConfigData(aResp, processorId, serviceName, objectPath);
779 }
George Liu0fda0f12021-11-16 10:06:17 +0800780 else if (interface ==
781 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800782 {
783 getCpuLocationCode(aResp, serviceName, objectPath);
784 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530785 else if (interface == "xyz.openbmc_project.Common.UUID")
786 {
787 getProcessorUUID(aResp, serviceName, objectPath);
788 }
George Liu0fda0f12021-11-16 10:06:17 +0800789 else if (interface ==
790 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800791 {
792 getCpuUniqueId(aResp, serviceName, objectPath);
793 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800794 }
795 }
796}
797
Jonathan Domandba0c292020-12-02 15:34:13 -0800798/**
799 * Request all the properties for the given D-Bus object and fill out the
800 * related entries in the Redfish OperatingConfig response.
801 *
802 * @param[in,out] aResp Async HTTP response.
803 * @param[in] service D-Bus service name to query.
804 * @param[in] objPath D-Bus object to query.
805 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800806inline void
807 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
808 const std::string& service,
809 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800810{
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200811 sdbusplus::asio::getAllProperties(
812 *crow::connections::systemBus, service, objPath,
813 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig",
Ed Tanous914e2d52022-01-07 11:38:34 -0800814 [aResp](const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200815 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700816 if (ec)
817 {
818 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message();
819 messages::internalError(aResp->res);
820 return;
821 }
822
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200823 const size_t* availableCoreCount = nullptr;
824 const uint32_t* baseSpeed = nullptr;
825 const uint32_t* maxJunctionTemperature = nullptr;
826 const uint32_t* maxSpeed = nullptr;
827 const uint32_t* powerLimit = nullptr;
828 const TurboProfileProperty* turboProfile = nullptr;
829 const BaseSpeedPrioritySettingsProperty* baseSpeedPrioritySettings =
830 nullptr;
831
832 const bool success = sdbusplus::unpackPropertiesNoThrow(
833 dbus_utils::UnpackErrorPrinter(), properties, "AvailableCoreCount",
834 availableCoreCount, "BaseSpeed", baseSpeed,
835 "MaxJunctionTemperature", maxJunctionTemperature, "MaxSpeed",
836 maxSpeed, "PowerLimit", powerLimit, "TurboProfile", turboProfile,
837 "BaseSpeedPrioritySettings", baseSpeedPrioritySettings);
838
839 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700840 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200841 messages::internalError(aResp->res);
842 return;
843 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700844
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200845 nlohmann::json& json = aResp->res.jsonValue;
Ed Tanous002d39b2022-05-31 08:59:27 -0700846
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200847 if (availableCoreCount != nullptr)
848 {
849 json["TotalAvailableCoreCount"] = *availableCoreCount;
850 }
851
852 if (baseSpeed != nullptr)
853 {
854 json["BaseSpeedMHz"] = *baseSpeed;
855 }
856
857 if (maxJunctionTemperature != nullptr)
858 {
859 json["MaxJunctionTemperatureCelsius"] = *maxJunctionTemperature;
860 }
861
862 if (maxSpeed != nullptr)
863 {
864 json["MaxSpeedMHz"] = *maxSpeed;
865 }
866
867 if (powerLimit != nullptr)
868 {
869 json["TDPWatts"] = *powerLimit;
870 }
871
872 if (turboProfile != nullptr)
873 {
874 nlohmann::json& turboArray = json["TurboProfile"];
875 turboArray = nlohmann::json::array();
876 for (const auto& [turboSpeed, coreCount] : *turboProfile)
877 {
878 nlohmann::json::object_t turbo;
879 turbo["ActiveCoreCount"] = coreCount;
880 turbo["MaxSpeedMHz"] = turboSpeed;
881 turboArray.push_back(std::move(turbo));
Ed Tanous002d39b2022-05-31 08:59:27 -0700882 }
883 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200884
885 if (baseSpeedPrioritySettings != nullptr)
886 {
887 nlohmann::json& baseSpeedArray = json["BaseSpeedPrioritySettings"];
888 baseSpeedArray = nlohmann::json::array();
889 for (const auto& [baseSpeedMhz, coreList] :
890 *baseSpeedPrioritySettings)
891 {
892 nlohmann::json::object_t speed;
893 speed["CoreCount"] = coreList.size();
894 speed["CoreIDs"] = coreList;
895 speed["BaseSpeedMHz"] = baseSpeedMhz;
896 baseSpeedArray.push_back(std::move(speed));
897 }
898 }
899 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800900}
901
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800902/**
903 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
904 * property. Main task is to translate error messages into Redfish errors.
905 *
906 * @param[in,out] resp HTTP response.
907 * @param[in] setPropVal Value which we attempted to set.
908 * @param[in] ec D-Bus response error code.
909 * @param[in] msg D-Bus response message.
910 */
911inline void
912 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
913 const std::string& setPropVal,
914 boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500915 const sdbusplus::message_t& msg)
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800916{
917 if (!ec)
918 {
919 BMCWEB_LOG_DEBUG << "Set Property succeeded";
920 return;
921 }
922
923 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
924
925 const sd_bus_error* dbusError = msg.get_error();
926 if (dbusError == nullptr)
927 {
928 messages::internalError(resp->res);
929 return;
930 }
931
932 // The asio error code doesn't know about our custom errors, so we have to
933 // parse the error string. Some of these D-Bus -> Redfish translations are a
934 // stretch, but it's good to try to communicate something vaguely useful.
935 if (strcmp(dbusError->name,
936 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
937 {
938 // Service did not like the object_path we tried to set.
939 messages::propertyValueIncorrect(
940 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
941 }
942 else if (strcmp(dbusError->name,
943 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
944 {
945 // Service indicates we can never change the config for this processor.
946 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
947 }
948 else if (strcmp(dbusError->name,
949 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
950 {
951 // Service indicates the config cannot be changed right now, but maybe
952 // in a different system state.
953 messages::resourceInStandby(resp->res);
954 }
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800955 else
956 {
957 messages::internalError(resp->res);
958 }
959}
960
961/**
962 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
963 * validation of the input data, and then set the D-Bus property.
964 *
965 * @param[in,out] resp Async HTTP response.
966 * @param[in] processorId Processor's Id.
967 * @param[in] appliedConfigUri New property value to apply.
968 * @param[in] cpuObjectPath Path of CPU object to modify.
969 * @param[in] serviceMap Service map for CPU object.
970 */
971inline void patchAppliedOperatingConfig(
972 const std::shared_ptr<bmcweb::AsyncResp>& resp,
973 const std::string& processorId, const std::string& appliedConfigUri,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600974 const std::string& cpuObjectPath,
975 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800976{
977 // Check that the property even exists by checking for the interface
978 const std::string* controlService = nullptr;
979 for (const auto& [serviceName, interfaceList] : serviceMap)
980 {
981 if (std::find(interfaceList.begin(), interfaceList.end(),
982 "xyz.openbmc_project.Control.Processor."
983 "CurrentOperatingConfig") != interfaceList.end())
984 {
985 controlService = &serviceName;
986 break;
987 }
988 }
989
990 if (controlService == nullptr)
991 {
992 messages::internalError(resp->res);
993 return;
994 }
995
996 // Check that the config URI is a child of the cpu URI being patched.
997 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
998 expectedPrefix += processorId;
999 expectedPrefix += "/OperatingConfigs/";
Ed Tanous11ba3972022-07-11 09:50:41 -07001000 if (!appliedConfigUri.starts_with(expectedPrefix) ||
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001001 expectedPrefix.size() == appliedConfigUri.size())
1002 {
1003 messages::propertyValueIncorrect(
1004 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1005 return;
1006 }
1007
1008 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1009 // direct child of the CPU object.
1010 // Strip the expectedPrefix from the config URI to get the "filename", and
1011 // append to the CPU's path.
1012 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1013 sdbusplus::message::object_path configPath(cpuObjectPath);
1014 configPath /= configBaseName;
1015
1016 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1017
1018 // Set the property, with handler to check error responses
1019 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -08001020 [resp, appliedConfigUri](const boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -05001021 const sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001022 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001023 },
1024 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1025 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
Ed Tanous168e20c2021-12-13 14:39:53 -08001026 "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001027}
1028
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001029inline void handleProcessorHead(crow::App& app, const crow::Request& req,
1030 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1031 const std::string& /* systemName */,
1032 const std::string& /* processorId */)
1033{
1034 if (!redfish::setUpRedfishRoute(app, req, aResp))
1035 {
1036 return;
1037 }
1038 aResp->res.addHeader(
1039 boost::beast::http::field::link,
1040 "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby");
1041}
1042
1043inline void handleProcessorCollectionHead(
1044 crow::App& app, const crow::Request& req,
1045 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1046 const std::string& /* systemName */)
1047{
1048 if (!redfish::setUpRedfishRoute(app, req, aResp))
1049 {
1050 return;
1051 }
1052 aResp->res.addHeader(
1053 boost::beast::http::field::link,
1054 "</redfish/v1/JsonSchemas/ProcessorCollection/ProcessorCollection.json>; rel=describedby");
1055}
1056
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001057inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001058{
Jonathan Domandba0c292020-12-02 15:34:13 -08001059
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001060 BMCWEB_ROUTE(
1061 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001062 .privileges(redfish::privileges::getOperatingConfigCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001063 .methods(boost::beast::http::verb::get)(
1064 [&app](const crow::Request& req,
1065 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1066 const std::string& cpuName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001067 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001068 {
1069 return;
1070 }
1071 asyncResp->res.jsonValue["@odata.type"] =
1072 "#OperatingConfigCollection.OperatingConfigCollection";
1073 asyncResp->res.jsonValue["@odata.id"] = req.url;
1074 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
1075
1076 // First find the matching CPU object so we know how to
1077 // constrain our search for related Config objects.
1078 crow::connections::systemBus->async_method_call(
1079 [asyncResp, cpuName](
1080 const boost::system::error_code ec,
1081 const dbus::utility::MapperGetSubTreePathsResponse& objects) {
1082 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001083 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001084 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1085 << ec.message();
1086 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001087 return;
1088 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001089
Ed Tanous002d39b2022-05-31 08:59:27 -07001090 for (const std::string& object : objects)
1091 {
Ed Tanous11ba3972022-07-11 09:50:41 -07001092 if (!object.ends_with(cpuName))
Ed Tanous002d39b2022-05-31 08:59:27 -07001093 {
1094 continue;
1095 }
George Liu0fda0f12021-11-16 10:06:17 +08001096
Ed Tanous002d39b2022-05-31 08:59:27 -07001097 // Not expected that there will be multiple matching
1098 // CPU objects, but if there are just use the first
1099 // one.
Jonathan Domandba0c292020-12-02 15:34:13 -08001100
Ed Tanous002d39b2022-05-31 08:59:27 -07001101 // Use the common search routine to construct the
1102 // Collection of all Config objects under this CPU.
1103 collection_util::getCollectionMembers(
1104 asyncResp,
Willy Tuae9031f2022-09-27 05:48:07 +00001105 crow::utility::urlFromPieces("redfish", "v1", "Systems",
1106 "system", "Processors",
1107 cpuName, "OperatingConfigs"),
Ed Tanous002d39b2022-05-31 08:59:27 -07001108 {"xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"},
1109 object.c_str());
1110 return;
1111 }
1112 },
1113 "xyz.openbmc_project.ObjectMapper",
1114 "/xyz/openbmc_project/object_mapper",
1115 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
1116 "/xyz/openbmc_project/inventory", 0,
1117 std::array<const char*, 1>{
1118 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"});
George Liu0fda0f12021-11-16 10:06:17 +08001119 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001120}
1121
1122inline void requestRoutesOperatingConfig(App& app)
1123{
1124 BMCWEB_ROUTE(
1125 app,
1126 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001127 .privileges(redfish::privileges::getOperatingConfig)
Ed Tanous002d39b2022-05-31 08:59:27 -07001128 .methods(boost::beast::http::verb::get)(
1129 [&app](const crow::Request& req,
1130 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1131 const std::string& cpuName, const std::string& configName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001132 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001133 {
1134 return;
1135 }
1136 // Ask for all objects implementing OperatingConfig so we can search
1137 // for one with a matching name
1138 crow::connections::systemBus->async_method_call(
1139 [asyncResp, cpuName, configName, reqUrl{req.url}](
1140 boost::system::error_code ec,
1141 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1142 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001143 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001144 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1145 << ec.message();
1146 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001147 return;
1148 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001149 const std::string expectedEnding = cpuName + '/' + configName;
1150 for (const auto& [objectPath, serviceMap] : subtree)
1151 {
1152 // Ignore any configs without matching cpuX/configY
Ed Tanous11ba3972022-07-11 09:50:41 -07001153 if (!objectPath.ends_with(expectedEnding) || serviceMap.empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001154 {
1155 continue;
1156 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001157
Ed Tanous002d39b2022-05-31 08:59:27 -07001158 nlohmann::json& json = asyncResp->res.jsonValue;
1159 json["@odata.type"] = "#OperatingConfig.v1_0_0.OperatingConfig";
1160 json["@odata.id"] = reqUrl;
1161 json["Name"] = "Processor Profile";
1162 json["Id"] = configName;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001163
Ed Tanous002d39b2022-05-31 08:59:27 -07001164 // Just use the first implementation of the object - not
1165 // expected that there would be multiple matching
1166 // services
1167 getOperatingConfigData(asyncResp, serviceMap.begin()->first,
1168 objectPath);
1169 return;
1170 }
1171 messages::resourceNotFound(asyncResp->res, "OperatingConfig",
1172 configName);
1173 },
1174 "xyz.openbmc_project.ObjectMapper",
1175 "/xyz/openbmc_project/object_mapper",
1176 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1177 "/xyz/openbmc_project/inventory", 0,
1178 std::array<const char*, 1>{
1179 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001180 });
1181}
Jonathan Domandba0c292020-12-02 15:34:13 -08001182
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001183inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001184{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001185 /**
1186 * Functions triggers appropriate requests on DBus
1187 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001188 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/")
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001189 .privileges(redfish::privileges::headProcessorCollection)
1190 .methods(boost::beast::http::verb::head)(
1191 std::bind_front(handleProcessorCollectionHead, std::ref(app)));
1192
1193 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001194 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001195 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001196 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001197 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1198 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001199 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001200 {
1201 return;
1202 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001203 if (systemName != "system")
1204 {
1205 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1206 systemName);
1207 return;
1208 }
1209
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001210 asyncResp->res.addHeader(
1211 boost::beast::http::field::link,
1212 "</redfish/v1/JsonSchemas/ProcessorCollection/ProcessorCollection.json>; rel=describedby");
1213
Ed Tanous002d39b2022-05-31 08:59:27 -07001214 asyncResp->res.jsonValue["@odata.type"] =
1215 "#ProcessorCollection.ProcessorCollection";
1216 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001217
Ed Tanous002d39b2022-05-31 08:59:27 -07001218 asyncResp->res.jsonValue["@odata.id"] =
1219 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001220
Ed Tanous002d39b2022-05-31 08:59:27 -07001221 collection_util::getCollectionMembers(
Willy Tuae9031f2022-09-27 05:48:07 +00001222 asyncResp,
1223 boost::urls::url("/redfish/v1/Systems/system/Processors"),
Ed Tanous002d39b2022-05-31 08:59:27 -07001224 std::vector<const char*>(processorInterfaces.begin(),
1225 processorInterfaces.end()));
1226 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001227}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001228
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001229inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001230{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001231 /**
1232 * Functions triggers appropriate requests on DBus
1233 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001234
Ed Tanous22d268c2022-05-19 09:39:07 -07001235 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001236 .privileges(redfish::privileges::headProcessor)
1237 .methods(boost::beast::http::verb::head)(
1238 std::bind_front(handleProcessorHead, std::ref(app)));
1239
1240 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001241 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001242 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001243 [&app](const crow::Request& req,
1244 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001245 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07001246 const std::string& processorId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001247 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001248 {
1249 return;
1250 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001251 if (systemName != "system")
1252 {
1253 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1254 systemName);
1255 return;
1256 }
1257
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001258 asyncResp->res.addHeader(
1259 boost::beast::http::field::link,
1260 "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby");
Ed Tanous002d39b2022-05-31 08:59:27 -07001261 asyncResp->res.jsonValue["@odata.type"] =
1262 "#Processor.v1_11_0.Processor";
1263 asyncResp->res.jsonValue["@odata.id"] =
1264 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001265
Ed Tanous8a592812022-06-04 09:06:59 -07001266 getProcessorObject(
1267 asyncResp, processorId,
1268 std::bind_front(getProcessorData, asyncResp, processorId));
Ed Tanous002d39b2022-05-31 08:59:27 -07001269 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001270
Ed Tanous22d268c2022-05-19 09:39:07 -07001271 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001272 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001273 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001274 [&app](const crow::Request& req,
1275 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001276 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07001277 const std::string& processorId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001278 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001279 {
1280 return;
1281 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001282 if (systemName != "system")
1283 {
1284 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1285 systemName);
1286 return;
1287 }
1288
Ed Tanous002d39b2022-05-31 08:59:27 -07001289 std::optional<nlohmann::json> appliedConfigJson;
1290 if (!json_util::readJsonPatch(req, asyncResp->res,
1291 "AppliedOperatingConfig",
1292 appliedConfigJson))
1293 {
1294 return;
1295 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001296
Ed Tanous002d39b2022-05-31 08:59:27 -07001297 if (appliedConfigJson)
1298 {
Ed Tanousf8fe53e2022-06-30 15:55:45 -07001299 std::string appliedConfigUri;
Ed Tanous002d39b2022-05-31 08:59:27 -07001300 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1301 "@odata.id", appliedConfigUri))
1302 {
1303 return;
1304 }
1305 // Check for 404 and find matching D-Bus object, then run
1306 // property patch handlers if that all succeeds.
Ed Tanous8a592812022-06-04 09:06:59 -07001307 getProcessorObject(asyncResp, processorId,
1308 std::bind_front(patchAppliedOperatingConfig,
1309 asyncResp, processorId,
1310 appliedConfigUri));
Ed Tanous002d39b2022-05-31 08:59:27 -07001311 }
1312 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001313}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001314
1315} // namespace redfish