blob: 6ce95bddbdf7ecf8ae515c1894596fc88ee187ca [file] [log] [blame]
Ed Tanous2474adf2018-09-05 16:31:16 -07001/*
Ed Tanous6be832e2024-09-10 11:44:48 -07002Copyright (c) 2018 Intel Corporation
3Copyright (c) 2018 Ampere Computing LLC
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
Ed Tanous2474adf2018-09-05 16:31:16 -070016*/
17#pragma once
18
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080019#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Ed Tanous539d8c62024-06-19 14:38:27 -070021#include "generated/enums/power.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080022#include "query.hpp"
23#include "registries/privilege_registry.hpp"
Ed Tanous2474adf2018-09-05 16:31:16 -070024#include "sensors.hpp"
Zhenwei Chen0d7702c2022-07-12 16:42:08 +000025#include "utils/chassis_utils.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070026#include "utils/json_utils.hpp"
Janet Adkinsc9563602024-08-28 11:37:46 -050027#include "utils/sensor_utils.hpp"
Ed Tanous2474adf2018-09-05 16:31:16 -070028
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020029#include <sdbusplus/asio/property.hpp>
John Edward Broadbent7e860f12021-04-08 15:57:16 -070030
George Liu7a1dbc42022-12-07 16:03:22 +080031#include <array>
Ed Tanous08850572024-03-06 15:09:17 -080032#include <string>
George Liu7a1dbc42022-12-07 16:03:22 +080033#include <string_view>
Ed Tanous08850572024-03-06 15:09:17 -080034#include <vector>
George Liu7a1dbc42022-12-07 16:03:22 +080035
Ed Tanous2474adf2018-09-05 16:31:16 -070036namespace redfish
37{
Ed Tanous53b00f52024-03-08 09:05:10 -080038
39inline void afterGetPowerCapEnable(
John Edward Broadbent7e860f12021-04-08 15:57:16 -070040 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanous53b00f52024-03-08 09:05:10 -080041 uint32_t valueToSet, const boost::system::error_code& ec,
42 bool powerCapEnable)
Ed Tanous2474adf2018-09-05 16:31:16 -070043{
Ed Tanous53b00f52024-03-08 09:05:10 -080044 if (ec)
45 {
46 messages::internalError(sensorsAsyncResp->asyncResp->res);
47 BMCWEB_LOG_ERROR("powerCapEnable Get handler: Dbus error {}", ec);
48 return;
49 }
50 if (!powerCapEnable)
51 {
52 messages::actionNotSupported(
53 sensorsAsyncResp->asyncResp->res,
54 "Setting LimitInWatts when PowerLimit feature is disabled");
55 BMCWEB_LOG_ERROR("PowerLimit feature is disabled ");
56 return;
57 }
George Liu0fda0f12021-11-16 10:06:17 +080058
Ginu Georgee93abac2024-06-14 17:35:27 +053059 setDbusProperty(sensorsAsyncResp->asyncResp, "PowerControl",
60 "xyz.openbmc_project.Settings",
Asmitha Karunanithi87c44962024-04-04 18:28:33 +000061 sdbusplus::message::object_path(
62 "/xyz/openbmc_project/control/host0/power_cap"),
63 "xyz.openbmc_project.Control.Power.Cap", "PowerCap",
Ginu Georgee93abac2024-06-14 17:35:27 +053064 valueToSet);
John Edward Broadbent7e860f12021-04-08 15:57:16 -070065}
Ed Tanous53b00f52024-03-08 09:05:10 -080066
67inline void afterGetChassisPath(
68 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
Ed Tanous08850572024-03-06 15:09:17 -080069 std::vector<nlohmann::json::object_t>& powerControlCollections,
Ed Tanous53b00f52024-03-08 09:05:10 -080070 const std::optional<std::string>& chassisPath)
71{
72 if (!chassisPath)
73 {
74 BMCWEB_LOG_WARNING("Don't find valid chassis path ");
75 messages::resourceNotFound(sensorsAsyncResp->asyncResp->res, "Chassis",
76 sensorsAsyncResp->chassisId);
77 return;
78 }
79
80 if (powerControlCollections.size() != 1)
81 {
82 BMCWEB_LOG_WARNING("Don't support multiple hosts at present ");
83 messages::resourceNotFound(sensorsAsyncResp->asyncResp->res, "Power",
84 "PowerControl");
85 return;
86 }
87
88 auto& item = powerControlCollections[0];
89
Ed Tanous53b00f52024-03-08 09:05:10 -080090 std::optional<uint32_t> value;
Myung Baeafc474a2024-10-09 00:53:29 -070091 if (!json_util::readJsonObject( //
92 item, sensorsAsyncResp->asyncResp->res, //
93 "PowerLimit/LimitInWatts", value //
94 ))
Ed Tanous53b00f52024-03-08 09:05:10 -080095 {
96 return;
97 }
98 if (!value)
99 {
100 return;
101 }
Ed Tanousdeae6a72024-11-11 21:58:57 -0800102 dbus::utility::getProperty<bool>(
103 "xyz.openbmc_project.Settings",
Ed Tanous53b00f52024-03-08 09:05:10 -0800104 "/xyz/openbmc_project/control/host0/power_cap",
105 "xyz.openbmc_project.Control.Power.Cap", "PowerCapEnable",
106 std::bind_front(afterGetPowerCapEnable, sensorsAsyncResp, *value));
107}
108
109inline void afterPowerCapSettingGet(
110 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
111 const boost::system::error_code& ec,
112 const dbus::utility::DBusPropertiesMap& properties)
113{
114 if (ec)
115 {
116 messages::internalError(sensorAsyncResp->asyncResp->res);
117 BMCWEB_LOG_ERROR("Power Limit GetAll handler: Dbus error {}", ec);
118 return;
119 }
120
121 nlohmann::json& tempArray =
122 sensorAsyncResp->asyncResp->res.jsonValue["PowerControl"];
123
124 // Put multiple "sensors" into a single PowerControl, 0,
125 // so only create the first one
126 if (tempArray.empty())
127 {
128 // Mandatory properties odata.id and MemberId
129 // A warning without a odata.type
130 nlohmann::json::object_t powerControl;
131 powerControl["@odata.type"] = "#Power.v1_0_0.PowerControl";
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400132 powerControl["@odata.id"] =
133 "/redfish/v1/Chassis/" + sensorAsyncResp->chassisId +
134 "/Power#/PowerControl/0";
Ed Tanous53b00f52024-03-08 09:05:10 -0800135 powerControl["Name"] = "Chassis Power Control";
136 powerControl["MemberId"] = "0";
137 tempArray.emplace_back(std::move(powerControl));
138 }
139
140 nlohmann::json& sensorJson = tempArray.back();
141 bool enabled = false;
142 double powerCap = 0.0;
143 int64_t scale = 0;
144
145 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
146 property : properties)
147 {
148 if (property.first == "Scale")
149 {
150 const int64_t* i = std::get_if<int64_t>(&property.second);
151
152 if (i != nullptr)
153 {
154 scale = *i;
155 }
156 }
157 else if (property.first == "PowerCap")
158 {
159 const double* d = std::get_if<double>(&property.second);
160 const int64_t* i = std::get_if<int64_t>(&property.second);
161 const uint32_t* u = std::get_if<uint32_t>(&property.second);
162
163 if (d != nullptr)
164 {
165 powerCap = *d;
166 }
167 else if (i != nullptr)
168 {
169 powerCap = static_cast<double>(*i);
170 }
171 else if (u != nullptr)
172 {
173 powerCap = *u;
174 }
175 }
176 else if (property.first == "PowerCapEnable")
177 {
178 const bool* b = std::get_if<bool>(&property.second);
179
180 if (b != nullptr)
181 {
182 enabled = *b;
183 }
184 }
185 }
186
187 // LimitException is Mandatory attribute as per OCP
Janet Adkinsc9563602024-08-28 11:37:46 -0500188 // Baseline Profile - v1.0.0, so currently making it
Ed Tanous53b00f52024-03-08 09:05:10 -0800189 // "NoAction" as default value to make it OCP Compliant.
Ed Tanous539d8c62024-06-19 14:38:27 -0700190 sensorJson["PowerLimit"]["LimitException"] =
191 power::PowerLimitException::NoAction;
Ed Tanous53b00f52024-03-08 09:05:10 -0800192
193 if (enabled)
194 {
195 // Redfish specification indicates PowerLimit should
196 // be null if the limit is not enabled.
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400197 sensorJson["PowerLimit"]["LimitInWatts"] =
198 powerCap * std::pow(10, scale);
Ed Tanous53b00f52024-03-08 09:05:10 -0800199 }
200}
201
202using Mapper = dbus::utility::MapperGetSubTreePathsResponse;
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400203inline void afterGetChassis(
204 const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
205 const boost::system::error_code& ec2, const Mapper& chassisPaths)
Ed Tanous53b00f52024-03-08 09:05:10 -0800206{
207 if (ec2)
208 {
209 BMCWEB_LOG_ERROR("Power Limit GetSubTreePaths handler Dbus error {}",
210 ec2);
211 return;
212 }
213
214 bool found = false;
215 for (const std::string& chassis : chassisPaths)
216 {
217 size_t len = std::string::npos;
218 size_t lastPos = chassis.rfind('/');
219 if (lastPos == std::string::npos)
220 {
221 continue;
222 }
223
224 if (lastPos == chassis.size() - 1)
225 {
226 size_t end = lastPos;
227 lastPos = chassis.rfind('/', lastPos - 1);
228 if (lastPos == std::string::npos)
229 {
230 continue;
231 }
232
233 len = end - (lastPos + 1);
234 }
235
236 std::string interfaceChassisName = chassis.substr(lastPos + 1, len);
237 if (interfaceChassisName == sensorAsyncResp->chassisId)
238 {
239 found = true;
240 break;
241 }
242 }
243
244 if (!found)
245 {
246 BMCWEB_LOG_DEBUG("Power Limit not present for {}",
247 sensorAsyncResp->chassisId);
248 return;
249 }
250
Ed Tanousdeae6a72024-11-11 21:58:57 -0800251 dbus::utility::getAllProperties(
252 "xyz.openbmc_project.Settings",
Ed Tanous53b00f52024-03-08 09:05:10 -0800253 "/xyz/openbmc_project/control/host0/power_cap",
254 "xyz.openbmc_project.Control.Power.Cap",
255 [sensorAsyncResp](const boost::system::error_code& ec,
256 const dbus::utility::DBusPropertiesMap& properties
257
258 ) { afterPowerCapSettingGet(sensorAsyncResp, ec, properties); });
259}
260
261inline void
262 handleChassisPowerGet(App& app, const crow::Request& req,
263 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
264 const std::string& chassisName)
265{
266 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
267 {
268 return;
269 }
270 asyncResp->res.jsonValue["PowerControl"] = nlohmann::json::array();
271
272 auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
273 asyncResp, chassisName, sensors::dbus::powerPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -0500274 sensor_utils::chassisSubNodeToString(
275 sensor_utils::ChassisSubNode::powerNode));
Ed Tanous53b00f52024-03-08 09:05:10 -0800276
277 getChassisData(sensorAsyncResp);
278
279 // This callback verifies that the power limit is only provided
280 // for the chassis that implements the Chassis inventory item.
281 // This prevents things like power supplies providing the
282 // chassis power limit
283
284 constexpr std::array<std::string_view, 2> interfaces = {
285 "xyz.openbmc_project.Inventory.Item.Board",
286 "xyz.openbmc_project.Inventory.Item.Chassis"};
287
288 dbus::utility::getSubTreePaths(
289 "/xyz/openbmc_project/inventory", 0, interfaces,
290 std::bind_front(afterGetChassis, sensorAsyncResp));
291}
292
293inline void
294 handleChassisPowerPatch(App& app, const crow::Request& req,
295 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
296 const std::string& chassisName)
297{
298 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
299 {
300 return;
301 }
302 auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
303 asyncResp, chassisName, sensors::dbus::powerPaths,
Janet Adkins0c728b42024-08-29 11:09:10 -0500304 sensor_utils::chassisSubNodeToString(
305 sensor_utils::ChassisSubNode::powerNode));
Ed Tanous53b00f52024-03-08 09:05:10 -0800306
Ed Tanous08850572024-03-06 15:09:17 -0800307 std::optional<std::vector<nlohmann::json::object_t>> voltageCollections;
308 std::optional<std::vector<nlohmann::json::object_t>> powerCtlCollections;
Ed Tanous53b00f52024-03-08 09:05:10 -0800309
Myung Baeafc474a2024-10-09 00:53:29 -0700310 if (!json_util::readJsonPatch( //
311 req, sensorAsyncResp->asyncResp->res, //
312 "PowerControl", powerCtlCollections, //
313 "Voltages", voltageCollections //
314 ))
Ed Tanous53b00f52024-03-08 09:05:10 -0800315 {
316 return;
317 }
318
319 if (powerCtlCollections)
320 {
321 redfish::chassis_utils::getValidChassisPath(
322 sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
323 std::bind_front(afterGetChassisPath, sensorAsyncResp,
324 *powerCtlCollections));
325 }
326 if (voltageCollections)
327 {
Ed Tanous08850572024-03-06 15:09:17 -0800328 std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>
Ed Tanous53b00f52024-03-08 09:05:10 -0800329 allCollections;
Ed Tanous08850572024-03-06 15:09:17 -0800330 allCollections.emplace("Voltages", std::move(*voltageCollections));
Ed Tanous53b00f52024-03-08 09:05:10 -0800331 setSensorsOverride(sensorAsyncResp, allCollections);
332 }
333}
334
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700335inline void requestRoutesPower(App& app)
336{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700337 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Power/")
Ed Tanoused398212021-06-09 17:05:54 -0700338 .privileges(redfish::privileges::getPower)
Ed Tanous002d39b2022-05-31 08:59:27 -0700339 .methods(boost::beast::http::verb::get)(
Ed Tanous53b00f52024-03-08 09:05:10 -0800340 std::bind_front(handleChassisPowerGet, std::ref(app)));
Eddie James028f7eb2019-05-17 21:24:36 +0000341
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700342 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Power/")
Ed Tanoused398212021-06-09 17:05:54 -0700343 .privileges(redfish::privileges::patchPower)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700344 .methods(boost::beast::http::verb::patch)(
Ed Tanous53b00f52024-03-08 09:05:10 -0800345 std::bind_front(handleChassisPowerPatch, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700346}
Ed Tanous2474adf2018-09-05 16:31:16 -0700347
348} // namespace redfish