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*1ee48f2bSMatthew Barth _incTimer(events, [this](){ this->incTimerExpired(); }), 468600d9a0SMatthew Barth _decTimer(events, [this](){ this->decTimerExpired(); }) 477f88fe61SMatt Spinler { 487f88fe61SMatt Spinler auto& fanDefs = std::get<fanListPos>(def); 497f88fe61SMatt Spinler 507f88fe61SMatt Spinler for (auto& def : fanDefs) 517f88fe61SMatt Spinler { 527f88fe61SMatt Spinler _fans.emplace_back(std::make_unique<Fan>(bus, def)); 537f88fe61SMatt Spinler } 5438a93a8aSMatthew Barth 5514184131SMatthew Barth // Do not enable set speed events when in init mode 5614184131SMatthew Barth if (mode != Mode::init) 5714184131SMatthew Barth { 581bf0ce4bSMatthew Barth initEvents(def); 598600d9a0SMatthew Barth // Start timer for fan speed decreases 608600d9a0SMatthew Barth if (!_decTimer.running()) 618600d9a0SMatthew Barth { 628600d9a0SMatthew Barth //TODO Update time value to what's given in zones yaml 638600d9a0SMatthew Barth _decTimer.start(seconds(30), 648600d9a0SMatthew Barth phosphor::fan::util::Timer::TimerType::repeating); 658600d9a0SMatthew Barth } 667f88fe61SMatt Spinler } 6714184131SMatthew Barth } 687f88fe61SMatt Spinler 697f88fe61SMatt Spinler 707f88fe61SMatt Spinler void Zone::setSpeed(uint64_t speed) 717f88fe61SMatt Spinler { 727f88fe61SMatt Spinler for (auto& fan : _fans) 737f88fe61SMatt Spinler { 747f88fe61SMatt Spinler fan->setSpeed(speed); 757f88fe61SMatt Spinler } 767f88fe61SMatt Spinler } 777f88fe61SMatt Spinler 78861d77c3SMatthew Barth void Zone::setActiveAllow(const Group* group, bool isActiveAllow) 79861d77c3SMatthew Barth { 80861d77c3SMatthew Barth _active[group] = isActiveAllow; 81861d77c3SMatthew Barth if (!isActiveAllow) 82861d77c3SMatthew Barth { 83861d77c3SMatthew Barth _isActive = false; 84861d77c3SMatthew Barth } 85861d77c3SMatthew Barth else 86861d77c3SMatthew Barth { 87861d77c3SMatthew Barth // Check all entries are set to allow control active 88861d77c3SMatthew Barth auto actPred = [](auto const& entry) {return entry.second;}; 89861d77c3SMatthew Barth _isActive = std::all_of(_active.begin(), 90861d77c3SMatthew Barth _active.end(), 91861d77c3SMatthew Barth actPred); 92861d77c3SMatthew Barth } 93861d77c3SMatthew Barth } 94861d77c3SMatthew Barth 95240397b9SMatthew Barth void Zone::requestSpeedIncrease(uint64_t targetDelta) 96240397b9SMatthew Barth { 97240397b9SMatthew Barth // Only increase speed when delta is higher than 98240397b9SMatthew Barth // the current increase delta for the zone and currently under ceiling 99240397b9SMatthew Barth if (targetDelta > _incSpeedDelta && 100240397b9SMatthew Barth _targetSpeed < _ceilingSpeed) 101240397b9SMatthew Barth { 102240397b9SMatthew Barth _targetSpeed = (targetDelta - _incSpeedDelta) + _targetSpeed; 103240397b9SMatthew Barth _incSpeedDelta = targetDelta; 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 } 114*1ee48f2bSMatthew Barth // Cancel current timer countdown 115*1ee48f2bSMatthew Barth if (_incTimer.running()) 116*1ee48f2bSMatthew Barth { 117*1ee48f2bSMatthew Barth _incTimer.stop(); 118240397b9SMatthew Barth } 119*1ee48f2bSMatthew Barth setSpeed(_targetSpeed); 120*1ee48f2bSMatthew Barth // Start timer countdown for fan speed increase 121*1ee48f2bSMatthew Barth //TODO Update time value to what's given in zones yaml 122*1ee48f2bSMatthew Barth _incTimer.start(seconds(5), 123*1ee48f2bSMatthew Barth phosphor::fan::util::Timer::TimerType::oneshot); 124*1ee48f2bSMatthew Barth } 125*1ee48f2bSMatthew Barth } 126*1ee48f2bSMatthew Barth 127*1ee48f2bSMatthew Barth void Zone::incTimerExpired() 128*1ee48f2bSMatthew Barth { 129*1ee48f2bSMatthew Barth // Clear increase delta when timer expires allowing additional speed 130*1ee48f2bSMatthew Barth // increase requests or speed decreases to occur 131240397b9SMatthew Barth _incSpeedDelta = 0; 132240397b9SMatthew Barth } 133240397b9SMatthew Barth 1340ce99d8bSMatthew Barth void Zone::requestSpeedDecrease(uint64_t targetDelta) 1350ce99d8bSMatthew Barth { 1360ce99d8bSMatthew Barth // Only decrease the lowest target delta requested 1370ce99d8bSMatthew Barth if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta) 1380ce99d8bSMatthew Barth { 1390ce99d8bSMatthew Barth _decSpeedDelta = targetDelta; 1400ce99d8bSMatthew Barth } 1418600d9a0SMatthew Barth } 1420ce99d8bSMatthew Barth 1438600d9a0SMatthew Barth void Zone::decTimerExpired() 1448600d9a0SMatthew Barth { 145*1ee48f2bSMatthew Barth // Only decrease speeds when no requested increases exist and 146*1ee48f2bSMatthew Barth // the increase timer is not running (i.e. not in the middle of increasing) 147*1ee48f2bSMatthew Barth if (_incSpeedDelta == 0 && !_incTimer.running()) 1480ce99d8bSMatthew Barth { 1490ce99d8bSMatthew Barth // Target speed can not go below the defined floor speed 1500ce99d8bSMatthew Barth if ((_targetSpeed < _decSpeedDelta) || 1510ce99d8bSMatthew Barth (_targetSpeed - _decSpeedDelta < _floorSpeed)) 1520ce99d8bSMatthew Barth { 1530ce99d8bSMatthew Barth _targetSpeed = _floorSpeed; 1540ce99d8bSMatthew Barth } 1550ce99d8bSMatthew Barth else 1560ce99d8bSMatthew Barth { 1570ce99d8bSMatthew Barth _targetSpeed = _targetSpeed - _decSpeedDelta; 1580ce99d8bSMatthew Barth } 1590ce99d8bSMatthew Barth setSpeed(_targetSpeed); 1600ce99d8bSMatthew Barth } 1610ce99d8bSMatthew Barth // Clear decrease delta when timer expires 1620ce99d8bSMatthew Barth _decSpeedDelta = 0; 1638600d9a0SMatthew Barth // Decrease timer is restarted since its repeating 1640ce99d8bSMatthew Barth } 1650ce99d8bSMatthew Barth 1661bf0ce4bSMatthew Barth void Zone::initEvents(const ZoneDefinition& def) 1671bf0ce4bSMatthew Barth { 1681bf0ce4bSMatthew Barth // Setup signal trigger for set speed events 1691bf0ce4bSMatthew Barth for (auto& event : std::get<setSpeedEventsPos>(def)) 1701bf0ce4bSMatthew Barth { 1711bf0ce4bSMatthew Barth // Get the current value for each property 1721bf0ce4bSMatthew Barth for (auto& entry : std::get<groupPos>(event)) 1731bf0ce4bSMatthew Barth { 1741bf0ce4bSMatthew Barth refreshProperty(_bus, 1751bf0ce4bSMatthew Barth entry.first, 1761bf0ce4bSMatthew Barth std::get<intfPos>(entry.second), 1771bf0ce4bSMatthew Barth std::get<propPos>(entry.second)); 1781bf0ce4bSMatthew Barth } 1791bf0ce4bSMatthew Barth // Setup signal matches for property change events 1801bf0ce4bSMatthew Barth for (auto& prop : std::get<propChangeListPos>(event)) 1811bf0ce4bSMatthew Barth { 1821bf0ce4bSMatthew Barth _signalEvents.emplace_back( 1831bf0ce4bSMatthew Barth std::make_unique<EventData>( 1841bf0ce4bSMatthew Barth EventData 1851bf0ce4bSMatthew Barth { 1861bf0ce4bSMatthew Barth std::get<groupPos>(event), 1871bf0ce4bSMatthew Barth std::get<handlerObjPos>(prop), 1881bf0ce4bSMatthew Barth std::get<actionPos>(event) 1891bf0ce4bSMatthew Barth })); 1901bf0ce4bSMatthew Barth _matches.emplace_back( 1911bf0ce4bSMatthew Barth _bus, 1921bf0ce4bSMatthew Barth std::get<signaturePos>(prop).c_str(), 1931bf0ce4bSMatthew Barth std::bind(std::mem_fn(&Zone::handleEvent), 1941bf0ce4bSMatthew Barth this, 1951bf0ce4bSMatthew Barth std::placeholders::_1, 1961bf0ce4bSMatthew Barth _signalEvents.back().get())); 1971bf0ce4bSMatthew Barth } 1981bf0ce4bSMatthew Barth // Run action function for initial event state 1991bf0ce4bSMatthew Barth std::get<actionPos>(event)(*this, 2001bf0ce4bSMatthew Barth std::get<groupPos>(event)); 2011bf0ce4bSMatthew Barth } 2021bf0ce4bSMatthew Barth } 2031bf0ce4bSMatthew Barth 2041bf0ce4bSMatthew Barth void Zone::refreshProperty(sdbusplus::bus::bus& bus, 2051bf0ce4bSMatthew Barth const std::string& path, 2061bf0ce4bSMatthew Barth const std::string& iface, 2071bf0ce4bSMatthew Barth const std::string& prop) 2081bf0ce4bSMatthew Barth { 2091bf0ce4bSMatthew Barth PropertyVariantType property; 2101bf0ce4bSMatthew Barth getProperty(_bus, path, iface, prop, property); 2111bf0ce4bSMatthew Barth setPropertyValue(path.c_str(), iface.c_str(), prop.c_str(), property); 2121bf0ce4bSMatthew Barth } 2131bf0ce4bSMatthew Barth 214df3e8d67SMatthew Barth void Zone::getProperty(sdbusplus::bus::bus& bus, 215df3e8d67SMatthew Barth const std::string& path, 216df3e8d67SMatthew Barth const std::string& iface, 217df3e8d67SMatthew Barth const std::string& prop, 2189e741ed0SMatthew Barth PropertyVariantType& value) 219df3e8d67SMatthew Barth { 220df3e8d67SMatthew Barth auto serv = phosphor::fan::util::getService(path, iface, bus); 221df3e8d67SMatthew Barth auto hostCall = bus.new_method_call(serv.c_str(), 222df3e8d67SMatthew Barth path.c_str(), 223df3e8d67SMatthew Barth "org.freedesktop.DBus.Properties", 224df3e8d67SMatthew Barth "Get"); 225df3e8d67SMatthew Barth hostCall.append(iface); 226df3e8d67SMatthew Barth hostCall.append(prop); 227df3e8d67SMatthew Barth auto hostResponseMsg = bus.call(hostCall); 228df3e8d67SMatthew Barth if (hostResponseMsg.is_method_error()) 229df3e8d67SMatthew Barth { 230618027abSDinesh Chinari log<level::ERR>("Error in host call response for retrieving property"); 231618027abSDinesh Chinari elog<InternalFailure>(); 232df3e8d67SMatthew Barth } 2339e741ed0SMatthew Barth hostResponseMsg.read(value); 234df3e8d67SMatthew Barth } 235df3e8d67SMatthew Barth 23638a93a8aSMatthew Barth void Zone::handleEvent(sdbusplus::message::message& msg, 23734f1bda2SMatthew Barth const EventData* eventData) 23838a93a8aSMatthew Barth { 23938a93a8aSMatthew Barth // Handle the callback 24034f1bda2SMatthew Barth std::get<eventHandlerPos>(*eventData)(_bus, msg, *this); 24117d1fe23SMatthew Barth // Perform the action 24234f1bda2SMatthew Barth std::get<eventActionPos>(*eventData)(*this, 24334f1bda2SMatthew Barth std::get<eventGroupPos>(*eventData)); 24438a93a8aSMatthew Barth } 24538a93a8aSMatthew Barth 2467f88fe61SMatt Spinler } 2477f88fe61SMatt Spinler } 2487f88fe61SMatt Spinler } 249