blob: f5203a92eab9ad8da38c1f4ac07fdb89c5317c84 [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"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
Jonathan Doman1e1e5982021-06-11 09:36:17 -070020#include "error_messages.hpp"
Gunnar Millsac6a4442020-10-14 14:55:29 -050021#include "health.hpp"
22
John Edward Broadbent7e860f12021-04-08 15:57:16 -070023#include <app.hpp>
Gunnar Millsac6a4442020-10-14 14:55:29 -050024#include <boost/container/flat_map.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
George Liu7a1dbc42022-12-07 16:03:22 +080035#include <array>
36#include <string_view>
37
Gunnar Millsac6a4442020-10-14 14:55:29 -050038namespace redfish
39{
40
Jonathan Domanc9514482021-02-24 09:20:51 -080041// Interfaces which imply a D-Bus object represents a Processor
George Liu7a1dbc42022-12-07 16:03:22 +080042constexpr std::array<std::string_view, 2> processorInterfaces = {
Jonathan Domanc9514482021-02-24 09:20:51 -080043 "xyz.openbmc_project.Inventory.Item.Cpu",
44 "xyz.openbmc_project.Inventory.Item.Accelerator"};
Jonathan Doman2bab9832020-12-02 15:27:40 -080045
Sharad Yadav71b82f22021-05-10 15:11:39 +053046/**
47 * @brief Fill out uuid info of a processor by
48 * requesting data from the given D-Bus object.
49 *
50 * @param[in,out] aResp Async HTTP response.
51 * @param[in] service D-Bus service to query.
52 * @param[in] objPath D-Bus object to query.
53 */
54inline void getProcessorUUID(std::shared_ptr<bmcweb::AsyncResp> aResp,
55 const std::string& service,
56 const std::string& objPath)
57{
58 BMCWEB_LOG_DEBUG << "Get Processor UUID";
Jonathan Doman1e1e5982021-06-11 09:36:17 -070059 sdbusplus::asio::getProperty<std::string>(
60 *crow::connections::systemBus, service, objPath,
61 "xyz.openbmc_project.Common.UUID", "UUID",
62 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
63 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -070064 if (ec)
65 {
66 BMCWEB_LOG_DEBUG << "DBUS response error";
67 messages::internalError(aResp->res);
68 return;
69 }
70 aResp->res.jsonValue["UUID"] = property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -070071 });
Sharad Yadav71b82f22021-05-10 15:11:39 +053072}
73
Ed Tanous711ac7a2021-12-20 09:34:41 -080074inline void getCpuDataByInterface(
75 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
76 const dbus::utility::DBusInteracesMap& cpuInterfacesProperties)
Gunnar Millsac6a4442020-10-14 14:55:29 -050077{
78 BMCWEB_LOG_DEBUG << "Get CPU resources by interface.";
79
Chicago Duana1649ec2021-03-30 16:54:58 +080080 // Set the default value of state
81 aResp->res.jsonValue["Status"]["State"] = "Enabled";
82 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -050083
84 for (const auto& interface : cpuInterfacesProperties)
85 {
86 for (const auto& property : interface.second)
87 {
Chicago Duana1649ec2021-03-30 16:54:58 +080088 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -050089 {
Chicago Duana1649ec2021-03-30 16:54:58 +080090 const bool* cpuPresent = std::get_if<bool>(&property.second);
91 if (cpuPresent == nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -050092 {
93 // Important property not in desired type
94 messages::internalError(aResp->res);
95 return;
96 }
Ed Tanouse05aec52022-01-25 10:28:56 -080097 if (!*cpuPresent)
Gunnar Millsac6a4442020-10-14 14:55:29 -050098 {
Chicago Duana1649ec2021-03-30 16:54:58 +080099 // Slot is not populated
Gunnar Millsac6a4442020-10-14 14:55:29 -0500100 aResp->res.jsonValue["Status"]["State"] = "Absent";
Chicago Duana1649ec2021-03-30 16:54:58 +0800101 }
102 }
103 else if (property.first == "Functional")
104 {
105 const bool* cpuFunctional = std::get_if<bool>(&property.second);
106 if (cpuFunctional == nullptr)
107 {
108 messages::internalError(aResp->res);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500109 return;
110 }
Ed Tanouse05aec52022-01-25 10:28:56 -0800111 if (!*cpuFunctional)
Chicago Duana1649ec2021-03-30 16:54:58 +0800112 {
113 aResp->res.jsonValue["Status"]["Health"] = "Critical";
114 }
115 }
116 else if (property.first == "CoreCount")
117 {
118 const uint16_t* coresCount =
119 std::get_if<uint16_t>(&property.second);
120 if (coresCount == nullptr)
121 {
122 messages::internalError(aResp->res);
123 return;
124 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500125 aResp->res.jsonValue["TotalCores"] = *coresCount;
126 }
Jonathan Domandc3fa662020-10-26 23:10:24 -0700127 else if (property.first == "MaxSpeedInMhz")
128 {
129 const uint32_t* value = std::get_if<uint32_t>(&property.second);
130 if (value != nullptr)
131 {
132 aResp->res.jsonValue["MaxSpeedMHz"] = *value;
133 }
134 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500135 else if (property.first == "Socket")
136 {
137 const std::string* value =
138 std::get_if<std::string>(&property.second);
139 if (value != nullptr)
140 {
141 aResp->res.jsonValue["Socket"] = *value;
142 }
143 }
144 else if (property.first == "ThreadCount")
145 {
Jonathan Domandc3fa662020-10-26 23:10:24 -0700146 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500147 if (value != nullptr)
148 {
149 aResp->res.jsonValue["TotalThreads"] = *value;
150 }
151 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700152 else if (property.first == "EffectiveFamily")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500153 {
Brandon Kim1930fbd2021-09-14 17:52:51 -0700154 const uint16_t* value = std::get_if<uint16_t>(&property.second);
Brad Bishop6169de22022-09-14 13:08:32 -0400155 if (value != nullptr && *value != 2)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500156 {
157 aResp->res.jsonValue["ProcessorId"]["EffectiveFamily"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800158 "0x" + intToHexString(*value, 4);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500159 }
160 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700161 else if (property.first == "EffectiveModel")
162 {
163 const uint16_t* value = std::get_if<uint16_t>(&property.second);
164 if (value == nullptr)
165 {
166 messages::internalError(aResp->res);
167 return;
168 }
Brad Bishop6169de22022-09-14 13:08:32 -0400169 if (*value != 0)
170 {
171 aResp->res.jsonValue["ProcessorId"]["EffectiveModel"] =
172 "0x" + intToHexString(*value, 4);
173 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700174 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500175 else if (property.first == "Id")
176 {
177 const uint64_t* value = std::get_if<uint64_t>(&property.second);
178 if (value != nullptr && *value != 0)
179 {
Gunnar Millsac6a4442020-10-14 14:55:29 -0500180 aResp->res
181 .jsonValue["ProcessorId"]["IdentificationRegisters"] =
Ed Tanous866e4862022-02-17 11:40:25 -0800182 "0x" + intToHexString(*value, 16);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500183 }
184 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700185 else if (property.first == "Microcode")
186 {
187 const uint32_t* value = std::get_if<uint32_t>(&property.second);
188 if (value == nullptr)
189 {
190 messages::internalError(aResp->res);
191 return;
192 }
Brad Bishop6169de22022-09-14 13:08:32 -0400193 if (*value != 0)
194 {
195 aResp->res.jsonValue["ProcessorId"]["MicrocodeInfo"] =
196 "0x" + intToHexString(*value, 8);
197 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700198 }
199 else if (property.first == "Step")
200 {
201 const uint16_t* value = std::get_if<uint16_t>(&property.second);
202 if (value == nullptr)
203 {
204 messages::internalError(aResp->res);
205 return;
206 }
Brad Bishop6169de22022-09-14 13:08:32 -0400207 if (*value != 0)
208 {
209 aResp->res.jsonValue["ProcessorId"]["Step"] =
210 "0x" + intToHexString(*value, 4);
211 }
Brandon Kim1930fbd2021-09-14 17:52:51 -0700212 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500213 }
214 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500215}
216
zhanghch058d1b46d2021-04-01 11:18:24 +0800217inline void getCpuDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500218 const std::string& cpuId,
219 const std::string& service,
220 const std::string& objPath)
221{
222 BMCWEB_LOG_DEBUG << "Get available system cpu resources by service.";
223
224 crow::connections::systemBus->async_method_call(
225 [cpuId, service, objPath, aResp{std::move(aResp)}](
226 const boost::system::error_code ec,
227 const dbus::utility::ManagedObjectType& dbusData) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700228 if (ec)
229 {
230 BMCWEB_LOG_DEBUG << "DBUS response error";
231 messages::internalError(aResp->res);
232 return;
233 }
234 aResp->res.jsonValue["Id"] = cpuId;
235 aResp->res.jsonValue["Name"] = "Processor";
236 aResp->res.jsonValue["ProcessorType"] = "CPU";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500237
Ed Tanous002d39b2022-05-31 08:59:27 -0700238 bool slotPresent = false;
239 std::string corePath = objPath + "/core";
240 size_t totalCores = 0;
241 for (const auto& object : dbusData)
242 {
243 if (object.first.str == objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500244 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700245 getCpuDataByInterface(aResp, object.second);
246 }
Ed Tanous11ba3972022-07-11 09:50:41 -0700247 else if (object.first.str.starts_with(corePath))
Ed Tanous002d39b2022-05-31 08:59:27 -0700248 {
249 for (const auto& interface : object.second)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500250 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700251 if (interface.first == "xyz.openbmc_project.Inventory.Item")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500252 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700253 for (const auto& property : interface.second)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500254 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700255 if (property.first == "Present")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500256 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700257 const bool* present =
258 std::get_if<bool>(&property.second);
259 if (present != nullptr)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500260 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700261 if (*present)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500262 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700263 slotPresent = true;
264 totalCores++;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500265 }
266 }
267 }
268 }
269 }
270 }
271 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700272 }
273 // In getCpuDataByInterface(), state and health are set
274 // based on the present and functional status. If core
275 // count is zero, then it has a higher precedence.
276 if (slotPresent)
277 {
278 if (totalCores == 0)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500279 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700280 // Slot is not populated, set status end return
281 aResp->res.jsonValue["Status"]["State"] = "Absent";
282 aResp->res.jsonValue["Status"]["Health"] = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500283 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700284 aResp->res.jsonValue["TotalCores"] = totalCores;
285 }
286 return;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500287 },
288 service, "/xyz/openbmc_project/inventory",
289 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
290}
291
zhanghch058d1b46d2021-04-01 11:18:24 +0800292inline void getCpuAssetData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500293 const std::string& service,
294 const std::string& objPath)
295{
296 BMCWEB_LOG_DEBUG << "Get Cpu Asset Data";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200297 sdbusplus::asio::getAllProperties(
298 *crow::connections::systemBus, service, objPath,
299 "xyz.openbmc_project.Inventory.Decorator.Asset",
Gunnar Millsac6a4442020-10-14 14:55:29 -0500300 [objPath, aResp{std::move(aResp)}](
301 const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200302 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700303 if (ec)
304 {
305 BMCWEB_LOG_DEBUG << "DBUS response error";
306 messages::internalError(aResp->res);
307 return;
308 }
309
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200310 const std::string* serialNumber = nullptr;
311 const std::string* model = nullptr;
312 const std::string* manufacturer = nullptr;
313 const std::string* partNumber = nullptr;
314 const std::string* sparePartNumber = nullptr;
315
316 const bool success = sdbusplus::unpackPropertiesNoThrow(
317 dbus_utils::UnpackErrorPrinter(), properties, "SerialNumber",
318 serialNumber, "Model", model, "Manufacturer", manufacturer,
319 "PartNumber", partNumber, "SparePartNumber", sparePartNumber);
320
321 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200323 messages::internalError(aResp->res);
324 return;
325 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700326
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200327 if (serialNumber != nullptr && !serialNumber->empty())
328 {
329 aResp->res.jsonValue["SerialNumber"] = *serialNumber;
330 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700331
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200332 if ((model != nullptr) && !model->empty())
333 {
334 aResp->res.jsonValue["Model"] = *model;
335 }
336
337 if (manufacturer != nullptr)
338 {
339 aResp->res.jsonValue["Manufacturer"] = *manufacturer;
340
341 // Otherwise would be unexpected.
342 if (manufacturer->find("Intel") != std::string::npos)
Ed Tanous002d39b2022-05-31 08:59:27 -0700343 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200344 aResp->res.jsonValue["ProcessorArchitecture"] = "x86";
345 aResp->res.jsonValue["InstructionSet"] = "x86-64";
Ed Tanous002d39b2022-05-31 08:59:27 -0700346 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200347 else if (manufacturer->find("IBM") != std::string::npos)
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200349 aResp->res.jsonValue["ProcessorArchitecture"] = "Power";
350 aResp->res.jsonValue["InstructionSet"] = "PowerISA";
Ed Tanous002d39b2022-05-31 08:59:27 -0700351 }
352 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200353
354 if (partNumber != nullptr)
355 {
356 aResp->res.jsonValue["PartNumber"] = *partNumber;
357 }
358
Brad Bishop6169de22022-09-14 13:08:32 -0400359 if (sparePartNumber != nullptr && !sparePartNumber->empty())
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200360 {
361 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
362 }
363 });
Gunnar Millsac6a4442020-10-14 14:55:29 -0500364}
365
zhanghch058d1b46d2021-04-01 11:18:24 +0800366inline void getCpuRevisionData(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Millsac6a4442020-10-14 14:55:29 -0500367 const std::string& service,
368 const std::string& objPath)
369{
370 BMCWEB_LOG_DEBUG << "Get Cpu Revision Data";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200371 sdbusplus::asio::getAllProperties(
372 *crow::connections::systemBus, service, objPath,
373 "xyz.openbmc_project.Inventory.Decorator.Revision",
Gunnar Millsac6a4442020-10-14 14:55:29 -0500374 [objPath, aResp{std::move(aResp)}](
375 const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200376 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700377 if (ec)
378 {
379 BMCWEB_LOG_DEBUG << "DBUS response error";
380 messages::internalError(aResp->res);
381 return;
382 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500383
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200384 const std::string* version = nullptr;
385
386 const bool success = sdbusplus::unpackPropertiesNoThrow(
387 dbus_utils::UnpackErrorPrinter(), properties, "Version", version);
388
389 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200391 messages::internalError(aResp->res);
392 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700393 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200394
395 if (version != nullptr)
396 {
397 aResp->res.jsonValue["Version"] = *version;
398 }
399 });
Gunnar Millsac6a4442020-10-14 14:55:29 -0500400}
401
zhanghch058d1b46d2021-04-01 11:18:24 +0800402inline void getAcceleratorDataByService(
403 std::shared_ptr<bmcweb::AsyncResp> aResp, const std::string& acclrtrId,
404 const std::string& service, const std::string& objPath)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500405{
406 BMCWEB_LOG_DEBUG
407 << "Get available system Accelerator resources by service.";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200408 sdbusplus::asio::getAllProperties(
409 *crow::connections::systemBus, service, objPath, "",
Gunnar Millsac6a4442020-10-14 14:55:29 -0500410 [acclrtrId, aResp{std::move(aResp)}](
411 const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200412 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 if (ec)
414 {
415 BMCWEB_LOG_DEBUG << "DBUS response error";
416 messages::internalError(aResp->res);
417 return;
418 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700419
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200420 const bool* functional = nullptr;
421 const bool* present = nullptr;
422
423 const bool success = sdbusplus::unpackPropertiesNoThrow(
424 dbus_utils::UnpackErrorPrinter(), properties, "Functional",
425 functional, "Present", present);
426
427 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700428 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200429 messages::internalError(aResp->res);
430 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500432
Ed Tanous002d39b2022-05-31 08:59:27 -0700433 std::string state = "Enabled";
434 std::string health = "OK";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500435
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200436 if (present != nullptr && !*present)
Ed Tanous002d39b2022-05-31 08:59:27 -0700437 {
438 state = "Absent";
439 }
440
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200441 if (functional != nullptr && !*functional)
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 {
443 if (state == "Enabled")
Gunnar Millsac6a4442020-10-14 14:55:29 -0500444 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700445 health = "Critical";
Gunnar Millsac6a4442020-10-14 14:55:29 -0500446 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700447 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500448
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200449 aResp->res.jsonValue["Id"] = acclrtrId;
450 aResp->res.jsonValue["Name"] = "Processor";
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 aResp->res.jsonValue["Status"]["State"] = state;
452 aResp->res.jsonValue["Status"]["Health"] = health;
453 aResp->res.jsonValue["ProcessorType"] = "Accelerator";
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200454 });
Gunnar Millsac6a4442020-10-14 14:55:29 -0500455}
456
Jonathan Domandba0c292020-12-02 15:34:13 -0800457// OperatingConfig D-Bus Types
458using TurboProfileProperty = std::vector<std::tuple<uint32_t, size_t>>;
459using BaseSpeedPrioritySettingsProperty =
460 std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>;
461// uint32_t and size_t may or may not be the same type, requiring a dedup'd
462// variant
Jonathan Domandba0c292020-12-02 15:34:13 -0800463
464/**
465 * Fill out the HighSpeedCoreIDs in a Processor resource from the given
466 * OperatingConfig D-Bus property.
467 *
468 * @param[in,out] aResp Async HTTP response.
469 * @param[in] baseSpeedSettings Full list of base speed priority groups,
470 * to use to determine the list of high
471 * speed cores.
472 */
473inline void highSpeedCoreIdsHandler(
zhanghch058d1b46d2021-04-01 11:18:24 +0800474 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800475 const BaseSpeedPrioritySettingsProperty& baseSpeedSettings)
476{
477 // The D-Bus property does not indicate which bucket is the "high
478 // priority" group, so let's discern that by looking for the one with
479 // highest base frequency.
480 auto highPriorityGroup = baseSpeedSettings.cend();
481 uint32_t highestBaseSpeed = 0;
482 for (auto it = baseSpeedSettings.cbegin(); it != baseSpeedSettings.cend();
483 ++it)
484 {
485 const uint32_t baseFreq = std::get<uint32_t>(*it);
486 if (baseFreq > highestBaseSpeed)
487 {
488 highestBaseSpeed = baseFreq;
489 highPriorityGroup = it;
490 }
491 }
492
493 nlohmann::json& jsonCoreIds = aResp->res.jsonValue["HighSpeedCoreIDs"];
494 jsonCoreIds = nlohmann::json::array();
495
496 // There may not be any entries in the D-Bus property, so only populate
497 // if there was actually something there.
498 if (highPriorityGroup != baseSpeedSettings.cend())
499 {
500 jsonCoreIds = std::get<std::vector<uint32_t>>(*highPriorityGroup);
501 }
502}
503
504/**
505 * Fill out OperatingConfig related items in a Processor resource by requesting
506 * data from the given D-Bus object.
507 *
508 * @param[in,out] aResp Async HTTP response.
509 * @param[in] cpuId CPU D-Bus name.
510 * @param[in] service D-Bus service to query.
511 * @param[in] objPath D-Bus object to query.
512 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800513inline void getCpuConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domandba0c292020-12-02 15:34:13 -0800514 const std::string& cpuId,
515 const std::string& service,
516 const std::string& objPath)
517{
518 BMCWEB_LOG_INFO << "Getting CPU operating configs for " << cpuId;
519
520 // First, GetAll CurrentOperatingConfig properties on the object
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200521 sdbusplus::asio::getAllProperties(
522 *crow::connections::systemBus, service, objPath,
523 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
524 [aResp, cpuId,
525 service](const boost::system::error_code ec,
526 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700527 if (ec)
528 {
529 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message();
530 messages::internalError(aResp->res);
531 return;
532 }
Jonathan Domandba0c292020-12-02 15:34:13 -0800533
Ed Tanous002d39b2022-05-31 08:59:27 -0700534 nlohmann::json& json = aResp->res.jsonValue;
Jonathan Domandba0c292020-12-02 15:34:13 -0800535
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200536 const sdbusplus::message::object_path* appliedConfig = nullptr;
537 const bool* baseSpeedPriorityEnabled = nullptr;
538
539 const bool success = sdbusplus::unpackPropertiesNoThrow(
540 dbus_utils::UnpackErrorPrinter(), properties, "AppliedConfig",
541 appliedConfig, "BaseSpeedPriorityEnabled",
542 baseSpeedPriorityEnabled);
543
544 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700545 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200546 messages::internalError(aResp->res);
547 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700548 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200549
550 if (appliedConfig != nullptr)
551 {
552 const std::string& dbusPath = appliedConfig->str;
553 std::string uri = "/redfish/v1/Systems/system/Processors/" + cpuId +
554 "/OperatingConfigs";
555 nlohmann::json::object_t operatingConfig;
556 operatingConfig["@odata.id"] = uri;
557 json["OperatingConfigs"] = std::move(operatingConfig);
558
559 // Reuse the D-Bus config object name for the Redfish
560 // URI
561 size_t baseNamePos = dbusPath.rfind('/');
562 if (baseNamePos == std::string::npos ||
563 baseNamePos == (dbusPath.size() - 1))
564 {
565 // If the AppliedConfig was somehow not a valid path,
566 // skip adding any more properties, since everything
567 // else is tied to this applied config.
568 messages::internalError(aResp->res);
569 return;
570 }
571 uri += '/';
572 uri += dbusPath.substr(baseNamePos + 1);
573 nlohmann::json::object_t appliedOperatingConfig;
574 appliedOperatingConfig["@odata.id"] = uri;
575 json["AppliedOperatingConfig"] = std::move(appliedOperatingConfig);
576
577 // Once we found the current applied config, queue another
578 // request to read the base freq core ids out of that
579 // config.
580 sdbusplus::asio::getProperty<BaseSpeedPrioritySettingsProperty>(
581 *crow::connections::systemBus, service, dbusPath,
582 "xyz.openbmc_project.Inventory.Item.Cpu."
583 "OperatingConfig",
584 "BaseSpeedPrioritySettings",
585 [aResp](
586 const boost::system::error_code ec2,
587 const BaseSpeedPrioritySettingsProperty& baseSpeedList) {
588 if (ec2)
589 {
590 BMCWEB_LOG_WARNING << "D-Bus Property Get error: " << ec2;
591 messages::internalError(aResp->res);
592 return;
593 }
594
595 highSpeedCoreIdsHandler(aResp, baseSpeedList);
596 });
597 }
598
599 if (baseSpeedPriorityEnabled != nullptr)
600 {
601 json["BaseSpeedPriorityState"] =
602 *baseSpeedPriorityEnabled ? "Enabled" : "Disabled";
603 }
604 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800605}
606
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600607/**
608 * @brief Fill out location info of a processor by
609 * requesting data from the given D-Bus object.
610 *
611 * @param[in,out] aResp Async HTTP response.
612 * @param[in] service D-Bus service to query.
613 * @param[in] objPath D-Bus object to query.
614 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800615inline void getCpuLocationCode(std::shared_ptr<bmcweb::AsyncResp> aResp,
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600616 const std::string& service,
617 const std::string& objPath)
618{
619 BMCWEB_LOG_DEBUG << "Get Cpu Location Data";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700620 sdbusplus::asio::getProperty<std::string>(
621 *crow::connections::systemBus, service, objPath,
622 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
623 [objPath, aResp{std::move(aResp)}](const boost::system::error_code ec,
624 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700625 if (ec)
626 {
627 BMCWEB_LOG_DEBUG << "DBUS response error";
628 messages::internalError(aResp->res);
629 return;
630 }
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600631
Ed Tanous002d39b2022-05-31 08:59:27 -0700632 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
633 property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700634 });
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600635}
636
Jonathan Domanc9514482021-02-24 09:20:51 -0800637/**
Jonathan Doman49e429c2021-03-03 13:11:44 -0800638 * Populate the unique identifier in a Processor resource by requesting data
639 * from the given D-Bus object.
640 *
641 * @param[in,out] aResp Async HTTP response.
642 * @param[in] service D-Bus service to query.
643 * @param[in] objPath D-Bus object to query.
644 */
645inline void getCpuUniqueId(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
646 const std::string& service,
647 const std::string& objectPath)
648{
649 BMCWEB_LOG_DEBUG << "Get CPU UniqueIdentifier";
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700650 sdbusplus::asio::getProperty<std::string>(
651 *crow::connections::systemBus, service, objectPath,
652 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier",
653 "UniqueIdentifier",
654 [aResp](boost::system::error_code ec, const std::string& id) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700655 if (ec)
656 {
657 BMCWEB_LOG_ERROR << "Failed to read cpu unique id: " << ec;
658 messages::internalError(aResp->res);
659 return;
660 }
661 aResp->res.jsonValue["ProcessorId"]["ProtectedIdentificationNumber"] =
662 id;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700663 });
Jonathan Doman49e429c2021-03-03 13:11:44 -0800664}
665
666/**
Jonathan Domanc9514482021-02-24 09:20:51 -0800667 * Find the D-Bus object representing the requested Processor, and call the
668 * handler with the results. If matching object is not found, add 404 error to
669 * response and don't call the handler.
670 *
671 * @param[in,out] resp Async HTTP response.
672 * @param[in] processorId Redfish Processor Id.
673 * @param[in] handler Callback to continue processing request upon
674 * successfully finding object.
675 */
676template <typename Handler>
zhanghch058d1b46d2021-04-01 11:18:24 +0800677inline void getProcessorObject(const std::shared_ptr<bmcweb::AsyncResp>& resp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800678 const std::string& processorId,
679 Handler&& handler)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500680{
681 BMCWEB_LOG_DEBUG << "Get available system processor resources.";
682
Jonathan Domanc9514482021-02-24 09:20:51 -0800683 // GetSubTree on all interfaces which provide info about a Processor
Gunnar Millsac6a4442020-10-14 14:55:29 -0500684 crow::connections::systemBus->async_method_call(
Jonathan Domanc9514482021-02-24 09:20:51 -0800685 [resp, processorId, handler = std::forward<Handler>(handler)](
686 boost::system::error_code ec,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600687 const dbus::utility::MapperGetSubTreeResponse& subtree) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700688 if (ec)
689 {
690 BMCWEB_LOG_DEBUG << "DBUS response error: " << ec;
691 messages::internalError(resp->res);
692 return;
693 }
694 for (const auto& [objectPath, serviceMap] : subtree)
695 {
696 // Ignore any objects which don't end with our desired cpu name
Ed Tanous11ba3972022-07-11 09:50:41 -0700697 if (!objectPath.ends_with(processorId))
Gunnar Millsac6a4442020-10-14 14:55:29 -0500698 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700699 continue;
Gunnar Millsac6a4442020-10-14 14:55:29 -0500700 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700701
702 bool found = false;
703 // Filter out objects that don't have the CPU-specific
704 // interfaces to make sure we can return 404 on non-CPUs
705 // (e.g. /redfish/../Processors/dimm0)
706 for (const auto& [serviceName, interfaceList] : serviceMap)
Gunnar Millsac6a4442020-10-14 14:55:29 -0500707 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700708 if (std::find_first_of(
709 interfaceList.begin(), interfaceList.end(),
710 processorInterfaces.begin(),
711 processorInterfaces.end()) != interfaceList.end())
Gunnar Millsac6a4442020-10-14 14:55:29 -0500712 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700713 found = true;
714 break;
Jonathan Doman2bab9832020-12-02 15:27:40 -0800715 }
Gunnar Millsac6a4442020-10-14 14:55:29 -0500716 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700717
718 if (!found)
719 {
720 continue;
721 }
722
723 // Process the first object which does match our cpu name and
724 // required interfaces, and potentially ignore any other
725 // matching objects. Assume all interfaces we want to process
726 // must be on the same object path.
727
Ed Tanous8a592812022-06-04 09:06:59 -0700728 handler(objectPath, serviceMap);
Ed Tanous002d39b2022-05-31 08:59:27 -0700729 return;
730 }
731 messages::resourceNotFound(resp->res, "Processor", processorId);
Gunnar Millsac6a4442020-10-14 14:55:29 -0500732 },
733 "xyz.openbmc_project.ObjectMapper",
734 "/xyz/openbmc_project/object_mapper",
735 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800736 "/xyz/openbmc_project/inventory", 0,
Jonathan Doman49e429c2021-03-03 13:11:44 -0800737 std::array<const char*, 8>{
Sharad Yadav71b82f22021-05-10 15:11:39 +0530738 "xyz.openbmc_project.Common.UUID",
Jonathan Doman2bab9832020-12-02 15:27:40 -0800739 "xyz.openbmc_project.Inventory.Decorator.Asset",
740 "xyz.openbmc_project.Inventory.Decorator.Revision",
741 "xyz.openbmc_project.Inventory.Item.Cpu",
SunnySrivastava1984cba4f442021-01-07 12:48:16 -0600742 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
Jonathan Domandba0c292020-12-02 15:34:13 -0800743 "xyz.openbmc_project.Inventory.Item.Accelerator",
Jonathan Doman49e429c2021-03-03 13:11:44 -0800744 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
745 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier"});
Gunnar Millsac6a4442020-10-14 14:55:29 -0500746}
747
zhanghch058d1b46d2021-04-01 11:18:24 +0800748inline void getProcessorData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jonathan Domanc9514482021-02-24 09:20:51 -0800749 const std::string& processorId,
750 const std::string& objectPath,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600751 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Domanc9514482021-02-24 09:20:51 -0800752{
753 for (const auto& [serviceName, interfaceList] : serviceMap)
754 {
755 for (const auto& interface : interfaceList)
756 {
757 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
758 {
759 getCpuAssetData(aResp, serviceName, objectPath);
760 }
George Liu0fda0f12021-11-16 10:06:17 +0800761 else if (interface ==
762 "xyz.openbmc_project.Inventory.Decorator.Revision")
Jonathan Domanc9514482021-02-24 09:20:51 -0800763 {
764 getCpuRevisionData(aResp, serviceName, objectPath);
765 }
766 else if (interface == "xyz.openbmc_project.Inventory.Item.Cpu")
767 {
768 getCpuDataByService(aResp, processorId, serviceName,
769 objectPath);
770 }
George Liu0fda0f12021-11-16 10:06:17 +0800771 else if (interface ==
772 "xyz.openbmc_project.Inventory.Item.Accelerator")
Jonathan Domanc9514482021-02-24 09:20:51 -0800773 {
774 getAcceleratorDataByService(aResp, processorId, serviceName,
775 objectPath);
776 }
George Liu0fda0f12021-11-16 10:06:17 +0800777 else if (
778 interface ==
779 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig")
Jonathan Domanc9514482021-02-24 09:20:51 -0800780 {
781 getCpuConfigData(aResp, processorId, serviceName, objectPath);
782 }
George Liu0fda0f12021-11-16 10:06:17 +0800783 else if (interface ==
784 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
Jonathan Domanc9514482021-02-24 09:20:51 -0800785 {
786 getCpuLocationCode(aResp, serviceName, objectPath);
787 }
Sharad Yadav71b82f22021-05-10 15:11:39 +0530788 else if (interface == "xyz.openbmc_project.Common.UUID")
789 {
790 getProcessorUUID(aResp, serviceName, objectPath);
791 }
George Liu0fda0f12021-11-16 10:06:17 +0800792 else if (interface ==
793 "xyz.openbmc_project.Inventory.Decorator.UniqueIdentifier")
Jonathan Doman49e429c2021-03-03 13:11:44 -0800794 {
795 getCpuUniqueId(aResp, serviceName, objectPath);
796 }
Jonathan Domanc9514482021-02-24 09:20:51 -0800797 }
798 }
799}
800
Jonathan Domandba0c292020-12-02 15:34:13 -0800801/**
802 * Request all the properties for the given D-Bus object and fill out the
803 * related entries in the Redfish OperatingConfig response.
804 *
805 * @param[in,out] aResp Async HTTP response.
806 * @param[in] service D-Bus service name to query.
807 * @param[in] objPath D-Bus object to query.
808 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800809inline void
810 getOperatingConfigData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
811 const std::string& service,
812 const std::string& objPath)
Jonathan Domandba0c292020-12-02 15:34:13 -0800813{
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200814 sdbusplus::asio::getAllProperties(
815 *crow::connections::systemBus, service, objPath,
816 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig",
Ed Tanous914e2d52022-01-07 11:38:34 -0800817 [aResp](const boost::system::error_code ec,
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200818 const dbus::utility::DBusPropertiesMap& properties) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700819 if (ec)
820 {
821 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", " << ec.message();
822 messages::internalError(aResp->res);
823 return;
824 }
825
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200826 const size_t* availableCoreCount = nullptr;
827 const uint32_t* baseSpeed = nullptr;
828 const uint32_t* maxJunctionTemperature = nullptr;
829 const uint32_t* maxSpeed = nullptr;
830 const uint32_t* powerLimit = nullptr;
831 const TurboProfileProperty* turboProfile = nullptr;
832 const BaseSpeedPrioritySettingsProperty* baseSpeedPrioritySettings =
833 nullptr;
834
835 const bool success = sdbusplus::unpackPropertiesNoThrow(
836 dbus_utils::UnpackErrorPrinter(), properties, "AvailableCoreCount",
837 availableCoreCount, "BaseSpeed", baseSpeed,
838 "MaxJunctionTemperature", maxJunctionTemperature, "MaxSpeed",
839 maxSpeed, "PowerLimit", powerLimit, "TurboProfile", turboProfile,
840 "BaseSpeedPrioritySettings", baseSpeedPrioritySettings);
841
842 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700843 {
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200844 messages::internalError(aResp->res);
845 return;
846 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700847
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200848 nlohmann::json& json = aResp->res.jsonValue;
Ed Tanous002d39b2022-05-31 08:59:27 -0700849
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200850 if (availableCoreCount != nullptr)
851 {
852 json["TotalAvailableCoreCount"] = *availableCoreCount;
853 }
854
855 if (baseSpeed != nullptr)
856 {
857 json["BaseSpeedMHz"] = *baseSpeed;
858 }
859
860 if (maxJunctionTemperature != nullptr)
861 {
862 json["MaxJunctionTemperatureCelsius"] = *maxJunctionTemperature;
863 }
864
865 if (maxSpeed != nullptr)
866 {
867 json["MaxSpeedMHz"] = *maxSpeed;
868 }
869
870 if (powerLimit != nullptr)
871 {
872 json["TDPWatts"] = *powerLimit;
873 }
874
875 if (turboProfile != nullptr)
876 {
877 nlohmann::json& turboArray = json["TurboProfile"];
878 turboArray = nlohmann::json::array();
879 for (const auto& [turboSpeed, coreCount] : *turboProfile)
880 {
881 nlohmann::json::object_t turbo;
882 turbo["ActiveCoreCount"] = coreCount;
883 turbo["MaxSpeedMHz"] = turboSpeed;
884 turboArray.push_back(std::move(turbo));
Ed Tanous002d39b2022-05-31 08:59:27 -0700885 }
886 }
Krzysztof Grobelny351053f2022-07-28 15:44:22 +0200887
888 if (baseSpeedPrioritySettings != nullptr)
889 {
890 nlohmann::json& baseSpeedArray = json["BaseSpeedPrioritySettings"];
891 baseSpeedArray = nlohmann::json::array();
892 for (const auto& [baseSpeedMhz, coreList] :
893 *baseSpeedPrioritySettings)
894 {
895 nlohmann::json::object_t speed;
896 speed["CoreCount"] = coreList.size();
897 speed["CoreIDs"] = coreList;
898 speed["BaseSpeedMHz"] = baseSpeedMhz;
899 baseSpeedArray.push_back(std::move(speed));
900 }
901 }
902 });
Jonathan Domandba0c292020-12-02 15:34:13 -0800903}
904
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800905/**
906 * Handle the D-Bus response from attempting to set the CPU's AppliedConfig
907 * property. Main task is to translate error messages into Redfish errors.
908 *
909 * @param[in,out] resp HTTP response.
910 * @param[in] setPropVal Value which we attempted to set.
911 * @param[in] ec D-Bus response error code.
912 * @param[in] msg D-Bus response message.
913 */
914inline void
915 handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp,
916 const std::string& setPropVal,
917 boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -0500918 const sdbusplus::message_t& msg)
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800919{
920 if (!ec)
921 {
922 BMCWEB_LOG_DEBUG << "Set Property succeeded";
923 return;
924 }
925
926 BMCWEB_LOG_DEBUG << "Set Property failed: " << ec;
927
928 const sd_bus_error* dbusError = msg.get_error();
929 if (dbusError == nullptr)
930 {
931 messages::internalError(resp->res);
932 return;
933 }
934
935 // The asio error code doesn't know about our custom errors, so we have to
936 // parse the error string. Some of these D-Bus -> Redfish translations are a
937 // stretch, but it's good to try to communicate something vaguely useful.
938 if (strcmp(dbusError->name,
939 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
940 {
941 // Service did not like the object_path we tried to set.
942 messages::propertyValueIncorrect(
943 resp->res, "AppliedOperatingConfig/@odata.id", setPropVal);
944 }
945 else if (strcmp(dbusError->name,
946 "xyz.openbmc_project.Common.Error.NotAllowed") == 0)
947 {
948 // Service indicates we can never change the config for this processor.
949 messages::propertyNotWritable(resp->res, "AppliedOperatingConfig");
950 }
951 else if (strcmp(dbusError->name,
952 "xyz.openbmc_project.Common.Error.Unavailable") == 0)
953 {
954 // Service indicates the config cannot be changed right now, but maybe
955 // in a different system state.
956 messages::resourceInStandby(resp->res);
957 }
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800958 else
959 {
960 messages::internalError(resp->res);
961 }
962}
963
964/**
965 * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic
966 * validation of the input data, and then set the D-Bus property.
967 *
968 * @param[in,out] resp Async HTTP response.
969 * @param[in] processorId Processor's Id.
970 * @param[in] appliedConfigUri New property value to apply.
971 * @param[in] cpuObjectPath Path of CPU object to modify.
972 * @param[in] serviceMap Service map for CPU object.
973 */
974inline void patchAppliedOperatingConfig(
975 const std::shared_ptr<bmcweb::AsyncResp>& resp,
976 const std::string& processorId, const std::string& appliedConfigUri,
Shantappa Teekappanavar5df6eda2022-01-18 12:29:28 -0600977 const std::string& cpuObjectPath,
978 const dbus::utility::MapperServiceMap& serviceMap)
Jonathan Doman3cde86f2020-12-02 14:50:45 -0800979{
980 // Check that the property even exists by checking for the interface
981 const std::string* controlService = nullptr;
982 for (const auto& [serviceName, interfaceList] : serviceMap)
983 {
984 if (std::find(interfaceList.begin(), interfaceList.end(),
985 "xyz.openbmc_project.Control.Processor."
986 "CurrentOperatingConfig") != interfaceList.end())
987 {
988 controlService = &serviceName;
989 break;
990 }
991 }
992
993 if (controlService == nullptr)
994 {
995 messages::internalError(resp->res);
996 return;
997 }
998
999 // Check that the config URI is a child of the cpu URI being patched.
1000 std::string expectedPrefix("/redfish/v1/Systems/system/Processors/");
1001 expectedPrefix += processorId;
1002 expectedPrefix += "/OperatingConfigs/";
Ed Tanous11ba3972022-07-11 09:50:41 -07001003 if (!appliedConfigUri.starts_with(expectedPrefix) ||
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001004 expectedPrefix.size() == appliedConfigUri.size())
1005 {
1006 messages::propertyValueIncorrect(
1007 resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri);
1008 return;
1009 }
1010
1011 // Generate the D-Bus path of the OperatingConfig object, by assuming it's a
1012 // direct child of the CPU object.
1013 // Strip the expectedPrefix from the config URI to get the "filename", and
1014 // append to the CPU's path.
1015 std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size());
1016 sdbusplus::message::object_path configPath(cpuObjectPath);
1017 configPath /= configBaseName;
1018
1019 BMCWEB_LOG_INFO << "Setting config to " << configPath.str;
1020
1021 // Set the property, with handler to check error responses
1022 crow::connections::systemBus->async_method_call(
Ed Tanous914e2d52022-01-07 11:38:34 -08001023 [resp, appliedConfigUri](const boost::system::error_code ec,
Patrick Williams59d494e2022-07-22 19:26:55 -05001024 const sdbusplus::message_t& msg) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001025 handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg);
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001026 },
1027 *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties",
1028 "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig",
Ed Tanous168e20c2021-12-13 14:39:53 -08001029 "AppliedConfig", dbus::utility::DbusVariantType(std::move(configPath)));
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001030}
1031
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001032inline void handleProcessorHead(crow::App& app, const crow::Request& req,
1033 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1034 const std::string& /* systemName */,
1035 const std::string& /* processorId */)
1036{
1037 if (!redfish::setUpRedfishRoute(app, req, aResp))
1038 {
1039 return;
1040 }
1041 aResp->res.addHeader(
1042 boost::beast::http::field::link,
1043 "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby");
1044}
1045
1046inline void handleProcessorCollectionHead(
1047 crow::App& app, const crow::Request& req,
1048 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1049 const std::string& /* systemName */)
1050{
1051 if (!redfish::setUpRedfishRoute(app, req, aResp))
1052 {
1053 return;
1054 }
1055 aResp->res.addHeader(
1056 boost::beast::http::field::link,
1057 "</redfish/v1/JsonSchemas/ProcessorCollection/ProcessorCollection.json>; rel=describedby");
1058}
1059
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001060inline void requestRoutesOperatingConfigCollection(App& app)
Jonathan Domandba0c292020-12-02 15:34:13 -08001061{
Jonathan Domandba0c292020-12-02 15:34:13 -08001062
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001063 BMCWEB_ROUTE(
1064 app, "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/")
Ed Tanoused398212021-06-09 17:05:54 -07001065 .privileges(redfish::privileges::getOperatingConfigCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001066 .methods(boost::beast::http::verb::get)(
1067 [&app](const crow::Request& req,
1068 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1069 const std::string& cpuName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001070 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001071 {
1072 return;
1073 }
1074 asyncResp->res.jsonValue["@odata.type"] =
1075 "#OperatingConfigCollection.OperatingConfigCollection";
1076 asyncResp->res.jsonValue["@odata.id"] = req.url;
1077 asyncResp->res.jsonValue["Name"] = "Operating Config Collection";
1078
1079 // First find the matching CPU object so we know how to
1080 // constrain our search for related Config objects.
George Liu7a1dbc42022-12-07 16:03:22 +08001081 const std::array<std::string_view, 1> interfaces = {
1082 "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig"};
1083 dbus::utility::getSubTreePaths(
1084 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -07001085 [asyncResp, cpuName](
George Liu7a1dbc42022-12-07 16:03:22 +08001086 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001087 const dbus::utility::MapperGetSubTreePathsResponse& objects) {
1088 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001089 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001090 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1091 << ec.message();
1092 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001093 return;
1094 }
Jonathan Domandba0c292020-12-02 15:34:13 -08001095
Ed Tanous002d39b2022-05-31 08:59:27 -07001096 for (const std::string& object : objects)
1097 {
Ed Tanous11ba3972022-07-11 09:50:41 -07001098 if (!object.ends_with(cpuName))
Ed Tanous002d39b2022-05-31 08:59:27 -07001099 {
1100 continue;
1101 }
George Liu0fda0f12021-11-16 10:06:17 +08001102
Ed Tanous002d39b2022-05-31 08:59:27 -07001103 // 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
Ed Tanous002d39b2022-05-31 08:59:27 -07001107 // Use the common search routine to construct the
1108 // Collection of all Config objects under this CPU.
George Liu7a1dbc42022-12-07 16:03:22 +08001109 constexpr std::array<std::string_view, 1> interface {
1110 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"
1111 };
Ed Tanous002d39b2022-05-31 08:59:27 -07001112 collection_util::getCollectionMembers(
1113 asyncResp,
Willy Tuae9031f2022-09-27 05:48:07 +00001114 crow::utility::urlFromPieces("redfish", "v1", "Systems",
1115 "system", "Processors",
1116 cpuName, "OperatingConfigs"),
George Liu7a1dbc42022-12-07 16:03:22 +08001117 interface, object.c_str());
Ed Tanous002d39b2022-05-31 08:59:27 -07001118 return;
1119 }
George Liu7a1dbc42022-12-07 16:03:22 +08001120 });
George Liu0fda0f12021-11-16 10:06:17 +08001121 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001122}
1123
1124inline void requestRoutesOperatingConfig(App& app)
1125{
1126 BMCWEB_ROUTE(
1127 app,
1128 "/redfish/v1/Systems/system/Processors/<str>/OperatingConfigs/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001129 .privileges(redfish::privileges::getOperatingConfig)
Ed Tanous002d39b2022-05-31 08:59:27 -07001130 .methods(boost::beast::http::verb::get)(
1131 [&app](const crow::Request& req,
1132 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1133 const std::string& cpuName, const std::string& configName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001134 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001135 {
1136 return;
1137 }
1138 // Ask for all objects implementing OperatingConfig so we can search
1139 // for one with a matching name
1140 crow::connections::systemBus->async_method_call(
1141 [asyncResp, cpuName, configName, reqUrl{req.url}](
1142 boost::system::error_code ec,
1143 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1144 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001145 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001146 BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "
1147 << ec.message();
1148 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001149 return;
1150 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001151 const std::string expectedEnding = cpuName + '/' + configName;
1152 for (const auto& [objectPath, serviceMap] : subtree)
1153 {
1154 // Ignore any configs without matching cpuX/configY
Ed Tanous11ba3972022-07-11 09:50:41 -07001155 if (!objectPath.ends_with(expectedEnding) || serviceMap.empty())
Ed Tanous002d39b2022-05-31 08:59:27 -07001156 {
1157 continue;
1158 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001159
Ed Tanous002d39b2022-05-31 08:59:27 -07001160 nlohmann::json& json = asyncResp->res.jsonValue;
1161 json["@odata.type"] = "#OperatingConfig.v1_0_0.OperatingConfig";
1162 json["@odata.id"] = reqUrl;
1163 json["Name"] = "Processor Profile";
1164 json["Id"] = configName;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001165
Ed Tanous002d39b2022-05-31 08:59:27 -07001166 // Just use the first implementation of the object - not
1167 // expected that there would be multiple matching
1168 // services
1169 getOperatingConfigData(asyncResp, serviceMap.begin()->first,
1170 objectPath);
1171 return;
1172 }
1173 messages::resourceNotFound(asyncResp->res, "OperatingConfig",
1174 configName);
1175 },
1176 "xyz.openbmc_project.ObjectMapper",
1177 "/xyz/openbmc_project/object_mapper",
1178 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1179 "/xyz/openbmc_project/inventory", 0,
1180 std::array<const char*, 1>{
1181 "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001182 });
1183}
Jonathan Domandba0c292020-12-02 15:34:13 -08001184
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001185inline void requestRoutesProcessorCollection(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001186{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001187 /**
1188 * Functions triggers appropriate requests on DBus
1189 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001190 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/")
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001191 .privileges(redfish::privileges::headProcessorCollection)
1192 .methods(boost::beast::http::verb::head)(
1193 std::bind_front(handleProcessorCollectionHead, std::ref(app)));
1194
1195 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/")
Ed Tanoused398212021-06-09 17:05:54 -07001196 .privileges(redfish::privileges::getProcessorCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001197 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001198 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001199 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1200 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001201 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001202 {
1203 return;
1204 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001205 if (systemName != "system")
1206 {
1207 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1208 systemName);
1209 return;
1210 }
1211
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001212 asyncResp->res.addHeader(
1213 boost::beast::http::field::link,
1214 "</redfish/v1/JsonSchemas/ProcessorCollection/ProcessorCollection.json>; rel=describedby");
1215
Ed Tanous002d39b2022-05-31 08:59:27 -07001216 asyncResp->res.jsonValue["@odata.type"] =
1217 "#ProcessorCollection.ProcessorCollection";
1218 asyncResp->res.jsonValue["Name"] = "Processor Collection";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001219
Ed Tanous002d39b2022-05-31 08:59:27 -07001220 asyncResp->res.jsonValue["@odata.id"] =
1221 "/redfish/v1/Systems/system/Processors";
Gunnar Millsac6a4442020-10-14 14:55:29 -05001222
Ed Tanous002d39b2022-05-31 08:59:27 -07001223 collection_util::getCollectionMembers(
Willy Tuae9031f2022-09-27 05:48:07 +00001224 asyncResp,
1225 boost::urls::url("/redfish/v1/Systems/system/Processors"),
George Liu7a1dbc42022-12-07 16:03:22 +08001226 processorInterfaces);
Ed Tanous002d39b2022-05-31 08:59:27 -07001227 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001228}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001229
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001230inline void requestRoutesProcessor(App& app)
Gunnar Millsac6a4442020-10-14 14:55:29 -05001231{
Gunnar Millsac6a4442020-10-14 14:55:29 -05001232 /**
1233 * Functions triggers appropriate requests on DBus
1234 */
Gunnar Millsac6a4442020-10-14 14:55:29 -05001235
Ed Tanous22d268c2022-05-19 09:39:07 -07001236 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001237 .privileges(redfish::privileges::headProcessor)
1238 .methods(boost::beast::http::verb::head)(
1239 std::bind_front(handleProcessorHead, std::ref(app)));
1240
1241 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001242 .privileges(redfish::privileges::getProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001243 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001244 [&app](const crow::Request& req,
1245 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001246 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07001247 const std::string& processorId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001248 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001249 {
1250 return;
1251 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001252 if (systemName != "system")
1253 {
1254 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1255 systemName);
1256 return;
1257 }
1258
Nikhil Namjoshi71a24ca2022-11-11 01:52:32 +00001259 asyncResp->res.addHeader(
1260 boost::beast::http::field::link,
1261 "</redfish/v1/JsonSchemas/Processor/Processor.json>; rel=describedby");
Ed Tanous002d39b2022-05-31 08:59:27 -07001262 asyncResp->res.jsonValue["@odata.type"] =
1263 "#Processor.v1_11_0.Processor";
1264 asyncResp->res.jsonValue["@odata.id"] =
1265 "/redfish/v1/Systems/system/Processors/" + processorId;
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001266
Ed Tanous8a592812022-06-04 09:06:59 -07001267 getProcessorObject(
1268 asyncResp, processorId,
1269 std::bind_front(getProcessorData, asyncResp, processorId));
Ed Tanous002d39b2022-05-31 08:59:27 -07001270 });
Jonathan Doman3cde86f2020-12-02 14:50:45 -08001271
Ed Tanous22d268c2022-05-19 09:39:07 -07001272 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Processors/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001273 .privileges(redfish::privileges::patchProcessor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001274 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001275 [&app](const crow::Request& req,
1276 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001277 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07001278 const std::string& processorId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001279 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001280 {
1281 return;
1282 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001283 if (systemName != "system")
1284 {
1285 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1286 systemName);
1287 return;
1288 }
1289
Ed Tanous002d39b2022-05-31 08:59:27 -07001290 std::optional<nlohmann::json> appliedConfigJson;
1291 if (!json_util::readJsonPatch(req, asyncResp->res,
1292 "AppliedOperatingConfig",
1293 appliedConfigJson))
1294 {
1295 return;
1296 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001297
Ed Tanous002d39b2022-05-31 08:59:27 -07001298 if (appliedConfigJson)
1299 {
Ed Tanousf8fe53e2022-06-30 15:55:45 -07001300 std::string appliedConfigUri;
Ed Tanous002d39b2022-05-31 08:59:27 -07001301 if (!json_util::readJson(*appliedConfigJson, asyncResp->res,
1302 "@odata.id", appliedConfigUri))
1303 {
1304 return;
1305 }
1306 // Check for 404 and find matching D-Bus object, then run
1307 // property patch handlers if that all succeeds.
Ed Tanous8a592812022-06-04 09:06:59 -07001308 getProcessorObject(asyncResp, processorId,
1309 std::bind_front(patchAppliedOperatingConfig,
1310 asyncResp, processorId,
1311 appliedConfigUri));
Ed Tanous002d39b2022-05-31 08:59:27 -07001312 }
1313 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001314}
Gunnar Millsac6a4442020-10-14 14:55:29 -05001315
1316} // namespace redfish