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)), 45*a956184bSMatthew Barth _incDelay(std::get<incDelayPos>(def)), 46*a956184bSMatthew Barth _decInterval(std::get<decIntervalPos>(def)), 471ee48f2bSMatthew Barth _incTimer(events, [this](){ this->incTimerExpired(); }), 488600d9a0SMatthew Barth _decTimer(events, [this](){ this->decTimerExpired(); }) 497f88fe61SMatt Spinler { 507f88fe61SMatt Spinler auto& fanDefs = std::get<fanListPos>(def); 517f88fe61SMatt Spinler 527f88fe61SMatt Spinler for (auto& def : fanDefs) 537f88fe61SMatt Spinler { 547f88fe61SMatt Spinler _fans.emplace_back(std::make_unique<Fan>(bus, def)); 557f88fe61SMatt Spinler } 5638a93a8aSMatthew Barth 5714184131SMatthew Barth // Do not enable set speed events when in init mode 5814184131SMatthew Barth if (mode != Mode::init) 5914184131SMatthew Barth { 601bf0ce4bSMatthew Barth initEvents(def); 618600d9a0SMatthew Barth // Start timer for fan speed decreases 62*a956184bSMatthew Barth if (!_decTimer.running() && _decInterval != seconds::zero()) 638600d9a0SMatthew Barth { 64*a956184bSMatthew Barth _decTimer.start(_decInterval, 658600d9a0SMatthew Barth phosphor::fan::util::Timer::TimerType::repeating); 668600d9a0SMatthew Barth } 677f88fe61SMatt Spinler } 6814184131SMatthew Barth } 697f88fe61SMatt Spinler 707f88fe61SMatt Spinler 717f88fe61SMatt Spinler void Zone::setSpeed(uint64_t speed) 727f88fe61SMatt Spinler { 737f88fe61SMatt Spinler for (auto& fan : _fans) 747f88fe61SMatt Spinler { 757f88fe61SMatt Spinler fan->setSpeed(speed); 767f88fe61SMatt Spinler } 777f88fe61SMatt Spinler } 787f88fe61SMatt Spinler 79861d77c3SMatthew Barth void Zone::setActiveAllow(const Group* group, bool isActiveAllow) 80861d77c3SMatthew Barth { 81861d77c3SMatthew Barth _active[group] = isActiveAllow; 82861d77c3SMatthew Barth if (!isActiveAllow) 83861d77c3SMatthew Barth { 84861d77c3SMatthew Barth _isActive = false; 85861d77c3SMatthew Barth } 86861d77c3SMatthew Barth else 87861d77c3SMatthew Barth { 88861d77c3SMatthew Barth // Check all entries are set to allow control active 89861d77c3SMatthew Barth auto actPred = [](auto const& entry) {return entry.second;}; 90861d77c3SMatthew Barth _isActive = std::all_of(_active.begin(), 91861d77c3SMatthew Barth _active.end(), 92861d77c3SMatthew Barth actPred); 93861d77c3SMatthew Barth } 94861d77c3SMatthew Barth } 95861d77c3SMatthew Barth 96b4a7cb99SMatthew Barth void Zone::setFloor(uint64_t speed) 97b4a7cb99SMatthew Barth { 98b4a7cb99SMatthew Barth _floorSpeed = speed; 99b4a7cb99SMatthew Barth // Floor speed above target, update target to floor speed 100b4a7cb99SMatthew Barth if (_targetSpeed < _floorSpeed) 101b4a7cb99SMatthew Barth { 102b4a7cb99SMatthew Barth requestSpeedIncrease(_floorSpeed - _targetSpeed); 103b4a7cb99SMatthew Barth } 104b4a7cb99SMatthew Barth } 105b4a7cb99SMatthew Barth 106240397b9SMatthew Barth void Zone::requestSpeedIncrease(uint64_t targetDelta) 107240397b9SMatthew Barth { 108240397b9SMatthew Barth // Only increase speed when delta is higher than 109240397b9SMatthew Barth // the current increase delta for the zone and currently under ceiling 110240397b9SMatthew Barth if (targetDelta > _incSpeedDelta && 111240397b9SMatthew Barth _targetSpeed < _ceilingSpeed) 112240397b9SMatthew Barth { 113240397b9SMatthew Barth _targetSpeed = (targetDelta - _incSpeedDelta) + _targetSpeed; 114240397b9SMatthew Barth _incSpeedDelta = targetDelta; 115240397b9SMatthew Barth // Target speed can not go above a defined ceiling speed 116240397b9SMatthew Barth if (_targetSpeed > _ceilingSpeed) 117240397b9SMatthew Barth { 118240397b9SMatthew Barth _targetSpeed = _ceilingSpeed; 119240397b9SMatthew Barth } 1201ee48f2bSMatthew Barth // Cancel current timer countdown 1211ee48f2bSMatthew Barth if (_incTimer.running()) 1221ee48f2bSMatthew Barth { 1231ee48f2bSMatthew Barth _incTimer.stop(); 124240397b9SMatthew Barth } 1251ee48f2bSMatthew Barth setSpeed(_targetSpeed); 1261ee48f2bSMatthew Barth // Start timer countdown for fan speed increase 127*a956184bSMatthew Barth _incTimer.start(_incDelay, 1281ee48f2bSMatthew Barth phosphor::fan::util::Timer::TimerType::oneshot); 1291ee48f2bSMatthew Barth } 1301ee48f2bSMatthew Barth } 1311ee48f2bSMatthew Barth 1321ee48f2bSMatthew Barth void Zone::incTimerExpired() 1331ee48f2bSMatthew Barth { 1341ee48f2bSMatthew Barth // Clear increase delta when timer expires allowing additional speed 1351ee48f2bSMatthew Barth // increase requests or speed decreases to occur 136240397b9SMatthew Barth _incSpeedDelta = 0; 137240397b9SMatthew Barth } 138240397b9SMatthew Barth 1390ce99d8bSMatthew Barth void Zone::requestSpeedDecrease(uint64_t targetDelta) 1400ce99d8bSMatthew Barth { 1410ce99d8bSMatthew Barth // Only decrease the lowest target delta requested 1420ce99d8bSMatthew Barth if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta) 1430ce99d8bSMatthew Barth { 1440ce99d8bSMatthew Barth _decSpeedDelta = targetDelta; 1450ce99d8bSMatthew Barth } 1468600d9a0SMatthew Barth } 1470ce99d8bSMatthew Barth 1488600d9a0SMatthew Barth void Zone::decTimerExpired() 1498600d9a0SMatthew Barth { 1501ee48f2bSMatthew Barth // Only decrease speeds when no requested increases exist and 1511ee48f2bSMatthew Barth // the increase timer is not running (i.e. not in the middle of increasing) 1521ee48f2bSMatthew Barth if (_incSpeedDelta == 0 && !_incTimer.running()) 1530ce99d8bSMatthew Barth { 1540ce99d8bSMatthew Barth // Target speed can not go below the defined floor speed 1550ce99d8bSMatthew Barth if ((_targetSpeed < _decSpeedDelta) || 1560ce99d8bSMatthew Barth (_targetSpeed - _decSpeedDelta < _floorSpeed)) 1570ce99d8bSMatthew Barth { 1580ce99d8bSMatthew Barth _targetSpeed = _floorSpeed; 1590ce99d8bSMatthew Barth } 1600ce99d8bSMatthew Barth else 1610ce99d8bSMatthew Barth { 1620ce99d8bSMatthew Barth _targetSpeed = _targetSpeed - _decSpeedDelta; 1630ce99d8bSMatthew Barth } 1640ce99d8bSMatthew Barth setSpeed(_targetSpeed); 1650ce99d8bSMatthew Barth } 1660ce99d8bSMatthew Barth // Clear decrease delta when timer expires 1670ce99d8bSMatthew Barth _decSpeedDelta = 0; 1688600d9a0SMatthew Barth // Decrease timer is restarted since its repeating 1690ce99d8bSMatthew Barth } 1700ce99d8bSMatthew Barth 1711bf0ce4bSMatthew Barth void Zone::initEvents(const ZoneDefinition& def) 1721bf0ce4bSMatthew Barth { 1731bf0ce4bSMatthew Barth // Setup signal trigger for set speed events 1741bf0ce4bSMatthew Barth for (auto& event : std::get<setSpeedEventsPos>(def)) 1751bf0ce4bSMatthew Barth { 1761bf0ce4bSMatthew Barth // Get the current value for each property 1771bf0ce4bSMatthew Barth for (auto& entry : std::get<groupPos>(event)) 1781bf0ce4bSMatthew Barth { 1791bf0ce4bSMatthew Barth refreshProperty(_bus, 1801bf0ce4bSMatthew Barth entry.first, 1811bf0ce4bSMatthew Barth std::get<intfPos>(entry.second), 1821bf0ce4bSMatthew Barth std::get<propPos>(entry.second)); 1831bf0ce4bSMatthew Barth } 1841bf0ce4bSMatthew Barth // Setup signal matches for property change events 1851bf0ce4bSMatthew Barth for (auto& prop : std::get<propChangeListPos>(event)) 1861bf0ce4bSMatthew Barth { 1871bf0ce4bSMatthew Barth _signalEvents.emplace_back( 1881bf0ce4bSMatthew Barth std::make_unique<EventData>( 1891bf0ce4bSMatthew Barth EventData 1901bf0ce4bSMatthew Barth { 1911bf0ce4bSMatthew Barth std::get<groupPos>(event), 1921bf0ce4bSMatthew Barth std::get<handlerObjPos>(prop), 1931bf0ce4bSMatthew Barth std::get<actionPos>(event) 1941bf0ce4bSMatthew Barth })); 1951bf0ce4bSMatthew Barth _matches.emplace_back( 1961bf0ce4bSMatthew Barth _bus, 1971bf0ce4bSMatthew Barth std::get<signaturePos>(prop).c_str(), 1981bf0ce4bSMatthew Barth std::bind(std::mem_fn(&Zone::handleEvent), 1991bf0ce4bSMatthew Barth this, 2001bf0ce4bSMatthew Barth std::placeholders::_1, 2011bf0ce4bSMatthew Barth _signalEvents.back().get())); 2021bf0ce4bSMatthew Barth } 2031bf0ce4bSMatthew Barth // Run action function for initial event state 2041bf0ce4bSMatthew Barth std::get<actionPos>(event)(*this, 2051bf0ce4bSMatthew Barth std::get<groupPos>(event)); 2061bf0ce4bSMatthew Barth } 2071bf0ce4bSMatthew Barth } 2081bf0ce4bSMatthew Barth 2091bf0ce4bSMatthew Barth void Zone::refreshProperty(sdbusplus::bus::bus& bus, 2101bf0ce4bSMatthew Barth const std::string& path, 2111bf0ce4bSMatthew Barth const std::string& iface, 2121bf0ce4bSMatthew Barth const std::string& prop) 2131bf0ce4bSMatthew Barth { 2141bf0ce4bSMatthew Barth PropertyVariantType property; 2151bf0ce4bSMatthew Barth getProperty(_bus, path, iface, prop, property); 2161bf0ce4bSMatthew Barth setPropertyValue(path.c_str(), iface.c_str(), prop.c_str(), property); 2171bf0ce4bSMatthew Barth } 2181bf0ce4bSMatthew Barth 219df3e8d67SMatthew Barth void Zone::getProperty(sdbusplus::bus::bus& bus, 220df3e8d67SMatthew Barth const std::string& path, 221df3e8d67SMatthew Barth const std::string& iface, 222df3e8d67SMatthew Barth const std::string& prop, 2239e741ed0SMatthew Barth PropertyVariantType& value) 224df3e8d67SMatthew Barth { 225df3e8d67SMatthew Barth auto serv = phosphor::fan::util::getService(path, iface, bus); 226df3e8d67SMatthew Barth auto hostCall = bus.new_method_call(serv.c_str(), 227df3e8d67SMatthew Barth path.c_str(), 228df3e8d67SMatthew Barth "org.freedesktop.DBus.Properties", 229df3e8d67SMatthew Barth "Get"); 230df3e8d67SMatthew Barth hostCall.append(iface); 231df3e8d67SMatthew Barth hostCall.append(prop); 232df3e8d67SMatthew Barth auto hostResponseMsg = bus.call(hostCall); 233df3e8d67SMatthew Barth if (hostResponseMsg.is_method_error()) 234df3e8d67SMatthew Barth { 235618027abSDinesh Chinari log<level::ERR>("Error in host call response for retrieving property"); 236618027abSDinesh Chinari elog<InternalFailure>(); 237df3e8d67SMatthew Barth } 2389e741ed0SMatthew Barth hostResponseMsg.read(value); 239df3e8d67SMatthew Barth } 240df3e8d67SMatthew Barth 24138a93a8aSMatthew Barth void Zone::handleEvent(sdbusplus::message::message& msg, 24234f1bda2SMatthew Barth const EventData* eventData) 24338a93a8aSMatthew Barth { 24438a93a8aSMatthew Barth // Handle the callback 24534f1bda2SMatthew Barth std::get<eventHandlerPos>(*eventData)(_bus, msg, *this); 24617d1fe23SMatthew Barth // Perform the action 24734f1bda2SMatthew Barth std::get<eventActionPos>(*eventData)(*this, 24834f1bda2SMatthew Barth std::get<eventGroupPos>(*eventData)); 24938a93a8aSMatthew Barth } 25038a93a8aSMatthew Barth 2517f88fe61SMatt Spinler } 2527f88fe61SMatt Spinler } 2537f88fe61SMatt Spinler } 254