blob: 1ca0b8101da4364d05f6f140ee9677135ebdc7af [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 */
Dinesh Chinari618027a2017-06-26 23:26:50 -050016#include <phosphor-logging/log.hpp>
Matthew Barthdf3e8d62017-05-31 11:07:24 -050017#include <phosphor-logging/elog.hpp>
Dinesh Chinari618027a2017-06-26 23:26:50 -050018#include <phosphor-logging/elog-errors.hpp>
19#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler7f88fe62017-04-10 14:39:02 -050020#include "zone.hpp"
Matthew Barthdf3e8d62017-05-31 11:07:24 -050021#include "utility.hpp"
Matt Spinler7f88fe62017-04-10 14:39:02 -050022
23namespace phosphor
24{
25namespace fan
26{
27namespace control
28{
29
Matthew Barthdf3e8d62017-05-31 11:07:24 -050030using namespace phosphor::logging;
Dinesh Chinari618027a2017-06-26 23:26:50 -050031using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
32 Error::InternalFailure;
Matt Spinler7f88fe62017-04-10 14:39:02 -050033
Matthew Barth14184132017-05-19 14:37:30 -050034Zone::Zone(Mode mode,
35 sdbusplus::bus::bus& bus,
Matt Spinler7f88fe62017-04-10 14:39:02 -050036 const ZoneDefinition& def) :
37 _bus(bus),
38 _fullSpeed(std::get<fullSpeedPos>(def)),
Matthew Barth1de66622017-06-12 13:13:02 -050039 _zoneNum(std::get<zoneNumPos>(def)),
Matthew Barthe0ca13e2017-06-13 16:29:09 -050040 _defFloorSpeed(std::get<floorSpeedPos>(def)),
41 _defCeilingSpeed(std::get<fullSpeedPos>(def))
Matt Spinler7f88fe62017-04-10 14:39:02 -050042{
43 auto& fanDefs = std::get<fanListPos>(def);
44
45 for (auto& def : fanDefs)
46 {
47 _fans.emplace_back(std::make_unique<Fan>(bus, def));
48 }
Matthew Barth38a93a82017-05-11 14:12:27 -050049
Matthew Barth14184132017-05-19 14:37:30 -050050 // Do not enable set speed events when in init mode
51 if (mode != Mode::init)
Matthew Barth17d1fe22017-05-11 15:00:36 -050052 {
Matthew Barth14184132017-05-19 14:37:30 -050053 // Setup signal trigger for set speed events
54 for (auto& event : std::get<setSpeedEventsPos>(def))
Matthew Barth17d1fe22017-05-11 15:00:36 -050055 {
Matthew Barthdf3e8d62017-05-31 11:07:24 -050056 // Get the current value for each property
57 for (auto& entry : std::get<groupPos>(event))
58 {
59 try
60 {
Matthew Barth9e741ed2017-06-02 16:29:09 -050061 PropertyVariantType property;
Matthew Barthdf3e8d62017-05-31 11:07:24 -050062 getProperty(_bus,
63 entry.first,
64 std::get<intfPos>(entry.second),
65 std::get<propPos>(entry.second),
Matthew Barth9e741ed2017-06-02 16:29:09 -050066 property);
Matthew Barthdf3e8d62017-05-31 11:07:24 -050067 setPropertyValue(entry.first.c_str(),
Matthew Barthcec5ab72017-06-02 15:20:56 -050068 std::get<intfPos>(entry.second).c_str(),
Matthew Barthdf3e8d62017-05-31 11:07:24 -050069 std::get<propPos>(entry.second).c_str(),
Matthew Barth9e741ed2017-06-02 16:29:09 -050070 property);
Matthew Barthdf3e8d62017-05-31 11:07:24 -050071 }
72 catch (const std::exception& e)
73 {
74 log<level::ERR>(e.what());
75 }
76 }
77 // Setup signal matches for property change events
Matthew Barth14184132017-05-19 14:37:30 -050078 for (auto& prop : std::get<propChangeListPos>(event))
79 {
80 _signalEvents.emplace_back(
Matthew Barth34f1bda2017-05-31 13:45:36 -050081 std::make_unique<EventData>(
Matthew Barth14184132017-05-19 14:37:30 -050082 EventData
83 {
84 std::get<groupPos>(event),
85 std::get<handlerObjPos>(prop),
86 std::get<actionPos>(event)
87 }));
88 _matches.emplace_back(
89 bus,
90 std::get<signaturePos>(prop).c_str(),
Matthew Barth34f1bda2017-05-31 13:45:36 -050091 std::bind(std::mem_fn(&Zone::handleEvent),
92 this,
93 std::placeholders::_1,
94 _signalEvents.back().get()));
Matthew Barth14184132017-05-19 14:37:30 -050095 }
Matthew Barthdf3e8d62017-05-31 11:07:24 -050096 // Run action function for initial event state
97 std::get<actionPos>(event)(*this,
98 std::get<groupPos>(event));
Matthew Barth17d1fe22017-05-11 15:00:36 -050099 }
Matthew Barth0ce99d82017-06-22 15:07:29 -0500100 //TODO openbmc/openbmc#1625 Start timer for fan speed decreases
Matthew Barth38a93a82017-05-11 14:12:27 -0500101 }
Matt Spinler7f88fe62017-04-10 14:39:02 -0500102}
103
104
105void Zone::setSpeed(uint64_t speed)
106{
107 for (auto& fan : _fans)
108 {
109 fan->setSpeed(speed);
110 }
111}
112
Matthew Barth861d77c2017-05-22 14:18:25 -0500113void Zone::setActiveAllow(const Group* group, bool isActiveAllow)
114{
115 _active[group] = isActiveAllow;
116 if (!isActiveAllow)
117 {
118 _isActive = false;
119 }
120 else
121 {
122 // Check all entries are set to allow control active
123 auto actPred = [](auto const& entry) {return entry.second;};
124 _isActive = std::all_of(_active.begin(),
125 _active.end(),
126 actPred);
127 }
128}
129
Matthew Barth240397b2017-06-22 11:23:30 -0500130void Zone::requestSpeedIncrease(uint64_t targetDelta)
131{
132 // Only increase speed when delta is higher than
133 // the current increase delta for the zone and currently under ceiling
134 if (targetDelta > _incSpeedDelta &&
135 _targetSpeed < _ceilingSpeed)
136 {
137 _targetSpeed = (targetDelta - _incSpeedDelta) + _targetSpeed;
138 _incSpeedDelta = targetDelta;
139 //TODO openbmc/openbmc#1625 Cancel current timer countdown
140 //TODO Floor speed above target, update target to floor speed
141 if (_targetSpeed < _floorSpeed)
142 {
143 _targetSpeed = _floorSpeed;
144 }
145 // Target speed can not go above a defined ceiling speed
146 if (_targetSpeed > _ceilingSpeed)
147 {
148 _targetSpeed = _ceilingSpeed;
149 }
150
151 setSpeed(_targetSpeed);
152 //TODO openbmc/openbmc#1625 Start timer countdown for fan speed increase
153 }
154 //TODO openbmc/openbmc#1625 Clear increase delta when timer expires
155 _incSpeedDelta = 0;
156}
157
Matthew Barth0ce99d82017-06-22 15:07:29 -0500158void Zone::requestSpeedDecrease(uint64_t targetDelta)
159{
160 // Only decrease the lowest target delta requested
161 if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta)
162 {
163 _decSpeedDelta = targetDelta;
164 }
165
166 //TODO openbmc/openbmc#1625 Set decrease target speed when timer expires
167 // Only decrease speeds when no requested increases exist
168 if (_incSpeedDelta == 0)
169 {
170 // Target speed can not go below the defined floor speed
171 if ((_targetSpeed < _decSpeedDelta) ||
172 (_targetSpeed - _decSpeedDelta < _floorSpeed))
173 {
174 _targetSpeed = _floorSpeed;
175 }
176 else
177 {
178 _targetSpeed = _targetSpeed - _decSpeedDelta;
179 }
180 setSpeed(_targetSpeed);
181 }
182 // Clear decrease delta when timer expires
183 _decSpeedDelta = 0;
184 //TODO openbmc/openbmc#1625 Restart decrease timer
185}
186
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500187void Zone::getProperty(sdbusplus::bus::bus& bus,
188 const std::string& path,
189 const std::string& iface,
190 const std::string& prop,
Matthew Barth9e741ed2017-06-02 16:29:09 -0500191 PropertyVariantType& value)
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500192{
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500193 auto serv = phosphor::fan::util::getService(path, iface, bus);
194 auto hostCall = bus.new_method_call(serv.c_str(),
195 path.c_str(),
196 "org.freedesktop.DBus.Properties",
197 "Get");
198 hostCall.append(iface);
199 hostCall.append(prop);
200 auto hostResponseMsg = bus.call(hostCall);
201 if (hostResponseMsg.is_method_error())
202 {
Dinesh Chinari618027a2017-06-26 23:26:50 -0500203 log<level::ERR>("Error in host call response for retrieving property");
204 elog<InternalFailure>();
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500205 }
Matthew Barth9e741ed2017-06-02 16:29:09 -0500206 hostResponseMsg.read(value);
Matthew Barthdf3e8d62017-05-31 11:07:24 -0500207}
208
Matthew Barth38a93a82017-05-11 14:12:27 -0500209void Zone::handleEvent(sdbusplus::message::message& msg,
Matthew Barth34f1bda2017-05-31 13:45:36 -0500210 const EventData* eventData)
Matthew Barth38a93a82017-05-11 14:12:27 -0500211{
212 // Handle the callback
Matthew Barth34f1bda2017-05-31 13:45:36 -0500213 std::get<eventHandlerPos>(*eventData)(_bus, msg, *this);
Matthew Barth17d1fe22017-05-11 15:00:36 -0500214 // Perform the action
Matthew Barth34f1bda2017-05-31 13:45:36 -0500215 std::get<eventActionPos>(*eventData)(*this,
216 std::get<eventGroupPos>(*eventData));
Matthew Barth38a93a82017-05-11 14:12:27 -0500217}
218
Matt Spinler7f88fe62017-04-10 14:39:02 -0500219}
220}
221}