140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
440e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Ampere Computing LLC
56be832e2SEd Tanous
62474adfaSEd Tanous #pragma once
72474adfaSEd Tanous
83ccb3adbSEd Tanous #include "app.hpp"
9d7857201SEd Tanous #include "async_resp.hpp"
107a1dbc48SGeorge Liu #include "dbus_utility.hpp"
11d7857201SEd Tanous #include "error_messages.hpp"
12539d8c6bSEd Tanous #include "generated/enums/power.hpp"
13d7857201SEd Tanous #include "http_request.hpp"
14d7857201SEd Tanous #include "logging.hpp"
153ccb3adbSEd Tanous #include "query.hpp"
163ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
172474adfaSEd Tanous #include "sensors.hpp"
180d7702c0SZhenwei Chen #include "utils/chassis_utils.hpp"
19d7857201SEd Tanous #include "utils/dbus_utils.hpp"
205b90429aSEd Tanous #include "utils/json_utils.hpp"
21c9563608SJanet Adkins #include "utils/sensor_utils.hpp"
222474adfaSEd Tanous
23d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
24d7857201SEd Tanous #include <nlohmann/json.hpp>
25d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
267e860f15SJohn Edward Broadbent
277a1dbc48SGeorge Liu #include <array>
28d7857201SEd Tanous #include <cmath>
29d7857201SEd Tanous #include <cstddef>
30d7857201SEd Tanous #include <cstdint>
31d7857201SEd Tanous #include <functional>
32d7857201SEd Tanous #include <memory>
33d7857201SEd Tanous #include <optional>
340885057cSEd Tanous #include <string>
357a1dbc48SGeorge Liu #include <string_view>
36d7857201SEd Tanous #include <unordered_map>
37d7857201SEd Tanous #include <utility>
38d7857201SEd Tanous #include <variant>
390885057cSEd Tanous #include <vector>
407a1dbc48SGeorge Liu
412474adfaSEd Tanous namespace redfish
422474adfaSEd Tanous {
4353b00f5dSEd Tanous
afterGetPowerCapEnable(const std::shared_ptr<SensorsAsyncResp> & sensorsAsyncResp,uint32_t valueToSet,const boost::system::error_code & ec,bool powerCapEnable)4453b00f5dSEd Tanous inline void afterGetPowerCapEnable(
458d1b46d7Szhanghch05 const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
4653b00f5dSEd Tanous uint32_t valueToSet, const boost::system::error_code& ec,
4753b00f5dSEd Tanous bool powerCapEnable)
484bb3dc34SCarol Wang {
4953b00f5dSEd Tanous if (ec)
5053b00f5dSEd Tanous {
5153b00f5dSEd Tanous messages::internalError(sensorsAsyncResp->asyncResp->res);
5253b00f5dSEd Tanous BMCWEB_LOG_ERROR("powerCapEnable Get handler: Dbus error {}", ec);
5353b00f5dSEd Tanous return;
5453b00f5dSEd Tanous }
5553b00f5dSEd Tanous if (!powerCapEnable)
5653b00f5dSEd Tanous {
5753b00f5dSEd Tanous messages::actionNotSupported(
5853b00f5dSEd Tanous sensorsAsyncResp->asyncResp->res,
5953b00f5dSEd Tanous "Setting LimitInWatts when PowerLimit feature is disabled");
6053b00f5dSEd Tanous BMCWEB_LOG_ERROR("PowerLimit feature is disabled ");
6153b00f5dSEd Tanous return;
6253b00f5dSEd Tanous }
6353b00f5dSEd Tanous
64e93abac6SGinu George setDbusProperty(sensorsAsyncResp->asyncResp, "PowerControl",
65e93abac6SGinu George "xyz.openbmc_project.Settings",
6687c44966SAsmitha Karunanithi sdbusplus::message::object_path(
6787c44966SAsmitha Karunanithi "/xyz/openbmc_project/control/host0/power_cap"),
6887c44966SAsmitha Karunanithi "xyz.openbmc_project.Control.Power.Cap", "PowerCap",
69e93abac6SGinu George valueToSet);
7053b00f5dSEd Tanous }
7153b00f5dSEd Tanous
afterGetChassisPath(const std::shared_ptr<SensorsAsyncResp> & sensorsAsyncResp,std::vector<nlohmann::json::object_t> & powerControlCollections,const std::optional<std::string> & chassisPath)7253b00f5dSEd Tanous inline void afterGetChassisPath(
7353b00f5dSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp,
740885057cSEd Tanous std::vector<nlohmann::json::object_t>& powerControlCollections,
7553b00f5dSEd Tanous const std::optional<std::string>& chassisPath)
7653b00f5dSEd Tanous {
774bb3dc34SCarol Wang if (!chassisPath)
784bb3dc34SCarol Wang {
7962598e31SEd Tanous BMCWEB_LOG_WARNING("Don't find valid chassis path ");
8053b00f5dSEd Tanous messages::resourceNotFound(sensorsAsyncResp->asyncResp->res, "Chassis",
8153b00f5dSEd Tanous sensorsAsyncResp->chassisId);
824bb3dc34SCarol Wang return;
834bb3dc34SCarol Wang }
844bb3dc34SCarol Wang
854bb3dc34SCarol Wang if (powerControlCollections.size() != 1)
864bb3dc34SCarol Wang {
8762598e31SEd Tanous BMCWEB_LOG_WARNING("Don't support multiple hosts at present ");
8853b00f5dSEd Tanous messages::resourceNotFound(sensorsAsyncResp->asyncResp->res, "Power",
8953b00f5dSEd Tanous "PowerControl");
904bb3dc34SCarol Wang return;
914bb3dc34SCarol Wang }
924bb3dc34SCarol Wang
934bb3dc34SCarol Wang auto& item = powerControlCollections[0];
944bb3dc34SCarol Wang
954bb3dc34SCarol Wang std::optional<uint32_t> value;
96afc474aeSMyung Bae if (!json_util::readJsonObject( //
97afc474aeSMyung Bae item, sensorsAsyncResp->asyncResp->res, //
98afc474aeSMyung Bae "PowerLimit/LimitInWatts", value //
99afc474aeSMyung Bae ))
1004bb3dc34SCarol Wang {
1014bb3dc34SCarol Wang return;
1024bb3dc34SCarol Wang }
1034bb3dc34SCarol Wang if (!value)
1044bb3dc34SCarol Wang {
1054bb3dc34SCarol Wang return;
1064bb3dc34SCarol Wang }
107deae6a78SEd Tanous dbus::utility::getProperty<bool>(
108deae6a78SEd Tanous "xyz.openbmc_project.Settings",
1091e1e598dSJonathan Doman "/xyz/openbmc_project/control/host0/power_cap",
1101e1e598dSJonathan Doman "xyz.openbmc_project.Control.Power.Cap", "PowerCapEnable",
11153b00f5dSEd Tanous std::bind_front(afterGetPowerCapEnable, sensorsAsyncResp, *value));
1124bb3dc34SCarol Wang }
1134bb3dc34SCarol Wang
afterPowerCapSettingGet(const std::shared_ptr<SensorsAsyncResp> & sensorAsyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & properties)11453b00f5dSEd Tanous inline void afterPowerCapSettingGet(
11553b00f5dSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
1165e7e2dc5SEd Tanous const boost::system::error_code& ec,
11753b00f5dSEd Tanous const dbus::utility::DBusPropertiesMap& properties)
11853b00f5dSEd Tanous {
119028f7ebcSEddie James if (ec)
120028f7ebcSEddie James {
121002d39b4SEd Tanous messages::internalError(sensorAsyncResp->asyncResp->res);
12253b00f5dSEd Tanous BMCWEB_LOG_ERROR("Power Limit GetAll handler: Dbus error {}", ec);
123028f7ebcSEddie James return;
124028f7ebcSEddie James }
125028f7ebcSEddie James
1267e860f15SJohn Edward Broadbent nlohmann::json& tempArray =
127002d39b4SEd Tanous sensorAsyncResp->asyncResp->res.jsonValue["PowerControl"];
128028f7ebcSEddie James
1297e860f15SJohn Edward Broadbent // Put multiple "sensors" into a single PowerControl, 0,
1307e860f15SJohn Edward Broadbent // so only create the first one
131028f7ebcSEddie James if (tempArray.empty())
132028f7ebcSEddie James {
1337ab06f49SGunnar Mills // Mandatory properties odata.id and MemberId
1347ab06f49SGunnar Mills // A warning without a odata.type
1351476687dSEd Tanous nlohmann::json::object_t powerControl;
136002d39b4SEd Tanous powerControl["@odata.type"] = "#Power.v1_0_0.PowerControl";
137bd79bce8SPatrick Williams powerControl["@odata.id"] =
138bd79bce8SPatrick Williams "/redfish/v1/Chassis/" + sensorAsyncResp->chassisId +
1391476687dSEd Tanous "/Power#/PowerControl/0";
1401476687dSEd Tanous powerControl["Name"] = "Chassis Power Control";
1411476687dSEd Tanous powerControl["MemberId"] = "0";
142b2ba3072SPatrick Williams tempArray.emplace_back(std::move(powerControl));
143028f7ebcSEddie James }
144028f7ebcSEddie James
145028f7ebcSEddie James nlohmann::json& sensorJson = tempArray.back();
146028f7ebcSEddie James bool enabled = false;
147028f7ebcSEddie James double powerCap = 0.0;
148028f7ebcSEddie James int64_t scale = 0;
149028f7ebcSEddie James
15053b00f5dSEd Tanous for (const std::pair<std::string, dbus::utility::DbusVariantType>&
15153b00f5dSEd Tanous property : properties)
152028f7ebcSEddie James {
15355f79e6fSEd Tanous if (property.first == "Scale")
154028f7ebcSEddie James {
15553b00f5dSEd Tanous const int64_t* i = std::get_if<int64_t>(&property.second);
156028f7ebcSEddie James
157e662eae8SEd Tanous if (i != nullptr)
158028f7ebcSEddie James {
159028f7ebcSEddie James scale = *i;
160028f7ebcSEddie James }
161028f7ebcSEddie James }
16255f79e6fSEd Tanous else if (property.first == "PowerCap")
163028f7ebcSEddie James {
164002d39b4SEd Tanous const double* d = std::get_if<double>(&property.second);
16553b00f5dSEd Tanous const int64_t* i = std::get_if<int64_t>(&property.second);
16653b00f5dSEd Tanous const uint32_t* u = std::get_if<uint32_t>(&property.second);
167028f7ebcSEddie James
168e662eae8SEd Tanous if (d != nullptr)
169028f7ebcSEddie James {
170028f7ebcSEddie James powerCap = *d;
171028f7ebcSEddie James }
172e662eae8SEd Tanous else if (i != nullptr)
173028f7ebcSEddie James {
174271584abSEd Tanous powerCap = static_cast<double>(*i);
175028f7ebcSEddie James }
176e662eae8SEd Tanous else if (u != nullptr)
177028f7ebcSEddie James {
178028f7ebcSEddie James powerCap = *u;
179028f7ebcSEddie James }
180028f7ebcSEddie James }
18155f79e6fSEd Tanous else if (property.first == "PowerCapEnable")
182028f7ebcSEddie James {
183002d39b4SEd Tanous const bool* b = std::get_if<bool>(&property.second);
184028f7ebcSEddie James
185e662eae8SEd Tanous if (b != nullptr)
186028f7ebcSEddie James {
187028f7ebcSEddie James enabled = *b;
188028f7ebcSEddie James }
189028f7ebcSEddie James }
190028f7ebcSEddie James }
191028f7ebcSEddie James
1927e860f15SJohn Edward Broadbent // LimitException is Mandatory attribute as per OCP
193c9563608SJanet Adkins // Baseline Profile - v1.0.0, so currently making it
1947e860f15SJohn Edward Broadbent // "NoAction" as default value to make it OCP Compliant.
195539d8c6bSEd Tanous sensorJson["PowerLimit"]["LimitException"] =
196539d8c6bSEd Tanous power::PowerLimitException::NoAction;
1975a64a6f3SJoshi-Mansi
198028f7ebcSEddie James if (enabled)
199028f7ebcSEddie James {
2007e860f15SJohn Edward Broadbent // Redfish specification indicates PowerLimit should
2017e860f15SJohn Edward Broadbent // be null if the limit is not enabled.
202bd79bce8SPatrick Williams sensorJson["PowerLimit"]["LimitInWatts"] =
203bd79bce8SPatrick Williams powerCap * std::pow(10, scale);
204028f7ebcSEddie James }
20553b00f5dSEd Tanous }
20653b00f5dSEd Tanous
20753b00f5dSEd Tanous using Mapper = dbus::utility::MapperGetSubTreePathsResponse;
afterGetChassis(const std::shared_ptr<SensorsAsyncResp> & sensorAsyncResp,const boost::system::error_code & ec2,const Mapper & chassisPaths)208bd79bce8SPatrick Williams inline void afterGetChassis(
209bd79bce8SPatrick Williams const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp,
210bd79bce8SPatrick Williams const boost::system::error_code& ec2, const Mapper& chassisPaths)
21153b00f5dSEd Tanous {
21253b00f5dSEd Tanous if (ec2)
21353b00f5dSEd Tanous {
21453b00f5dSEd Tanous BMCWEB_LOG_ERROR("Power Limit GetSubTreePaths handler Dbus error {}",
21553b00f5dSEd Tanous ec2);
21653b00f5dSEd Tanous return;
21753b00f5dSEd Tanous }
21853b00f5dSEd Tanous
21953b00f5dSEd Tanous bool found = false;
22053b00f5dSEd Tanous for (const std::string& chassis : chassisPaths)
22153b00f5dSEd Tanous {
22253b00f5dSEd Tanous size_t len = std::string::npos;
22353b00f5dSEd Tanous size_t lastPos = chassis.rfind('/');
22453b00f5dSEd Tanous if (lastPos == std::string::npos)
22553b00f5dSEd Tanous {
22653b00f5dSEd Tanous continue;
22753b00f5dSEd Tanous }
22853b00f5dSEd Tanous
22953b00f5dSEd Tanous if (lastPos == chassis.size() - 1)
23053b00f5dSEd Tanous {
23153b00f5dSEd Tanous size_t end = lastPos;
23253b00f5dSEd Tanous lastPos = chassis.rfind('/', lastPos - 1);
23353b00f5dSEd Tanous if (lastPos == std::string::npos)
23453b00f5dSEd Tanous {
23553b00f5dSEd Tanous continue;
23653b00f5dSEd Tanous }
23753b00f5dSEd Tanous
23853b00f5dSEd Tanous len = end - (lastPos + 1);
23953b00f5dSEd Tanous }
24053b00f5dSEd Tanous
24153b00f5dSEd Tanous std::string interfaceChassisName = chassis.substr(lastPos + 1, len);
24253b00f5dSEd Tanous if (interfaceChassisName == sensorAsyncResp->chassisId)
24353b00f5dSEd Tanous {
24453b00f5dSEd Tanous found = true;
24553b00f5dSEd Tanous break;
24653b00f5dSEd Tanous }
24753b00f5dSEd Tanous }
24853b00f5dSEd Tanous
24953b00f5dSEd Tanous if (!found)
25053b00f5dSEd Tanous {
25153b00f5dSEd Tanous BMCWEB_LOG_DEBUG("Power Limit not present for {}",
25253b00f5dSEd Tanous sensorAsyncResp->chassisId);
25353b00f5dSEd Tanous return;
25453b00f5dSEd Tanous }
255028f7ebcSEddie James
256deae6a78SEd Tanous dbus::utility::getAllProperties(
257deae6a78SEd Tanous "xyz.openbmc_project.Settings",
258028f7ebcSEddie James "/xyz/openbmc_project/control/host0/power_cap",
259d1bde9e5SKrzysztof Grobelny "xyz.openbmc_project.Control.Power.Cap",
26053b00f5dSEd Tanous [sensorAsyncResp](const boost::system::error_code& ec,
26153b00f5dSEd Tanous const dbus::utility::DBusPropertiesMap& properties
26253b00f5dSEd Tanous
26353b00f5dSEd Tanous ) { afterPowerCapSettingGet(sensorAsyncResp, ec, properties); });
26453b00f5dSEd Tanous }
26553b00f5dSEd Tanous
handleChassisPowerGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisName)266*504af5a0SPatrick Williams inline void handleChassisPowerGet(
267*504af5a0SPatrick Williams App& app, const crow::Request& req,
26853b00f5dSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26953b00f5dSEd Tanous const std::string& chassisName)
27053b00f5dSEd Tanous {
27153b00f5dSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp))
27253b00f5dSEd Tanous {
27353b00f5dSEd Tanous return;
27453b00f5dSEd Tanous }
27553b00f5dSEd Tanous asyncResp->res.jsonValue["PowerControl"] = nlohmann::json::array();
27653b00f5dSEd Tanous
27753b00f5dSEd Tanous auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
27853b00f5dSEd Tanous asyncResp, chassisName, sensors::dbus::powerPaths,
2790c728b42SJanet Adkins sensor_utils::chassisSubNodeToString(
2800c728b42SJanet Adkins sensor_utils::ChassisSubNode::powerNode));
28153b00f5dSEd Tanous
28253b00f5dSEd Tanous getChassisData(sensorAsyncResp);
28353b00f5dSEd Tanous
28453b00f5dSEd Tanous // This callback verifies that the power limit is only provided
28553b00f5dSEd Tanous // for the chassis that implements the Chassis inventory item.
28653b00f5dSEd Tanous // This prevents things like power supplies providing the
28753b00f5dSEd Tanous // chassis power limit
288028f7ebcSEddie James
2897a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = {
290f857e9aeSAppaRao Puli "xyz.openbmc_project.Inventory.Item.Board",
2917a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"};
2927a1dbc48SGeorge Liu
29353b00f5dSEd Tanous dbus::utility::getSubTreePaths(
29453b00f5dSEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces,
29553b00f5dSEd Tanous std::bind_front(afterGetChassis, sensorAsyncResp));
29653b00f5dSEd Tanous }
2974bb3dc34SCarol Wang
handleChassisPowerPatch(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & chassisName)298*504af5a0SPatrick Williams inline void handleChassisPowerPatch(
299*504af5a0SPatrick Williams App& app, const crow::Request& req,
3007e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
30153b00f5dSEd Tanous const std::string& chassisName)
30253b00f5dSEd Tanous {
3033ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp))
30445ca1b86SEd Tanous {
30545ca1b86SEd Tanous return;
30645ca1b86SEd Tanous }
3078d1b46d7Szhanghch05 auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
30802da7c5aSEd Tanous asyncResp, chassisName, sensors::dbus::powerPaths,
3090c728b42SJanet Adkins sensor_utils::chassisSubNodeToString(
3100c728b42SJanet Adkins sensor_utils::ChassisSubNode::powerNode));
3114bb3dc34SCarol Wang
3120885057cSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> voltageCollections;
3130885057cSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> powerCtlCollections;
3144bb3dc34SCarol Wang
315afc474aeSMyung Bae if (!json_util::readJsonPatch( //
316afc474aeSMyung Bae req, sensorAsyncResp->asyncResp->res, //
317afc474aeSMyung Bae "PowerControl", powerCtlCollections, //
318afc474aeSMyung Bae "Voltages", voltageCollections //
319afc474aeSMyung Bae ))
3204bb3dc34SCarol Wang {
3214bb3dc34SCarol Wang return;
3224bb3dc34SCarol Wang }
3234bb3dc34SCarol Wang
3244bb3dc34SCarol Wang if (powerCtlCollections)
3254bb3dc34SCarol Wang {
32653b00f5dSEd Tanous redfish::chassis_utils::getValidChassisPath(
32753b00f5dSEd Tanous sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId,
32853b00f5dSEd Tanous std::bind_front(afterGetChassisPath, sensorAsyncResp,
32953b00f5dSEd Tanous *powerCtlCollections));
3304bb3dc34SCarol Wang }
3314bb3dc34SCarol Wang if (voltageCollections)
3324bb3dc34SCarol Wang {
3330885057cSEd Tanous std::unordered_map<std::string, std::vector<nlohmann::json::object_t>>
3344bb3dc34SCarol Wang allCollections;
3350885057cSEd Tanous allCollections.emplace("Voltages", std::move(*voltageCollections));
33680ac4024SBruce Lee setSensorsOverride(sensorAsyncResp, allCollections);
3374bb3dc34SCarol Wang }
33853b00f5dSEd Tanous }
33953b00f5dSEd Tanous
requestRoutesPower(App & app)34053b00f5dSEd Tanous inline void requestRoutesPower(App& app)
34153b00f5dSEd Tanous {
34253b00f5dSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Power/")
34353b00f5dSEd Tanous .privileges(redfish::privileges::getPower)
34453b00f5dSEd Tanous .methods(boost::beast::http::verb::get)(
34553b00f5dSEd Tanous std::bind_front(handleChassisPowerGet, std::ref(app)));
34653b00f5dSEd Tanous
34753b00f5dSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Power/")
34853b00f5dSEd Tanous .privileges(redfish::privileges::patchPower)
34953b00f5dSEd Tanous .methods(boost::beast::http::verb::patch)(
35053b00f5dSEd Tanous std::bind_front(handleChassisPowerPatch, std::ref(app)));
351413961deSRichard Marian Thomaiyar }
3522474adfaSEd Tanous
3532474adfaSEd Tanous } // namespace redfish
354