17f88fe61SMatt Spinler /** 27f88fe61SMatt Spinler * Copyright © 2017 IBM Corporation 37f88fe61SMatt Spinler * 47f88fe61SMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License"); 57f88fe61SMatt Spinler * you may not use this file except in compliance with the License. 67f88fe61SMatt Spinler * You may obtain a copy of the License at 77f88fe61SMatt Spinler * 87f88fe61SMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0 97f88fe61SMatt Spinler * 107f88fe61SMatt Spinler * Unless required by applicable law or agreed to in writing, software 117f88fe61SMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS, 127f88fe61SMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137f88fe61SMatt Spinler * See the License for the specific language governing permissions and 147f88fe61SMatt Spinler * limitations under the License. 157f88fe61SMatt Spinler */ 168600d9a0SMatthew Barth #include <chrono> 17618027abSDinesh Chinari #include <phosphor-logging/log.hpp> 18df3e8d67SMatthew Barth #include <phosphor-logging/elog.hpp> 19618027abSDinesh Chinari #include <phosphor-logging/elog-errors.hpp> 20618027abSDinesh Chinari #include <xyz/openbmc_project/Common/error.hpp> 217f88fe61SMatt Spinler #include "zone.hpp" 22df3e8d67SMatthew Barth #include "utility.hpp" 237f88fe61SMatt Spinler 247f88fe61SMatt Spinler namespace phosphor 257f88fe61SMatt Spinler { 267f88fe61SMatt Spinler namespace fan 277f88fe61SMatt Spinler { 287f88fe61SMatt Spinler namespace control 297f88fe61SMatt Spinler { 307f88fe61SMatt Spinler 318600d9a0SMatthew Barth using namespace std::chrono; 32df3e8d67SMatthew Barth using namespace phosphor::logging; 33618027abSDinesh Chinari using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 34618027abSDinesh Chinari Error::InternalFailure; 357f88fe61SMatt Spinler 3614184131SMatthew Barth Zone::Zone(Mode mode, 3714184131SMatthew Barth sdbusplus::bus::bus& bus, 388600d9a0SMatthew Barth phosphor::fan::event::EventPtr& events, 397f88fe61SMatt Spinler const ZoneDefinition& def) : 407f88fe61SMatt Spinler _bus(bus), 417f88fe61SMatt Spinler _fullSpeed(std::get<fullSpeedPos>(def)), 421de66629SMatthew Barth _zoneNum(std::get<zoneNumPos>(def)), 43e0ca13ebSMatthew Barth _defFloorSpeed(std::get<floorSpeedPos>(def)), 448600d9a0SMatthew Barth _defCeilingSpeed(std::get<fullSpeedPos>(def)), 458600d9a0SMatthew Barth _decTimer(events, [this](){ this->decTimerExpired(); }) 467f88fe61SMatt Spinler { 477f88fe61SMatt Spinler auto& fanDefs = std::get<fanListPos>(def); 487f88fe61SMatt Spinler 497f88fe61SMatt Spinler for (auto& def : fanDefs) 507f88fe61SMatt Spinler { 517f88fe61SMatt Spinler _fans.emplace_back(std::make_unique<Fan>(bus, def)); 527f88fe61SMatt Spinler } 5338a93a8aSMatthew Barth 5414184131SMatthew Barth // Do not enable set speed events when in init mode 5514184131SMatthew Barth if (mode != Mode::init) 5614184131SMatthew Barth { 57*1bf0ce4bSMatthew Barth initEvents(def); 588600d9a0SMatthew Barth // Start timer for fan speed decreases 598600d9a0SMatthew Barth if (!_decTimer.running()) 608600d9a0SMatthew Barth { 618600d9a0SMatthew Barth //TODO Update time value to what's given in zones yaml 628600d9a0SMatthew Barth _decTimer.start(seconds(30), 638600d9a0SMatthew Barth phosphor::fan::util::Timer::TimerType::repeating); 648600d9a0SMatthew Barth } 657f88fe61SMatt Spinler } 6614184131SMatthew Barth } 677f88fe61SMatt Spinler 687f88fe61SMatt Spinler 697f88fe61SMatt Spinler void Zone::setSpeed(uint64_t speed) 707f88fe61SMatt Spinler { 717f88fe61SMatt Spinler for (auto& fan : _fans) 727f88fe61SMatt Spinler { 737f88fe61SMatt Spinler fan->setSpeed(speed); 747f88fe61SMatt Spinler } 757f88fe61SMatt Spinler } 767f88fe61SMatt Spinler 77861d77c3SMatthew Barth void Zone::setActiveAllow(const Group* group, bool isActiveAllow) 78861d77c3SMatthew Barth { 79861d77c3SMatthew Barth _active[group] = isActiveAllow; 80861d77c3SMatthew Barth if (!isActiveAllow) 81861d77c3SMatthew Barth { 82861d77c3SMatthew Barth _isActive = false; 83861d77c3SMatthew Barth } 84861d77c3SMatthew Barth else 85861d77c3SMatthew Barth { 86861d77c3SMatthew Barth // Check all entries are set to allow control active 87861d77c3SMatthew Barth auto actPred = [](auto const& entry) {return entry.second;}; 88861d77c3SMatthew Barth _isActive = std::all_of(_active.begin(), 89861d77c3SMatthew Barth _active.end(), 90861d77c3SMatthew Barth actPred); 91861d77c3SMatthew Barth } 92861d77c3SMatthew Barth } 93861d77c3SMatthew Barth 94240397b9SMatthew Barth void Zone::requestSpeedIncrease(uint64_t targetDelta) 95240397b9SMatthew Barth { 96240397b9SMatthew Barth // Only increase speed when delta is higher than 97240397b9SMatthew Barth // the current increase delta for the zone and currently under ceiling 98240397b9SMatthew Barth if (targetDelta > _incSpeedDelta && 99240397b9SMatthew Barth _targetSpeed < _ceilingSpeed) 100240397b9SMatthew Barth { 101240397b9SMatthew Barth _targetSpeed = (targetDelta - _incSpeedDelta) + _targetSpeed; 102240397b9SMatthew Barth _incSpeedDelta = targetDelta; 103240397b9SMatthew Barth //TODO openbmc/openbmc#1625 Cancel current timer countdown 104240397b9SMatthew Barth //TODO Floor speed above target, update target to floor speed 105240397b9SMatthew Barth if (_targetSpeed < _floorSpeed) 106240397b9SMatthew Barth { 107240397b9SMatthew Barth _targetSpeed = _floorSpeed; 108240397b9SMatthew Barth } 109240397b9SMatthew Barth // Target speed can not go above a defined ceiling speed 110240397b9SMatthew Barth if (_targetSpeed > _ceilingSpeed) 111240397b9SMatthew Barth { 112240397b9SMatthew Barth _targetSpeed = _ceilingSpeed; 113240397b9SMatthew Barth } 114240397b9SMatthew Barth 115240397b9SMatthew Barth setSpeed(_targetSpeed); 116240397b9SMatthew Barth //TODO openbmc/openbmc#1625 Start timer countdown for fan speed increase 117240397b9SMatthew Barth } 118240397b9SMatthew Barth //TODO openbmc/openbmc#1625 Clear increase delta when timer expires 119240397b9SMatthew Barth _incSpeedDelta = 0; 120240397b9SMatthew Barth } 121240397b9SMatthew Barth 1220ce99d8bSMatthew Barth void Zone::requestSpeedDecrease(uint64_t targetDelta) 1230ce99d8bSMatthew Barth { 1240ce99d8bSMatthew Barth // Only decrease the lowest target delta requested 1250ce99d8bSMatthew Barth if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta) 1260ce99d8bSMatthew Barth { 1270ce99d8bSMatthew Barth _decSpeedDelta = targetDelta; 1280ce99d8bSMatthew Barth } 1298600d9a0SMatthew Barth } 1300ce99d8bSMatthew Barth 1318600d9a0SMatthew Barth void Zone::decTimerExpired() 1328600d9a0SMatthew Barth { 1330ce99d8bSMatthew Barth // Only decrease speeds when no requested increases exist 1348600d9a0SMatthew Barth //TODO Add increase timer not running (i.e. not in the middle of increasing) 1350ce99d8bSMatthew Barth if (_incSpeedDelta == 0) 1360ce99d8bSMatthew Barth { 1370ce99d8bSMatthew Barth // Target speed can not go below the defined floor speed 1380ce99d8bSMatthew Barth if ((_targetSpeed < _decSpeedDelta) || 1390ce99d8bSMatthew Barth (_targetSpeed - _decSpeedDelta < _floorSpeed)) 1400ce99d8bSMatthew Barth { 1410ce99d8bSMatthew Barth _targetSpeed = _floorSpeed; 1420ce99d8bSMatthew Barth } 1430ce99d8bSMatthew Barth else 1440ce99d8bSMatthew Barth { 1450ce99d8bSMatthew Barth _targetSpeed = _targetSpeed - _decSpeedDelta; 1460ce99d8bSMatthew Barth } 1470ce99d8bSMatthew Barth setSpeed(_targetSpeed); 1480ce99d8bSMatthew Barth } 1490ce99d8bSMatthew Barth // Clear decrease delta when timer expires 1500ce99d8bSMatthew Barth _decSpeedDelta = 0; 1518600d9a0SMatthew Barth // Decrease timer is restarted since its repeating 1520ce99d8bSMatthew Barth } 1530ce99d8bSMatthew Barth 154*1bf0ce4bSMatthew Barth void Zone::initEvents(const ZoneDefinition& def) 155*1bf0ce4bSMatthew Barth { 156*1bf0ce4bSMatthew Barth // Setup signal trigger for set speed events 157*1bf0ce4bSMatthew Barth for (auto& event : std::get<setSpeedEventsPos>(def)) 158*1bf0ce4bSMatthew Barth { 159*1bf0ce4bSMatthew Barth // Get the current value for each property 160*1bf0ce4bSMatthew Barth for (auto& entry : std::get<groupPos>(event)) 161*1bf0ce4bSMatthew Barth { 162*1bf0ce4bSMatthew Barth refreshProperty(_bus, 163*1bf0ce4bSMatthew Barth entry.first, 164*1bf0ce4bSMatthew Barth std::get<intfPos>(entry.second), 165*1bf0ce4bSMatthew Barth std::get<propPos>(entry.second)); 166*1bf0ce4bSMatthew Barth } 167*1bf0ce4bSMatthew Barth // Setup signal matches for property change events 168*1bf0ce4bSMatthew Barth for (auto& prop : std::get<propChangeListPos>(event)) 169*1bf0ce4bSMatthew Barth { 170*1bf0ce4bSMatthew Barth _signalEvents.emplace_back( 171*1bf0ce4bSMatthew Barth std::make_unique<EventData>( 172*1bf0ce4bSMatthew Barth EventData 173*1bf0ce4bSMatthew Barth { 174*1bf0ce4bSMatthew Barth std::get<groupPos>(event), 175*1bf0ce4bSMatthew Barth std::get<handlerObjPos>(prop), 176*1bf0ce4bSMatthew Barth std::get<actionPos>(event) 177*1bf0ce4bSMatthew Barth })); 178*1bf0ce4bSMatthew Barth _matches.emplace_back( 179*1bf0ce4bSMatthew Barth _bus, 180*1bf0ce4bSMatthew Barth std::get<signaturePos>(prop).c_str(), 181*1bf0ce4bSMatthew Barth std::bind(std::mem_fn(&Zone::handleEvent), 182*1bf0ce4bSMatthew Barth this, 183*1bf0ce4bSMatthew Barth std::placeholders::_1, 184*1bf0ce4bSMatthew Barth _signalEvents.back().get())); 185*1bf0ce4bSMatthew Barth } 186*1bf0ce4bSMatthew Barth // Run action function for initial event state 187*1bf0ce4bSMatthew Barth std::get<actionPos>(event)(*this, 188*1bf0ce4bSMatthew Barth std::get<groupPos>(event)); 189*1bf0ce4bSMatthew Barth } 190*1bf0ce4bSMatthew Barth } 191*1bf0ce4bSMatthew Barth 192*1bf0ce4bSMatthew Barth void Zone::refreshProperty(sdbusplus::bus::bus& bus, 193*1bf0ce4bSMatthew Barth const std::string& path, 194*1bf0ce4bSMatthew Barth const std::string& iface, 195*1bf0ce4bSMatthew Barth const std::string& prop) 196*1bf0ce4bSMatthew Barth { 197*1bf0ce4bSMatthew Barth PropertyVariantType property; 198*1bf0ce4bSMatthew Barth getProperty(_bus, path, iface, prop, property); 199*1bf0ce4bSMatthew Barth setPropertyValue(path.c_str(), iface.c_str(), prop.c_str(), property); 200*1bf0ce4bSMatthew Barth } 201*1bf0ce4bSMatthew Barth 202df3e8d67SMatthew Barth void Zone::getProperty(sdbusplus::bus::bus& bus, 203df3e8d67SMatthew Barth const std::string& path, 204df3e8d67SMatthew Barth const std::string& iface, 205df3e8d67SMatthew Barth const std::string& prop, 2069e741ed0SMatthew Barth PropertyVariantType& value) 207df3e8d67SMatthew Barth { 208df3e8d67SMatthew Barth auto serv = phosphor::fan::util::getService(path, iface, bus); 209df3e8d67SMatthew Barth auto hostCall = bus.new_method_call(serv.c_str(), 210df3e8d67SMatthew Barth path.c_str(), 211df3e8d67SMatthew Barth "org.freedesktop.DBus.Properties", 212df3e8d67SMatthew Barth "Get"); 213df3e8d67SMatthew Barth hostCall.append(iface); 214df3e8d67SMatthew Barth hostCall.append(prop); 215df3e8d67SMatthew Barth auto hostResponseMsg = bus.call(hostCall); 216df3e8d67SMatthew Barth if (hostResponseMsg.is_method_error()) 217df3e8d67SMatthew Barth { 218618027abSDinesh Chinari log<level::ERR>("Error in host call response for retrieving property"); 219618027abSDinesh Chinari elog<InternalFailure>(); 220df3e8d67SMatthew Barth } 2219e741ed0SMatthew Barth hostResponseMsg.read(value); 222df3e8d67SMatthew Barth } 223df3e8d67SMatthew Barth 22438a93a8aSMatthew Barth void Zone::handleEvent(sdbusplus::message::message& msg, 22534f1bda2SMatthew Barth const EventData* eventData) 22638a93a8aSMatthew Barth { 22738a93a8aSMatthew Barth // Handle the callback 22834f1bda2SMatthew Barth std::get<eventHandlerPos>(*eventData)(_bus, msg, *this); 22917d1fe23SMatthew Barth // Perform the action 23034f1bda2SMatthew Barth std::get<eventActionPos>(*eventData)(*this, 23134f1bda2SMatthew Barth std::get<eventGroupPos>(*eventData)); 23238a93a8aSMatthew Barth } 23338a93a8aSMatthew Barth 2347f88fe61SMatt Spinler } 2357f88fe61SMatt Spinler } 2367f88fe61SMatt Spinler } 237