blob: 4fb60cd960cb9ab76c193478adab2e5ad7200d4d [file] [log] [blame]
Matt Spinler7f88fe62017-04-10 14:39:02 -05001/**
2 * Copyright © 2017 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 */
Matthew Barth8600d9a2017-06-23 14:38:05 -050016#include <chrono>
Dinesh Chinari618027a2017-06-26 23:26:50 -050017#include <phosphor-logging/log.hpp>
Matthew Barthdf3e8d62017-05-31 11:07:24 -050018#include <phosphor-logging/elog.hpp>
Dinesh Chinari618027a2017-06-26 23:26:50 -050019#include <phosphor-logging/elog-errors.hpp>
20#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler7f88fe62017-04-10 14:39:02 -050021#include "zone.hpp"
Matthew Barthdf3e8d62017-05-31 11:07:24 -050022#include "utility.hpp"
Matt Spinler7f88fe62017-04-10 14:39:02 -050023
24namespace phosphor
25{
26namespace fan
27{
28namespace control
29{
30
Matthew Barth8600d9a2017-06-23 14:38:05 -050031using namespace std::chrono;
Matthew Barthdf3e8d62017-05-31 11:07:24 -050032using namespace phosphor::logging;
Dinesh Chinari618027a2017-06-26 23:26:50 -050033using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
34 Error::InternalFailure;
Matt Spinler7f88fe62017-04-10 14:39:02 -050035
Matthew Barth14184132017-05-19 14:37:30 -050036Zone::Zone(Mode mode,
37 sdbusplus::bus::bus& bus,
Matthew Barth8600d9a2017-06-23 14:38:05 -050038 phosphor::fan::event::EventPtr& events,
Matt Spinler7f88fe62017-04-10 14:39:02 -050039 const ZoneDefinition& def) :
40 _bus(bus),
41 _fullSpeed(std::get<fullSpeedPos>(def)),
Matthew Barth1de66622017-06-12 13:13:02 -050042 _zoneNum(std::get<zoneNumPos>(def)),
Matthew Barthe0ca13e2017-06-13 16:29:09 -050043 _defFloorSpeed(std::get<floorSpeedPos>(def)),
Matthew Barth8600d9a2017-06-23 14:38:05 -050044 _defCeilingSpeed(std::get<fullSpeedPos>(def)),
Matthew Bartha9561842017-06-29 11:43:45 -050045 _incDelay(std::get<incDelayPos>(def)),
46 _decInterval(std::get<decIntervalPos>(def)),
Matthew Barth1ee48f22017-06-27 15:14:48 -050047 _incTimer(events, [this](){ this->incTimerExpired(); }),
Matthew Barth8600d9a2017-06-23 14:38:05 -050048 _decTimer(events, [this](){ this->decTimerExpired(); })
Matt Spinler7f88fe62017-04-10 14:39:02 -050049{
50 auto& fanDefs = std::get<fanListPos>(def);
51
52 for (auto& def : fanDefs)
53 {
54 _fans.emplace_back(std::make_unique<Fan>(bus, def));
55 }
Matthew Barth38a93a82017-05-11 14:12:27 -050056
Matthew Barth14184132017-05-19 14:37:30 -050057 // Do not enable set speed events when in init mode
58 if (mode != Mode::init)
Matthew Barth17d1fe22017-05-11 15:00:36 -050059 {
Matthew Barthccc77702017-07-28 13:43:04 -050060 // Setup signal trigger for set speed events
61 for (auto& event : std::get<setSpeedEventsPos>(def))
62 {
63 initEvent(event);
64 }
Matthew Barth8600d9a2017-06-23 14:38:05 -050065 // Start timer for fan speed decreases
Matthew Bartha9561842017-06-29 11:43:45 -050066 if (!_decTimer.running() && _decInterval != seconds::zero())
Matthew Barth8600d9a2017-06-23 14:38:05 -050067 {
Matthew Bartha9561842017-06-29 11:43:45 -050068 _decTimer.start(_decInterval,
Matthew Barth8600d9a2017-06-23 14:38:05 -050069 phosphor::fan::util::Timer::TimerType::repeating);
70 }
Matthew Barth38a93a82017-05-11 14:12:27 -050071 }
Matt Spinler7f88fe62017-04-10 14:39:02 -050072}
73
74
75void Zone::setSpeed(uint64_t speed)
76{
77 for (auto& fan : _fans)
78 {
79 fan->setSpeed(speed);
80 }
81}
82
Matthew Barth861d77c2017-05-22 14:18:25 -050083void Zone::setActiveAllow(const Group* group, bool isActiveAllow)
84{
85 _active[group] = isActiveAllow;
86 if (!isActiveAllow)
87 {
88 _isActive = false;
89 }
90 else
91 {
92 // Check all entries are set to allow control active
93 auto actPred = [](auto const& entry) {return entry.second;};
94 _isActive = std::all_of(_active.begin(),
95 _active.end(),
96 actPred);
97 }
98}
99
Matthew Barthb4a7cb92017-06-28 15:29:50 -0500100void Zone::setFloor(uint64_t speed)
101{
102 _floorSpeed = speed;
103 // Floor speed above target, update target to floor speed
104 if (_targetSpeed < _floorSpeed)
105 {
106 requestSpeedIncrease(_floorSpeed - _targetSpeed);
107 }
108}
109
Matthew Barth240397b2017-06-22 11:23:30 -0500110void Zone::requestSpeedIncrease(uint64_t targetDelta)
111{
112 // Only increase speed when delta is higher than
113 // the current increase delta for the zone and currently under ceiling
114 if (targetDelta > _incSpeedDelta &&
115 _targetSpeed < _ceilingSpeed)
116 {
117 _targetSpeed = (targetDelta - _incSpeedDelta) + _targetSpeed;
118 _incSpeedDelta = targetDelta;
Matthew Barth240397b2017-06-22 11:23:30 -0500119 // Target speed can not go above a defined ceiling speed
120 if (_targetSpeed > _ceilingSpeed)
121 {
122 _targetSpeed = _ceilingSpeed;
123 }
Matthew Barth1ee48f22017-06-27 15:14:48 -0500124 // Cancel current timer countdown
125 if (_incTimer.running())
126 {
127 _incTimer.stop();
128 }
Matthew Barth240397b2017-06-22 11:23:30 -0500129 setSpeed(_targetSpeed);
Matthew Barth1ee48f22017-06-27 15:14:48 -0500130 // Start timer countdown for fan speed increase
Matthew Bartha9561842017-06-29 11:43:45 -0500131 _incTimer.start(_incDelay,
Matthew Barth1ee48f22017-06-27 15:14:48 -0500132 phosphor::fan::util::Timer::TimerType::oneshot);
Matthew Barth240397b2017-06-22 11:23:30 -0500133 }
Matthew Barth1ee48f22017-06-27 15:14:48 -0500134}
135
136void Zone::incTimerExpired()
137{
138 // Clear increase delta when timer expires allowing additional speed
139 // increase requests or speed decreases to occur
Matthew Barth240397b2017-06-22 11:23:30 -0500140 _incSpeedDelta = 0;
141}
142
Matthew Barth0ce99d82017-06-22 15:07:29 -0500143void Zone::requestSpeedDecrease(uint64_t targetDelta)
144{
145 // Only decrease the lowest target delta requested
146 if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta)
147 {
148 _decSpeedDelta = targetDelta;
149 }
Matthew Barth8600d9a2017-06-23 14:38:05 -0500150}
Matthew Barth0ce99d82017-06-22 15:07:29 -0500151
Matthew Barth8600d9a2017-06-23 14:38:05 -0500152void Zone::decTimerExpired()
153{
Matthew Barth1ee48f22017-06-27 15:14:48 -0500154 // Only decrease speeds when no requested increases exist and
155 // the increase timer is not running (i.e. not in the middle of increasing)
156 if (_incSpeedDelta == 0 && !_incTimer.running())
Matthew Barth0ce99d82017-06-22 15:07:29 -0500157 {
158 // Target speed can not go below the defined floor speed
159 if ((_targetSpeed < _decSpeedDelta) ||
160 (_targetSpeed - _decSpeedDelta < _floorSpeed))
161 {
162 _targetSpeed = _floorSpeed;
163 }
164 else
165 {
166 _targetSpeed = _targetSpeed - _decSpeedDelta;
167 }
168 setSpeed(_targetSpeed);
169 }
170 // Clear decrease delta when timer expires
171 _decSpeedDelta = 0;
Matthew Barth8600d9a2017-06-23 14:38:05 -0500172 // Decrease timer is restarted since its repeating
Matthew Barth0ce99d82017-06-22 15:07:29 -0500173}
174
Matthew Barthccc77702017-07-28 13:43:04 -0500175void Zone::initEvent(const SetSpeedEvent& event)
Matthew Barth1bf0ce42017-06-23 16:16:30 -0500176{
Matthew Barthccc77702017-07-28 13:43:04 -0500177 // Get the current value for each property
178 for (auto& entry : std::get<groupPos>(event))
Matthew Barth1bf0ce42017-06-23 16:16:30 -0500179 {
Matthew Barthccc77702017-07-28 13:43:04 -0500180 refreshProperty(_bus,
181 entry.first,
182 std::get<intfPos>(entry.second),
183 std::get<propPos>(entry.second));
Matthew Barth1bf0ce42017-06-23 16:16:30 -0500184 }
Matthew Barthccc77702017-07-28 13:43:04 -0500185 // Setup signal matches for property change events
186 for (auto& prop : std::get<propChangeListPos>(event))
187 {
188 _signalEvents.emplace_back(
189 std::make_unique<EventData>(
190 EventData
191 {
192 std::get<groupPos>(event),
193 std::get<handlerObjPos>(prop),
194 std::get<actionPos>(event)
195 }));
196 _matches.emplace_back(
197 _bus,
198 std::get<signaturePos>(prop).c_str(),
199 std::bind(std::mem_fn(&Zone::handleEvent),
200 this,
201 std::placeholders::_1,
202 _signalEvents.back().get()));
203 }
204 // Run action function for initial event state
205 std::get<actionPos>(event)(*this,
206 std::get<groupPos>(event));
Matthew Barth1bf0ce42017-06-23 16:16:30 -0500207}
208
209void Zone::refreshProperty(sdbusplus::bus::bus& bus,
210 const std::string& path,
211 const std::string& iface,
212 const std::string& prop)
213{
214 PropertyVariantType property;
215 getProperty(_bus, path, iface, prop, property);
216 setPropertyValue(path.c_str(), iface.c_str(), prop.c_str(), property);
217}
218
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500219void Zone::getProperty(sdbusplus::bus::bus& bus,
220 const std::string& path,
221 const std::string& iface,
222 const std::string& prop,
Matthew Barth9e741ed2017-06-02 16:29:09 -0500223 PropertyVariantType& value)
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500224{
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500225 auto serv = phosphor::fan::util::getService(path, iface, bus);
226 auto hostCall = bus.new_method_call(serv.c_str(),
227 path.c_str(),
228 "org.freedesktop.DBus.Properties",
229 "Get");
230 hostCall.append(iface);
231 hostCall.append(prop);
232 auto hostResponseMsg = bus.call(hostCall);
233 if (hostResponseMsg.is_method_error())
234 {
Dinesh Chinari618027a2017-06-26 23:26:50 -0500235 log<level::ERR>("Error in host call response for retrieving property");
236 elog<InternalFailure>();
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500237 }
Matthew Barth9e741ed2017-06-02 16:29:09 -0500238 hostResponseMsg.read(value);
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500239}
240
Matthew Barth38a93a82017-05-11 14:12:27 -0500241void Zone::handleEvent(sdbusplus::message::message& msg,
Matthew Barth34f1bda2017-05-31 13:45:36 -0500242 const EventData* eventData)
Matthew Barth38a93a82017-05-11 14:12:27 -0500243{
244 // Handle the callback
Matthew Barth34f1bda2017-05-31 13:45:36 -0500245 std::get<eventHandlerPos>(*eventData)(_bus, msg, *this);
Matthew Barth17d1fe22017-05-11 15:00:36 -0500246 // Perform the action
Matthew Barth34f1bda2017-05-31 13:45:36 -0500247 std::get<eventActionPos>(*eventData)(*this,
248 std::get<eventGroupPos>(*eventData));
Matthew Barth38a93a82017-05-11 14:12:27 -0500249}
250
Matt Spinler7f88fe62017-04-10 14:39:02 -0500251}
252}
253}