blob: 17e0089aa48146e7866355db6e9afaa4531ea27e [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)),
45 _decTimer(events, [this](){ this->decTimerExpired(); })
Matt Spinler7f88fe62017-04-10 14:39:02 -050046{
47 auto& fanDefs = std::get<fanListPos>(def);
48
49 for (auto& def : fanDefs)
50 {
51 _fans.emplace_back(std::make_unique<Fan>(bus, def));
52 }
Matthew Barth38a93a82017-05-11 14:12:27 -050053
Matthew Barth14184132017-05-19 14:37:30 -050054 // Do not enable set speed events when in init mode
55 if (mode != Mode::init)
Matthew Barth17d1fe22017-05-11 15:00:36 -050056 {
Matthew Barth14184132017-05-19 14:37:30 -050057 // Setup signal trigger for set speed events
58 for (auto& event : std::get<setSpeedEventsPos>(def))
Matthew Barth17d1fe22017-05-11 15:00:36 -050059 {
Matthew Barthdf3e8d62017-05-31 11:07:24 -050060 // Get the current value for each property
61 for (auto& entry : std::get<groupPos>(event))
62 {
63 try
64 {
Matthew Barth9e741ed2017-06-02 16:29:09 -050065 PropertyVariantType property;
Matthew Barthdf3e8d62017-05-31 11:07:24 -050066 getProperty(_bus,
67 entry.first,
68 std::get<intfPos>(entry.second),
69 std::get<propPos>(entry.second),
Matthew Barth9e741ed2017-06-02 16:29:09 -050070 property);
Matthew Barthdf3e8d62017-05-31 11:07:24 -050071 setPropertyValue(entry.first.c_str(),
Matthew Barthcec5ab72017-06-02 15:20:56 -050072 std::get<intfPos>(entry.second).c_str(),
Matthew Barthdf3e8d62017-05-31 11:07:24 -050073 std::get<propPos>(entry.second).c_str(),
Matthew Barth9e741ed2017-06-02 16:29:09 -050074 property);
Matthew Barthdf3e8d62017-05-31 11:07:24 -050075 }
76 catch (const std::exception& e)
77 {
78 log<level::ERR>(e.what());
79 }
80 }
81 // Setup signal matches for property change events
Matthew Barth14184132017-05-19 14:37:30 -050082 for (auto& prop : std::get<propChangeListPos>(event))
83 {
84 _signalEvents.emplace_back(
Matthew Barth34f1bda2017-05-31 13:45:36 -050085 std::make_unique<EventData>(
Matthew Barth14184132017-05-19 14:37:30 -050086 EventData
87 {
88 std::get<groupPos>(event),
89 std::get<handlerObjPos>(prop),
90 std::get<actionPos>(event)
91 }));
92 _matches.emplace_back(
93 bus,
94 std::get<signaturePos>(prop).c_str(),
Matthew Barth34f1bda2017-05-31 13:45:36 -050095 std::bind(std::mem_fn(&Zone::handleEvent),
96 this,
97 std::placeholders::_1,
98 _signalEvents.back().get()));
Matthew Barth14184132017-05-19 14:37:30 -050099 }
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500100 // Run action function for initial event state
101 std::get<actionPos>(event)(*this,
102 std::get<groupPos>(event));
Matthew Barth17d1fe22017-05-11 15:00:36 -0500103 }
Matthew Barth8600d9a2017-06-23 14:38:05 -0500104 // Start timer for fan speed decreases
105 if (!_decTimer.running())
106 {
107 //TODO Update time value to what's given in zones yaml
108 _decTimer.start(seconds(30),
109 phosphor::fan::util::Timer::TimerType::repeating);
110 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500111 }
Matt Spinler7f88fe62017-04-10 14:39:02 -0500112}
113
114
115void Zone::setSpeed(uint64_t speed)
116{
117 for (auto& fan : _fans)
118 {
119 fan->setSpeed(speed);
120 }
121}
122
Matthew Barth861d77c2017-05-22 14:18:25 -0500123void Zone::setActiveAllow(const Group* group, bool isActiveAllow)
124{
125 _active[group] = isActiveAllow;
126 if (!isActiveAllow)
127 {
128 _isActive = false;
129 }
130 else
131 {
132 // Check all entries are set to allow control active
133 auto actPred = [](auto const& entry) {return entry.second;};
134 _isActive = std::all_of(_active.begin(),
135 _active.end(),
136 actPred);
137 }
138}
139
Matthew Barth240397b2017-06-22 11:23:30 -0500140void Zone::requestSpeedIncrease(uint64_t targetDelta)
141{
142 // Only increase speed when delta is higher than
143 // the current increase delta for the zone and currently under ceiling
144 if (targetDelta > _incSpeedDelta &&
145 _targetSpeed < _ceilingSpeed)
146 {
147 _targetSpeed = (targetDelta - _incSpeedDelta) + _targetSpeed;
148 _incSpeedDelta = targetDelta;
149 //TODO openbmc/openbmc#1625 Cancel current timer countdown
150 //TODO Floor speed above target, update target to floor speed
151 if (_targetSpeed < _floorSpeed)
152 {
153 _targetSpeed = _floorSpeed;
154 }
155 // Target speed can not go above a defined ceiling speed
156 if (_targetSpeed > _ceilingSpeed)
157 {
158 _targetSpeed = _ceilingSpeed;
159 }
160
161 setSpeed(_targetSpeed);
162 //TODO openbmc/openbmc#1625 Start timer countdown for fan speed increase
163 }
164 //TODO openbmc/openbmc#1625 Clear increase delta when timer expires
165 _incSpeedDelta = 0;
166}
167
Matthew Barth0ce99d82017-06-22 15:07:29 -0500168void Zone::requestSpeedDecrease(uint64_t targetDelta)
169{
170 // Only decrease the lowest target delta requested
171 if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta)
172 {
173 _decSpeedDelta = targetDelta;
174 }
Matthew Barth8600d9a2017-06-23 14:38:05 -0500175}
Matthew Barth0ce99d82017-06-22 15:07:29 -0500176
Matthew Barth8600d9a2017-06-23 14:38:05 -0500177void Zone::decTimerExpired()
178{
Matthew Barth0ce99d82017-06-22 15:07:29 -0500179 // Only decrease speeds when no requested increases exist
Matthew Barth8600d9a2017-06-23 14:38:05 -0500180 //TODO Add increase timer not running (i.e. not in the middle of increasing)
Matthew Barth0ce99d82017-06-22 15:07:29 -0500181 if (_incSpeedDelta == 0)
182 {
183 // Target speed can not go below the defined floor speed
184 if ((_targetSpeed < _decSpeedDelta) ||
185 (_targetSpeed - _decSpeedDelta < _floorSpeed))
186 {
187 _targetSpeed = _floorSpeed;
188 }
189 else
190 {
191 _targetSpeed = _targetSpeed - _decSpeedDelta;
192 }
193 setSpeed(_targetSpeed);
194 }
195 // Clear decrease delta when timer expires
196 _decSpeedDelta = 0;
Matthew Barth8600d9a2017-06-23 14:38:05 -0500197 // Decrease timer is restarted since its repeating
Matthew Barth0ce99d82017-06-22 15:07:29 -0500198}
199
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500200void Zone::getProperty(sdbusplus::bus::bus& bus,
201 const std::string& path,
202 const std::string& iface,
203 const std::string& prop,
Matthew Barth9e741ed2017-06-02 16:29:09 -0500204 PropertyVariantType& value)
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500205{
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500206 auto serv = phosphor::fan::util::getService(path, iface, bus);
207 auto hostCall = bus.new_method_call(serv.c_str(),
208 path.c_str(),
209 "org.freedesktop.DBus.Properties",
210 "Get");
211 hostCall.append(iface);
212 hostCall.append(prop);
213 auto hostResponseMsg = bus.call(hostCall);
214 if (hostResponseMsg.is_method_error())
215 {
Dinesh Chinari618027a2017-06-26 23:26:50 -0500216 log<level::ERR>("Error in host call response for retrieving property");
217 elog<InternalFailure>();
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500218 }
Matthew Barth9e741ed2017-06-02 16:29:09 -0500219 hostResponseMsg.read(value);
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500220}
221
Matthew Barth38a93a82017-05-11 14:12:27 -0500222void Zone::handleEvent(sdbusplus::message::message& msg,
Matthew Barth34f1bda2017-05-31 13:45:36 -0500223 const EventData* eventData)
Matthew Barth38a93a82017-05-11 14:12:27 -0500224{
225 // Handle the callback
Matthew Barth34f1bda2017-05-31 13:45:36 -0500226 std::get<eventHandlerPos>(*eventData)(_bus, msg, *this);
Matthew Barth17d1fe22017-05-11 15:00:36 -0500227 // Perform the action
Matthew Barth34f1bda2017-05-31 13:45:36 -0500228 std::get<eventActionPos>(*eventData)(*this,
229 std::get<eventGroupPos>(*eventData));
Matthew Barth38a93a82017-05-11 14:12:27 -0500230}
231
Matt Spinler7f88fe62017-04-10 14:39:02 -0500232}
233}
234}