blob: 3ae81390e7fa124e68d1d26db9aeec76dbc13b9e [file] [log] [blame]
Matthew Barth4f0d3b72020-08-27 14:32:15 -05001/**
2 * Copyright © 2020 IBM 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
18#include "config_base.hpp"
Matthew Barthde90fb42021-03-04 16:34:28 -060019#include "fan.hpp"
Matthew Bartha0dd1352021-03-09 11:10:49 -060020#include "xyz/openbmc_project/Control/ThermalMode/server.hpp"
Matthew Barth4f0d3b72020-08-27 14:32:15 -050021
22#include <nlohmann/json.hpp>
Matthew Barthacd737c2021-03-04 11:04:01 -060023#include <sdbusplus/bus.hpp>
Matthew Barth4f0d3b72020-08-27 14:32:15 -050024
Matthew Barth651f03a2020-08-27 16:15:11 -050025#include <any>
26#include <functional>
27#include <map>
28#include <tuple>
29
Matthew Barth4f0d3b72020-08-27 14:32:15 -050030namespace phosphor::fan::control::json
31{
32
33using json = nlohmann::json;
34
Matthew Bartha0dd1352021-03-09 11:10:49 -060035/* Extend the Control::ThermalMode interface */
36using ThermalObject = sdbusplus::server::object::object<
37 sdbusplus::xyz::openbmc_project::Control::server::ThermalMode>;
38
Matthew Barth4f0d3b72020-08-27 14:32:15 -050039/**
40 * @class Zone - Represents a configured fan control zone
41 *
42 * A zone object contains the configured attributes for a zone that groups
Matthew Barthe47c9582021-03-09 14:24:02 -060043 * a number of fans together to be under the same target control. These
44 * configuration attributes include, but are not limited to, the default ceiling
45 * of the fans within the zone, a default floor, the delay between increases, a
46 * decrease interval, and any profiles(OPTIONAL) the zone should be included in.
Matthew Barth4f0d3b72020-08-27 14:32:15 -050047 *
48 * (When no profile for a zone is given, the zone defaults to always exist)
49 *
50 */
Matthew Bartha0dd1352021-03-09 11:10:49 -060051class Zone : public ConfigBase, public ThermalObject
Matthew Barth4f0d3b72020-08-27 14:32:15 -050052{
53 public:
54 /* JSON file name for zones */
55 static constexpr auto confFileName = "zones.json";
Matthew Barth216229c2020-09-24 13:47:33 -050056 static constexpr auto thermModeIntf =
57 "xyz.openbmc_project.Control.ThermalMode";
58 static constexpr auto supportedProp = "Supported";
59 static constexpr auto currentProp = "Current";
Matthew Barth651f03a2020-08-27 16:15:11 -050060
Matthew Barth4f0d3b72020-08-27 14:32:15 -050061 Zone() = delete;
62 Zone(const Zone&) = delete;
63 Zone(Zone&&) = delete;
64 Zone& operator=(const Zone&) = delete;
65 Zone& operator=(Zone&&) = delete;
66 ~Zone() = default;
67
68 /**
69 * Constructor
70 * Parses and populates a zone from JSON object data
71 *
Matthew Barthacd737c2021-03-04 11:04:01 -060072 * @param[in] bus - sdbusplus bus object
Matthew Barth4f0d3b72020-08-27 14:32:15 -050073 * @param[in] jsonObj - JSON object
74 */
Matthew Barthacd737c2021-03-04 11:04:01 -060075 Zone(sdbusplus::bus::bus& bus, const json& jsonObj);
Matthew Barth4f0d3b72020-08-27 14:32:15 -050076
77 /**
Matthew Barthe47c9582021-03-09 14:24:02 -060078 * @brief Get the default ceiling
Matthew Barth4f0d3b72020-08-27 14:32:15 -050079 *
Matthew Barthe47c9582021-03-09 14:24:02 -060080 * Default ceiling is the highest target the fans within this zone is
81 * allowed to increase to. The zone's ceiling defaults to this unless
82 * changed by some configured event.
Matthew Barth4f0d3b72020-08-27 14:32:15 -050083 *
Matthew Barthe47c9582021-03-09 14:24:02 -060084 * @return Default ceiling of this zone
Matthew Barth4f0d3b72020-08-27 14:32:15 -050085 */
Matthew Barthe47c9582021-03-09 14:24:02 -060086 inline const auto& getDefaultCeiling() const
Matthew Barth4f0d3b72020-08-27 14:32:15 -050087 {
Matthew Barthe47c9582021-03-09 14:24:02 -060088 return _defaultCeiling;
Matthew Barth4f0d3b72020-08-27 14:32:15 -050089 }
90
91 /**
Matthew Barthe47c9582021-03-09 14:24:02 -060092 * @brief Get the default floor
Matthew Barth4f0d3b72020-08-27 14:32:15 -050093 *
Matthew Barthe47c9582021-03-09 14:24:02 -060094 * The default floor is the lowest target the fans within this zone
95 * are allowed to decrease to. The zone's floor defaults to this
Matthew Barth4f0d3b72020-08-27 14:32:15 -050096 * unless changed by some configured event.
97 *
Matthew Barthe47c9582021-03-09 14:24:02 -060098 * @return Default floor
Matthew Barth4f0d3b72020-08-27 14:32:15 -050099 */
100 inline const auto& getDefaultFloor() const
101 {
102 return _defaultFloor;
103 }
104
105 /**
Matthew Barthe47c9582021-03-09 14:24:02 -0600106 * @brief Get the increase delay(OPTIONAL)
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500107 *
Matthew Barthe47c9582021-03-09 14:24:02 -0600108 * The increase delay is the amount of time(in seconds) increases
109 * to a target are delayed before being made. The default is 0, which
110 * results in immediate increase requests when any events result in
111 * a change to the target.
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500112 *
113 * It is recommend a value other than 0 is configured, but that inherently
Matthew Barthe47c9582021-03-09 14:24:02 -0600114 * depends on the fan controller and configured increases.
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500115 *
Matthew Barthe47c9582021-03-09 14:24:02 -0600116 * @return Increase delay(in seconds)
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500117 */
118 inline const auto& getIncDelay() const
119 {
120 return _incDelay;
121 }
122
123 /**
Matthew Barthe47c9582021-03-09 14:24:02 -0600124 * @brief Get the decrease interval
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500125 *
Matthew Barthe47c9582021-03-09 14:24:02 -0600126 * Decreases happen on a set interval when no requests for an increase
127 * in fan targets exists. This is the interval(in seconds) at which the fans
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500128 * within the zone are decreased if events exist that result in a target
Matthew Barthe47c9582021-03-09 14:24:02 -0600129 * decrease.
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500130 *
Matthew Barthe47c9582021-03-09 14:24:02 -0600131 * @return Decrease interval(in seconds)
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500132 */
133 inline const auto& getDecInterval() const
134 {
135 return _decInterval;
136 }
137
Matthew Barth651f03a2020-08-27 16:15:11 -0500138 /**
Matthew Barthdc776c82021-02-25 16:06:16 -0600139 * @brief Get the target increase delta
140 *
141 * @return - The current target increase delta
142 */
143 inline auto& getIncDelta() const
144 {
145 return _incDelta;
146 };
147
148 /**
Matthew Barth45c44ea2021-03-03 13:16:14 -0600149 * @brief Get the target decrease delta
150 *
151 * @return - The current target decrease delta
152 */
153 inline auto& getDecDelta() const
154 {
155 return _decDelta;
156 };
157
158 /**
Matthew Barthde90fb42021-03-04 16:34:28 -0600159 * @brief Add a fan object to the zone
160 *
161 * @param[in] fan - Unique pointer to a fan object that will be moved into
162 * the zone
163 *
164 * Adds a fan object to the list of fans that make up the zone by moving the
165 * fan object into the list.
166 */
167 void addFan(std::unique_ptr<Fan> fan);
168
Matthew Barth12cb1252021-03-08 16:47:30 -0600169 /**
Matthew Barth8ba715e2021-03-05 09:00:05 -0600170 * Sets all fans in the zone to the target given when the zone is active
171 *
172 * @param[in] target - Target for fans
173 */
174 void setTarget(uint64_t target);
175
176 /**
177 * @brief Sets the automatic fan control allowed active state
178 *
179 * @param[in] ident - An identifier that affects the active state
180 * @param[in] isActiveAllow - Active state according to group
181 */
182 void setActiveAllow(const std::string& ident, bool isActiveAllow);
183
184 /**
Matthew Barth12cb1252021-03-08 16:47:30 -0600185 * @brief Set the floor to the given target and increase target to the floor
186 * when the target is below the floor value when floor changes are allowed.
187 *
188 * @param[in] target - Target to set the floor to
189 */
190 void setFloor(uint64_t target);
191
192 /**
193 * @brief Sets the floor change allowed state
194 *
195 * @param[in] ident - An identifier that affects floor changes
196 * @param[in] isAllow - Allow state according to the identifier
197 */
198 inline void setFloorChangeAllow(const std::string& ident, bool isAllow)
199 {
200 _floorChange[ident] = isAllow;
201 }
202
203 /**
Matthew Barth45c44ea2021-03-03 13:16:14 -0600204 * @brief Sets the decrease allowed state of a group
205 *
206 * @param[in] ident - An identifier that affects speed decreases
207 * @param[in] isAllow - Allow state according to the identifier
208 */
209 inline void setDecreaseAllow(const std::string& ident, bool isAllow)
210 {
211 _decAllowed[ident] = isAllow;
212 }
213
214 /**
Matthew Barth12cb1252021-03-08 16:47:30 -0600215 * @brief Calculate the requested target from the given delta and increases
216 * the fans, not going above the ceiling.
217 *
218 * @param[in] targetDelta - The delta to increase the target by
219 */
220 void requestIncrease(uint64_t targetDelta);
221
Matthew Bartha0dd1352021-03-09 11:10:49 -0600222 /**
Matthew Barth45c44ea2021-03-03 13:16:14 -0600223 * @brief Calculate the lowest requested decrease target from the given
224 * delta within a decrease interval.
225 *
226 * @param[in] targetDelta - The delta to decrease the target by
227 */
228 void requestDecrease(uint64_t targetDelta);
229
230 /**
Matthew Barth07fecfc2021-01-29 09:04:43 -0600231 * @brief Set the requested target base to be used as the target to base a
232 * new requested target from
233 *
234 * @param[in] targetBase - Base target value to use
235 */
236 inline void setRequestTargetBase(uint64_t targetBase)
237 {
238 _requestTargetBase = targetBase;
239 };
240
241 /**
Matthew Bartha0dd1352021-03-09 11:10:49 -0600242 * @brief Set a property to be persisted
243 *
244 * @param[in] intf - Interface containing property
245 * @param[in] prop - Property to be persisted
246 */
247 void setPersisted(const std::string& intf, const std::string& prop);
248
249 /**
250 * @brief Overridden thermal object's set 'Current' property function
251 *
252 * @param[in] value - Value to set 'Current' to
253 *
254 * @return - The updated value of the 'Current' property
255 */
256 std::string current(std::string value) override;
257
Matthew Barthb584d812021-03-11 15:55:04 -0600258 /**
259 * @brief A handler function to set/update a property on a zone
260 * @details Sets or updates a zone's dbus property to the given value using
261 * the provided base dbus object's set property function
262 *
263 * @param[in] intf - Interface on zone object
264 * @param[in] prop - Property on interface
265 * @param[in] func - Zone object's set property function pointer
266 * @param[in] value - Value to set property to
267 * @param[in] persist - Persist property value or not
268 *
269 * @return Lambda function
270 * A lambda function to set/update the zone's dbus property
271 */
272 template <typename T>
273 static auto setProperty(const char* intf, const char* prop,
274 T (Zone::*func)(T), T&& value, bool persist)
275 {
276 return [=, value = std::forward<T>(value)](Zone* zone) {
277 (zone->*func)(value);
278 if (persist)
279 {
280 zone->setPersisted(intf, prop);
281 }
282 };
283 }
284
285 /**
286 * @brief A handler function to set/update a zone's dbus property's persist
287 * state
288 * @details Sets or updates a zone's dbus property's persist state where the
289 * value of the property is to be left unchanged
290 *
291 * @param[in] intf - Interface on zone object
292 * @param[in] prop - Property on interface
293 * @param[in] persist - Persist property value or not
294 *
295 * @return Lambda function
296 * A lambda function to set/update the zone's dbus property's persist
297 * state
298 */
299 static auto setPropertyPersist(const char* intf, const char* prop,
300 bool persist)
301 {
302 return [=](Zone* zone) {
303 if (persist)
304 {
305 zone->setPersisted(intf, prop);
306 }
307 };
308 }
309
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500310 private:
Matthew Barthe47c9582021-03-09 14:24:02 -0600311 /* The zone's default ceiling value for fans */
312 uint64_t _defaultCeiling;
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500313
Matthew Barthe47c9582021-03-09 14:24:02 -0600314 /* The zone's default floor value for fans */
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500315 uint64_t _defaultFloor;
316
Matthew Barthe47c9582021-03-09 14:24:02 -0600317 /* Zone's increase delay(in seconds) (OPTIONAL) */
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500318 uint64_t _incDelay;
319
Matthew Barthe47c9582021-03-09 14:24:02 -0600320 /* Zone's decrease interval(in seconds) */
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500321 uint64_t _decInterval;
322
Matthew Barth12cb1252021-03-08 16:47:30 -0600323 /* The floor target to not go below */
324 uint64_t _floor;
325
326 /* Target for this zone */
327 uint64_t _target;
328
Matthew Barth2b3253e2021-03-09 14:51:16 -0600329 /* Zone increase delta */
330 uint64_t _incDelta;
331
Matthew Barth45c44ea2021-03-03 13:16:14 -0600332 /* Zone decrease delta */
333 uint64_t _decDelta;
334
Matthew Barth2b3253e2021-03-09 14:51:16 -0600335 /* The ceiling target to not go above */
336 uint64_t _ceiling;
337
338 /* Requested target base */
339 uint64_t _requestTargetBase;
340
Matthew Barth12cb1252021-03-08 16:47:30 -0600341 /* Map of whether floor changes are allowed by a string identifier */
342 std::map<std::string, bool> _floorChange;
343
Matthew Barth45c44ea2021-03-03 13:16:14 -0600344 /* Map of controlling decreases allowed by a string identifer */
345 std::map<std::string, bool> _decAllowed;
346
Matthew Bartha0dd1352021-03-09 11:10:49 -0600347 /* Map of interfaces to persisted properties the zone hosts*/
348 std::map<std::string, std::vector<std::string>> _propsPersisted;
349
Matthew Barth8ba715e2021-03-05 09:00:05 -0600350 /* Automatic fan control active state */
351 bool _isActive;
352
353 /* Map of active fan control allowed by a string identifier */
354 std::map<std::string, bool> _active;
355
Matthew Barthb584d812021-03-11 15:55:04 -0600356 /* Interface to property mapping of their associated set property handler
357 * function */
358 static const std::map<
359 std::string,
360 std::map<std::string,
361 std::function<std::function<void(Zone*)>(const json&, bool)>>>
Matthew Barth216229c2020-09-24 13:47:33 -0500362 _intfPropHandlers;
Matthew Barth651f03a2020-08-27 16:15:11 -0500363
Matthew Barthde90fb42021-03-04 16:34:28 -0600364 /* List of fans included in this zone */
365 std::vector<std::unique_ptr<Fan>> _fans;
366
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500367 /**
Matthew Barthe47c9582021-03-09 14:24:02 -0600368 * @brief Parse and set the zone's default ceiling value
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500369 *
370 * @param[in] jsonObj - JSON object for the zone
371 *
Matthew Barthe47c9582021-03-09 14:24:02 -0600372 * Sets the default ceiling value for the zone from the JSON configuration
373 * object
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500374 */
Matthew Barthe47c9582021-03-09 14:24:02 -0600375 void setDefaultCeiling(const json& jsonObj);
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500376
377 /**
Matthew Barthe47c9582021-03-09 14:24:02 -0600378 * @brief Parse and set the zone's default floor value
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500379 *
380 * @param[in] jsonObj - JSON object for the zone
381 *
Matthew Barthe47c9582021-03-09 14:24:02 -0600382 * Sets the default floor value for the zone from the JSON configuration
383 * object
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500384 */
385 void setDefaultFloor(const json& jsonObj);
386
387 /**
388 * @brief Parse and set the zone's decrease interval(in seconds)
389 *
390 * @param[in] jsonObj - JSON object for the zone
391 *
Matthew Barthe47c9582021-03-09 14:24:02 -0600392 * Sets the decrease interval(in seconds) for the zone from the JSON
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500393 * configuration object
394 */
395 void setDecInterval(const json& jsonObj);
Matthew Barth651f03a2020-08-27 16:15:11 -0500396
397 /**
Matthew Barth216229c2020-09-24 13:47:33 -0500398 * @brief Parse and set the interfaces served by the zone(OPTIONAL)
Matthew Barth651f03a2020-08-27 16:15:11 -0500399 *
400 * @param[in] jsonObj - JSON object for the zone
401 *
Matthew Barth216229c2020-09-24 13:47:33 -0500402 * Constructs any zone interface handler functions for interfaces that the
403 * zone serves which contains the interface's property's value and
404 * persistency state (OPTIONAL). A property's "persist" state is defaulted
405 * to not be persisted when not given.
Matthew Barth651f03a2020-08-27 16:15:11 -0500406 */
407 void setInterfaces(const json& jsonObj);
Matthew Bartha0dd1352021-03-09 11:10:49 -0600408
409 /**
410 * @brief Is the property persisted
411 *
412 * @param[in] intf - Interface containing property
413 * @param[in] prop - Property to check if persisted
414 *
415 * @return - True if property is to be persisted, false otherwise
416 */
417 bool isPersisted(const std::string& intf, const std::string& prop);
418
419 /**
420 * @brief Save the thermal control current mode property to persisted
421 * storage
422 */
423 void saveCurrentMode();
Matthew Barth2b3253e2021-03-09 14:51:16 -0600424
425 /**
426 * @brief Get the request target base if defined, otherwise the the current
427 * target is returned
428 *
429 * @return - The request target base or current target
430 */
431 inline auto getRequestTargetBase() const
432 {
433 return (_requestTargetBase != 0) ? _requestTargetBase : _target;
434 };
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500435};
436
Matthew Barth651f03a2020-08-27 16:15:11 -0500437/**
438 * Properties of interfaces supported by the zone configuration
439 */
440namespace zone::property
441{
442
443/**
Matthew Barth216229c2020-09-24 13:47:33 -0500444 * @brief "Supported" property on the "xyz.openbmc_project.Control.ThermalMode"
Matthew Barthb584d812021-03-11 15:55:04 -0600445 * interface parser. Also creates the handler function for the Zone object to
446 * initialize the property according to what's parsed from the configuration.
Matthew Barth651f03a2020-08-27 16:15:11 -0500447 *
448 * @param[in] jsonObj - JSON object for the "Supported" property
Matthew Barth216229c2020-09-24 13:47:33 -0500449 * @param[in] persist - Whether to persist the value or not
Matthew Barth651f03a2020-08-27 16:15:11 -0500450 *
Matthew Barthb584d812021-03-11 15:55:04 -0600451 * @return Zone interface set property handler function for the "Supported"
452 * property
Matthew Barth651f03a2020-08-27 16:15:11 -0500453 */
Matthew Barthb584d812021-03-11 15:55:04 -0600454std::function<void(Zone*)> supported(const json& jsonObj, bool persist);
Matthew Barth651f03a2020-08-27 16:15:11 -0500455
456/**
Matthew Barth216229c2020-09-24 13:47:33 -0500457 * @brief "Current" property on the "xyz.openbmc_project.Control.ThermalMode"
Matthew Barthb584d812021-03-11 15:55:04 -0600458 * interface parser. Also creates the handler function for the Zone object to
459 * initialize the property according to what's parsed from the configuration.
Matthew Barth651f03a2020-08-27 16:15:11 -0500460 *
461 * @param[in] jsonObj - JSON object for the "Current" property
Matthew Barth216229c2020-09-24 13:47:33 -0500462 * @param[in] persist - Whether to persist the value or not
Matthew Barth651f03a2020-08-27 16:15:11 -0500463 *
Matthew Barthb584d812021-03-11 15:55:04 -0600464 * @return Zone interface set property handler function for the "Current"
465 * property
Matthew Barth651f03a2020-08-27 16:15:11 -0500466 */
Matthew Barthb584d812021-03-11 15:55:04 -0600467std::function<void(Zone*)> current(const json& jsonObj, bool persist);
Matthew Barth651f03a2020-08-27 16:15:11 -0500468
469} // namespace zone::property
470
Matthew Barth4f0d3b72020-08-27 14:32:15 -0500471} // namespace phosphor::fan::control::json