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 */ 16cc8912e9SMatthew Barth #include "config.h" 17*3e1bb274SMatthew Barth 187f88fe61SMatt Spinler #include "zone.hpp" 19*3e1bb274SMatthew Barth 20d953bb25SMatthew Barth #include "sdbusplus.hpp" 21*3e1bb274SMatthew Barth #include "utility.hpp" 22*3e1bb274SMatthew Barth 23*3e1bb274SMatthew Barth #include <cereal/archives/json.hpp> 24*3e1bb274SMatthew Barth #include <cereal/cereal.hpp> 25*3e1bb274SMatthew Barth #include <phosphor-logging/elog-errors.hpp> 26*3e1bb274SMatthew Barth #include <phosphor-logging/elog.hpp> 27*3e1bb274SMatthew Barth #include <phosphor-logging/log.hpp> 28*3e1bb274SMatthew Barth #include <xyz/openbmc_project/Common/error.hpp> 29*3e1bb274SMatthew Barth 30*3e1bb274SMatthew Barth #include <chrono> 31*3e1bb274SMatthew Barth #include <experimental/filesystem> 32*3e1bb274SMatthew Barth #include <fstream> 33*3e1bb274SMatthew Barth #include <functional> 34*3e1bb274SMatthew Barth #include <stdexcept> 357f88fe61SMatt Spinler 367f88fe61SMatt Spinler namespace phosphor 377f88fe61SMatt Spinler { 387f88fe61SMatt Spinler namespace fan 397f88fe61SMatt Spinler { 407f88fe61SMatt Spinler namespace control 417f88fe61SMatt Spinler { 427f88fe61SMatt Spinler 438600d9a0SMatthew Barth using namespace std::chrono; 449014980aSMatthew Barth using namespace phosphor::fan; 45df3e8d67SMatthew Barth using namespace phosphor::logging; 46cc8912e9SMatthew Barth namespace fs = std::experimental::filesystem; 47*3e1bb274SMatthew Barth using InternalFailure = 48*3e1bb274SMatthew Barth sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 497f88fe61SMatt Spinler 50*3e1bb274SMatthew Barth Zone::Zone(Mode mode, sdbusplus::bus::bus& bus, const std::string& path, 51*3e1bb274SMatthew Barth const sdeventplus::Event& event, const ZoneDefinition& def) : 5293af4194SMatthew Barth ThermalObject(bus, path.c_str(), true), 53*3e1bb274SMatthew Barth _bus(bus), _path(path), 54766f8545SMatthew Barth _ifaces({"xyz.openbmc_project.Control.ThermalMode"}), 557f88fe61SMatt Spinler _fullSpeed(std::get<fullSpeedPos>(def)), 561de66629SMatthew Barth _zoneNum(std::get<zoneNumPos>(def)), 57e0ca13ebSMatthew Barth _defFloorSpeed(std::get<floorSpeedPos>(def)), 588600d9a0SMatthew Barth _defCeilingSpeed(std::get<fullSpeedPos>(def)), 59a956184bSMatthew Barth _incDelay(std::get<incDelayPos>(def)), 60a956184bSMatthew Barth _decInterval(std::get<decIntervalPos>(def)), 6122c36ab6SWilliam A. Kennington III _incTimer(event, std::bind(&Zone::incTimerExpired, this)), 62*3e1bb274SMatthew Barth _decTimer(event, std::bind(&Zone::decTimerExpired, this)), _eventLoop(event) 637f88fe61SMatt Spinler { 647f88fe61SMatt Spinler auto& fanDefs = std::get<fanListPos>(def); 657f88fe61SMatt Spinler 667f88fe61SMatt Spinler for (auto& def : fanDefs) 677f88fe61SMatt Spinler { 687f88fe61SMatt Spinler _fans.emplace_back(std::make_unique<Fan>(bus, def)); 697f88fe61SMatt Spinler } 7038a93a8aSMatthew Barth 7114184131SMatthew Barth // Do not enable set speed events when in init mode 7293af4194SMatthew Barth if (mode == Mode::control) 7314184131SMatthew Barth { 741b3e9602SMatthew Barth // Process any zone handlers defined 751b3e9602SMatthew Barth for (auto& hand : std::get<handlerPos>(def)) 761b3e9602SMatthew Barth { 771b3e9602SMatthew Barth hand(*this); 781b3e9602SMatthew Barth } 791b3e9602SMatthew Barth 809e4db25cSMatthew Barth // Restore thermal control current mode state 819e4db25cSMatthew Barth restoreCurrentMode(); 8293af4194SMatthew Barth 8393af4194SMatthew Barth // Emit objects added in control mode only 8493af4194SMatthew Barth this->emit_object_added(); 8593af4194SMatthew Barth 862b3db618SMatthew Barth // Update target speed to current zone target speed 872b3db618SMatthew Barth if (!_fans.empty()) 882b3db618SMatthew Barth { 892b3db618SMatthew Barth _targetSpeed = _fans.front()->getTargetSpeed(); 902b3db618SMatthew Barth } 91ccc7770eSMatthew Barth // Setup signal trigger for set speed events 92ccc7770eSMatthew Barth for (auto& event : std::get<setSpeedEventsPos>(def)) 93ccc7770eSMatthew Barth { 94ccc7770eSMatthew Barth initEvent(event); 95ccc7770eSMatthew Barth } 968600d9a0SMatthew Barth // Start timer for fan speed decreases 978fd879fbSWilliam A. Kennington III _decTimer.restart(_decInterval); 987f88fe61SMatt Spinler } 9914184131SMatthew Barth } 1007f88fe61SMatt Spinler 1017f88fe61SMatt Spinler void Zone::setSpeed(uint64_t speed) 1027f88fe61SMatt Spinler { 10360b00766SMatthew Barth if (_isActive) 10460b00766SMatthew Barth { 10560b00766SMatthew Barth _targetSpeed = speed; 1067f88fe61SMatt Spinler for (auto& fan : _fans) 1077f88fe61SMatt Spinler { 10860b00766SMatthew Barth fan->setSpeed(_targetSpeed); 10960b00766SMatthew Barth } 11060b00766SMatthew Barth } 11160b00766SMatthew Barth } 11260b00766SMatthew Barth 11360b00766SMatthew Barth void Zone::setFullSpeed() 11460b00766SMatthew Barth { 11560b00766SMatthew Barth if (_fullSpeed != 0) 11660b00766SMatthew Barth { 11760b00766SMatthew Barth _targetSpeed = _fullSpeed; 11860b00766SMatthew Barth for (auto& fan : _fans) 11960b00766SMatthew Barth { 12060b00766SMatthew Barth fan->setSpeed(_targetSpeed); 12160b00766SMatthew Barth } 1227f88fe61SMatt Spinler } 1237f88fe61SMatt Spinler } 1247f88fe61SMatt Spinler 125861d77c3SMatthew Barth void Zone::setActiveAllow(const Group* group, bool isActiveAllow) 126861d77c3SMatthew Barth { 12760b00766SMatthew Barth _active[*(group)] = isActiveAllow; 128861d77c3SMatthew Barth if (!isActiveAllow) 129861d77c3SMatthew Barth { 130861d77c3SMatthew Barth _isActive = false; 131861d77c3SMatthew Barth } 132861d77c3SMatthew Barth else 133861d77c3SMatthew Barth { 134861d77c3SMatthew Barth // Check all entries are set to allow control active 135861d77c3SMatthew Barth auto actPred = [](auto const& entry) { return entry.second; }; 136*3e1bb274SMatthew Barth _isActive = std::all_of(_active.begin(), _active.end(), actPred); 137861d77c3SMatthew Barth } 138861d77c3SMatthew Barth } 139861d77c3SMatthew Barth 140*3e1bb274SMatthew Barth void Zone::removeService(const Group* group, const std::string& name) 14155dea643SMatthew Barth { 14255dea643SMatthew Barth try 14355dea643SMatthew Barth { 14455dea643SMatthew Barth auto& sNames = _services.at(*group); 145*3e1bb274SMatthew Barth auto it = std::find_if(sNames.begin(), sNames.end(), 146*3e1bb274SMatthew Barth [&name](auto const& entry) { 14755dea643SMatthew Barth return name == std::get<namePos>(entry); 148*3e1bb274SMatthew Barth }); 14955dea643SMatthew Barth if (it != std::end(sNames)) 15055dea643SMatthew Barth { 15155dea643SMatthew Barth // Remove service name from group 15255dea643SMatthew Barth sNames.erase(it); 15355dea643SMatthew Barth } 15455dea643SMatthew Barth } 15555dea643SMatthew Barth catch (const std::out_of_range& oore) 15655dea643SMatthew Barth { 15755dea643SMatthew Barth // No services for group found 15855dea643SMatthew Barth } 15955dea643SMatthew Barth } 16055dea643SMatthew Barth 161*3e1bb274SMatthew Barth void Zone::setServiceOwner(const Group* group, const std::string& name, 162e59fdf70SMatthew Barth const bool hasOwner) 163e59fdf70SMatthew Barth { 164e59fdf70SMatthew Barth try 165e59fdf70SMatthew Barth { 166e59fdf70SMatthew Barth auto& sNames = _services.at(*group); 167*3e1bb274SMatthew Barth auto it = std::find_if(sNames.begin(), sNames.end(), 168*3e1bb274SMatthew Barth [&name](auto const& entry) { 169e59fdf70SMatthew Barth return name == std::get<namePos>(entry); 170*3e1bb274SMatthew Barth }); 171e59fdf70SMatthew Barth if (it != std::end(sNames)) 172e59fdf70SMatthew Barth { 173e59fdf70SMatthew Barth std::get<hasOwnerPos>(*it) = hasOwner; 174e59fdf70SMatthew Barth } 175e59fdf70SMatthew Barth else 176e59fdf70SMatthew Barth { 177e59fdf70SMatthew Barth _services[*group].emplace_back(name, hasOwner); 178e59fdf70SMatthew Barth } 179e59fdf70SMatthew Barth } 180e59fdf70SMatthew Barth catch (const std::out_of_range& oore) 181e59fdf70SMatthew Barth { 182e59fdf70SMatthew Barth _services[*group].emplace_back(name, hasOwner); 183e59fdf70SMatthew Barth } 184e59fdf70SMatthew Barth } 185e59fdf70SMatthew Barth 186480787c1SMatthew Barth void Zone::setServices(const Group* group) 187480787c1SMatthew Barth { 18855dea643SMatthew Barth // Remove the empty service name if exists 18955dea643SMatthew Barth removeService(group, ""); 190480787c1SMatthew Barth for (auto it = group->begin(); it != group->end(); ++it) 191480787c1SMatthew Barth { 192480787c1SMatthew Barth std::string name; 193480787c1SMatthew Barth bool hasOwner = false; 194480787c1SMatthew Barth try 195480787c1SMatthew Barth { 196*3e1bb274SMatthew Barth name = getService(std::get<pathPos>(*it), std::get<intfPos>(*it)); 197480787c1SMatthew Barth hasOwner = util::SDBusPlus::callMethodAndRead<bool>( 198*3e1bb274SMatthew Barth _bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", 199*3e1bb274SMatthew Barth "org.freedesktop.DBus", "NameHasOwner", name); 200480787c1SMatthew Barth } 201ba7b5feaSMatt Spinler catch (const util::DBusMethodError& e) 202480787c1SMatthew Barth { 203480787c1SMatthew Barth // Failed to get service name owner state 204480787c1SMatthew Barth hasOwner = false; 205480787c1SMatthew Barth } 206480787c1SMatthew Barth setServiceOwner(group, name, hasOwner); 207480787c1SMatthew Barth } 208480787c1SMatthew Barth } 209480787c1SMatthew Barth 210b4a7cb99SMatthew Barth void Zone::setFloor(uint64_t speed) 211b4a7cb99SMatthew Barth { 21298726c45SMatthew Barth // Check all entries are set to allow floor to be set 21398726c45SMatthew Barth auto pred = [](auto const& entry) { return entry.second; }; 214*3e1bb274SMatthew Barth auto setFloor = std::all_of(_floorChange.begin(), _floorChange.end(), pred); 21598726c45SMatthew Barth if (setFloor) 21698726c45SMatthew Barth { 217b4a7cb99SMatthew Barth _floorSpeed = speed; 218b4a7cb99SMatthew Barth // Floor speed above target, update target to floor speed 219b4a7cb99SMatthew Barth if (_targetSpeed < _floorSpeed) 220b4a7cb99SMatthew Barth { 221b4a7cb99SMatthew Barth requestSpeedIncrease(_floorSpeed - _targetSpeed); 222b4a7cb99SMatthew Barth } 223b4a7cb99SMatthew Barth } 22498726c45SMatthew Barth } 225b4a7cb99SMatthew Barth 226240397b9SMatthew Barth void Zone::requestSpeedIncrease(uint64_t targetDelta) 227240397b9SMatthew Barth { 228240397b9SMatthew Barth // Only increase speed when delta is higher than 229240397b9SMatthew Barth // the current increase delta for the zone and currently under ceiling 230*3e1bb274SMatthew Barth if (targetDelta > _incSpeedDelta && _targetSpeed < _ceilingSpeed) 231240397b9SMatthew Barth { 2324e728542SMatthew Barth auto requestTarget = getRequestSpeedBase(); 23360b00766SMatthew Barth requestTarget = (targetDelta - _incSpeedDelta) + requestTarget; 234240397b9SMatthew Barth _incSpeedDelta = targetDelta; 235240397b9SMatthew Barth // Target speed can not go above a defined ceiling speed 23660b00766SMatthew Barth if (requestTarget > _ceilingSpeed) 237240397b9SMatthew Barth { 23860b00766SMatthew Barth requestTarget = _ceilingSpeed; 239240397b9SMatthew Barth } 24060b00766SMatthew Barth setSpeed(requestTarget); 2418fd879fbSWilliam A. Kennington III // Retart timer countdown for fan speed increase 2428fd879fbSWilliam A. Kennington III _incTimer.restartOnce(_incDelay); 2431ee48f2bSMatthew Barth } 2441ee48f2bSMatthew Barth } 2451ee48f2bSMatthew Barth 2461ee48f2bSMatthew Barth void Zone::incTimerExpired() 2471ee48f2bSMatthew Barth { 2481ee48f2bSMatthew Barth // Clear increase delta when timer expires allowing additional speed 2491ee48f2bSMatthew Barth // increase requests or speed decreases to occur 250240397b9SMatthew Barth _incSpeedDelta = 0; 251240397b9SMatthew Barth } 252240397b9SMatthew Barth 2530ce99d8bSMatthew Barth void Zone::requestSpeedDecrease(uint64_t targetDelta) 2540ce99d8bSMatthew Barth { 2550ce99d8bSMatthew Barth // Only decrease the lowest target delta requested 2560ce99d8bSMatthew Barth if (_decSpeedDelta == 0 || targetDelta < _decSpeedDelta) 2570ce99d8bSMatthew Barth { 2580ce99d8bSMatthew Barth _decSpeedDelta = targetDelta; 2590ce99d8bSMatthew Barth } 2608600d9a0SMatthew Barth } 2610ce99d8bSMatthew Barth 2628600d9a0SMatthew Barth void Zone::decTimerExpired() 2638600d9a0SMatthew Barth { 264e4338cdbSMatthew Barth // Check all entries are set to allow a decrease 265e4338cdbSMatthew Barth auto pred = [](auto const& entry) { return entry.second; }; 266*3e1bb274SMatthew Barth auto decAllowed = std::all_of(_decAllowed.begin(), _decAllowed.end(), pred); 267e4338cdbSMatthew Barth 268e4338cdbSMatthew Barth // Only decrease speeds when allowed, 269d4c001f2SMatthew Barth // a requested decrease speed delta exists, 270e4338cdbSMatthew Barth // where no requested increases exist and 271e4338cdbSMatthew Barth // the increase timer is not running 272e4338cdbSMatthew Barth // (i.e. not in the middle of increasing) 273*3e1bb274SMatthew Barth if (decAllowed && _decSpeedDelta != 0 && _incSpeedDelta == 0 && 274*3e1bb274SMatthew Barth !_incTimer.isEnabled()) 2750ce99d8bSMatthew Barth { 2764e728542SMatthew Barth auto requestTarget = getRequestSpeedBase(); 277c63973a1SMatthew Barth // Request target speed should not start above ceiling 278c63973a1SMatthew Barth if (requestTarget > _ceilingSpeed) 279c63973a1SMatthew Barth { 280c63973a1SMatthew Barth requestTarget = _ceilingSpeed; 281c63973a1SMatthew Barth } 2820ce99d8bSMatthew Barth // Target speed can not go below the defined floor speed 28360b00766SMatthew Barth if ((requestTarget < _decSpeedDelta) || 28460b00766SMatthew Barth (requestTarget - _decSpeedDelta < _floorSpeed)) 2850ce99d8bSMatthew Barth { 28660b00766SMatthew Barth requestTarget = _floorSpeed; 2870ce99d8bSMatthew Barth } 2880ce99d8bSMatthew Barth else 2890ce99d8bSMatthew Barth { 29060b00766SMatthew Barth requestTarget = requestTarget - _decSpeedDelta; 2910ce99d8bSMatthew Barth } 29260b00766SMatthew Barth setSpeed(requestTarget); 2930ce99d8bSMatthew Barth } 2940ce99d8bSMatthew Barth // Clear decrease delta when timer expires 2950ce99d8bSMatthew Barth _decSpeedDelta = 0; 2968600d9a0SMatthew Barth // Decrease timer is restarted since its repeating 2970ce99d8bSMatthew Barth } 2980ce99d8bSMatthew Barth 299ccc7770eSMatthew Barth void Zone::initEvent(const SetSpeedEvent& event) 3001bf0ce4bSMatthew Barth { 3011b4de26aSMatthew Barth // Enable event triggers 3021b4de26aSMatthew Barth std::for_each( 303*3e1bb274SMatthew Barth std::get<triggerPos>(event).begin(), std::get<triggerPos>(event).end(), 304*3e1bb274SMatthew Barth [this, &event](auto const& trigger) { 30575d97350SMatthew Barth if (!std::get<actionsPos>(event).empty()) 30675d97350SMatthew Barth { 30775d97350SMatthew Barth std::for_each( 30875d97350SMatthew Barth std::get<actionsPos>(event).begin(), 30975d97350SMatthew Barth std::get<actionsPos>(event).end(), 310*3e1bb274SMatthew Barth [this, &trigger, &event](auto const& action) { 31175d97350SMatthew Barth // Default to use group defined with action if exists 31275d97350SMatthew Barth if (!std::get<adGroupPos>(action).empty()) 31375d97350SMatthew Barth { 314*3e1bb274SMatthew Barth trigger(*this, std::get<sseNamePos>(event), 31575d97350SMatthew Barth std::get<adGroupPos>(action), 31675d97350SMatthew Barth std::get<adActionsPos>(action)); 31775d97350SMatthew Barth } 31875d97350SMatthew Barth else 31975d97350SMatthew Barth { 320*3e1bb274SMatthew Barth trigger(*this, std::get<sseNamePos>(event), 3211b4de26aSMatthew Barth std::get<groupPos>(event), 32275d97350SMatthew Barth std::get<adActionsPos>(action)); 32375d97350SMatthew Barth } 324*3e1bb274SMatthew Barth }); 32575d97350SMatthew Barth } 32675d97350SMatthew Barth else 32775d97350SMatthew Barth { 328*3e1bb274SMatthew Barth trigger(*this, std::get<sseNamePos>(event), 329*3e1bb274SMatthew Barth std::get<groupPos>(event), {}); 33075d97350SMatthew Barth } 331*3e1bb274SMatthew Barth }); 3321bf0ce4bSMatthew Barth } 3331bf0ce4bSMatthew Barth 334f6b76d8eSMatthew Barth void Zone::removeEvent(const SetSpeedEvent& event) 335f6b76d8eSMatthew Barth { 33679cb8312SMatthew Barth // Remove event signals 33779cb8312SMatthew Barth auto sigIter = _signalEvents.find(std::get<sseNamePos>(event)); 33879cb8312SMatthew Barth if (sigIter != _signalEvents.end()) 339f6b76d8eSMatthew Barth { 34079cb8312SMatthew Barth auto& signals = sigIter->second; 34179cb8312SMatthew Barth for (auto it = signals.begin(); it != signals.end(); ++it) 342f9201abbSMatthew Barth { 34333bfe761SMatthew Barth removeSignal(it); 344f9201abbSMatthew Barth } 34579cb8312SMatthew Barth _signalEvents.erase(sigIter); 34633bfe761SMatthew Barth } 34779cb8312SMatthew Barth 348d7b716a6SMatthew Barth // Remove event timers 349d7b716a6SMatthew Barth auto timIter = _timerEvents.find(std::get<sseNamePos>(event)); 350d7b716a6SMatthew Barth if (timIter != _timerEvents.end()) 35133bfe761SMatthew Barth { 352d7b716a6SMatthew Barth _timerEvents.erase(timIter); 35333bfe761SMatthew Barth } 35433bfe761SMatthew Barth } 35533bfe761SMatthew Barth 356*3e1bb274SMatthew Barth std::vector<TimerEvent>::iterator 357*3e1bb274SMatthew Barth Zone::findTimer(const Group& eventGroup, 358d7b716a6SMatthew Barth const std::vector<Action>& eventActions, 359d7b716a6SMatthew Barth std::vector<TimerEvent>& eventTimers) 360bfb1a566SMatthew Barth { 361d7b716a6SMatthew Barth for (auto it = eventTimers.begin(); it != eventTimers.end(); ++it) 362bfb1a566SMatthew Barth { 3630420a932SWilliam A. Kennington III const auto& teEventData = *std::get<timerEventDataPos>(*it); 364d7b716a6SMatthew Barth if (std::get<eventGroupPos>(teEventData) == eventGroup && 365d7b716a6SMatthew Barth std::get<eventActionsPos>(teEventData).size() == 366bfb1a566SMatthew Barth eventActions.size()) 367bfb1a566SMatthew Barth { 368bfb1a566SMatthew Barth // TODO openbmc/openbmc#2328 - Use the action function target 369bfb1a566SMatthew Barth // for comparison 370*3e1bb274SMatthew Barth auto actsEqual = [](auto const& a1, auto const& a2) { 371*3e1bb274SMatthew Barth return a1.target_type().name() == a2.target_type().name(); 372bfb1a566SMatthew Barth }; 373*3e1bb274SMatthew Barth if (std::equal(eventActions.begin(), eventActions.end(), 374bfb1a566SMatthew Barth std::get<eventActionsPos>(teEventData).begin(), 375bfb1a566SMatthew Barth actsEqual)) 376bfb1a566SMatthew Barth { 377bfb1a566SMatthew Barth return it; 378bfb1a566SMatthew Barth } 379bfb1a566SMatthew Barth } 380bfb1a566SMatthew Barth } 381bfb1a566SMatthew Barth 382d7b716a6SMatthew Barth return eventTimers.end(); 383bfb1a566SMatthew Barth } 384bfb1a566SMatthew Barth 385*3e1bb274SMatthew Barth void Zone::addTimer(const std::string& name, const Group& group, 386*3e1bb274SMatthew Barth const std::vector<Action>& actions, const TimerConf& tConf) 38794fe1a0cSWilliam A. Kennington III { 388*3e1bb274SMatthew Barth auto eventData = std::make_unique<EventData>(group, "", nullptr, actions); 3898fd879fbSWilliam A. Kennington III Timer timer( 39094fe1a0cSWilliam A. Kennington III _eventLoop, 391*3e1bb274SMatthew Barth std::bind(&Zone::timerExpired, this, 3928fd879fbSWilliam A. Kennington III std::cref(std::get<Group>(*eventData)), 3938fd879fbSWilliam A. Kennington III std::cref(std::get<std::vector<Action>>(*eventData)))); 3948fd879fbSWilliam A. Kennington III if (std::get<TimerType>(tConf) == TimerType::repeating) 39594fe1a0cSWilliam A. Kennington III { 3968fd879fbSWilliam A. Kennington III timer.restart(std::get<intervalPos>(tConf)); 39794fe1a0cSWilliam A. Kennington III } 3988fd879fbSWilliam A. Kennington III else if (std::get<TimerType>(tConf) == TimerType::oneshot) 3998fd879fbSWilliam A. Kennington III { 4008fd879fbSWilliam A. Kennington III timer.restartOnce(std::get<intervalPos>(tConf)); 4018fd879fbSWilliam A. Kennington III } 4028fd879fbSWilliam A. Kennington III else 4038fd879fbSWilliam A. Kennington III { 4048fd879fbSWilliam A. Kennington III throw std::invalid_argument("Invalid Timer Type"); 4058fd879fbSWilliam A. Kennington III } 406d7b716a6SMatthew Barth _timerEvents[name].emplace_back(std::move(eventData), std::move(timer)); 40794fe1a0cSWilliam A. Kennington III } 40894fe1a0cSWilliam A. Kennington III 409c0c5f07fSWilliam A. Kennington III void Zone::timerExpired(const Group& eventGroup, 410c0c5f07fSWilliam A. Kennington III const std::vector<Action>& eventActions) 4119014980aSMatthew Barth { 412f9201abbSMatthew Barth // Perform the actions 413*3e1bb274SMatthew Barth std::for_each( 414*3e1bb274SMatthew Barth eventActions.begin(), eventActions.end(), 415*3e1bb274SMatthew Barth [this, &eventGroup](auto const& action) { action(*this, eventGroup); }); 4169014980aSMatthew Barth } 4179014980aSMatthew Barth 41838a93a8aSMatthew Barth void Zone::handleEvent(sdbusplus::message::message& msg, 41934f1bda2SMatthew Barth const EventData* eventData) 42038a93a8aSMatthew Barth { 42138a93a8aSMatthew Barth // Handle the callback 42234f1bda2SMatthew Barth std::get<eventHandlerPos> (*eventData)(_bus, msg, *this); 423f9201abbSMatthew Barth // Perform the actions 424*3e1bb274SMatthew Barth std::for_each(std::get<eventActionsPos>(*eventData).begin(), 425f9201abbSMatthew Barth std::get<eventActionsPos>(*eventData).end(), 426*3e1bb274SMatthew Barth [this, &eventData](auto const& action) { 427*3e1bb274SMatthew Barth action(*this, std::get<eventGroupPos>(*eventData)); 428f9201abbSMatthew Barth }); 42938a93a8aSMatthew Barth } 43038a93a8aSMatthew Barth 431a603ed01SMatthew Barth const std::string& Zone::getService(const std::string& path, 432a603ed01SMatthew Barth const std::string& intf) 433a603ed01SMatthew Barth { 434a603ed01SMatthew Barth // Retrieve service from cache 435a603ed01SMatthew Barth auto srvIter = _servTree.find(path); 436a603ed01SMatthew Barth if (srvIter != _servTree.end()) 437a603ed01SMatthew Barth { 438a603ed01SMatthew Barth for (auto& serv : srvIter->second) 439a603ed01SMatthew Barth { 440a603ed01SMatthew Barth auto it = std::find_if( 441*3e1bb274SMatthew Barth serv.second.begin(), serv.second.end(), 442*3e1bb274SMatthew Barth [&intf](auto const& interface) { return intf == interface; }); 443a603ed01SMatthew Barth if (it != std::end(serv.second)) 444a603ed01SMatthew Barth { 445a603ed01SMatthew Barth // Service found 446a603ed01SMatthew Barth return serv.first; 447a603ed01SMatthew Barth } 448a603ed01SMatthew Barth } 449a603ed01SMatthew Barth // Interface not found in cache, add and return 450a603ed01SMatthew Barth return addServices(path, intf, 0); 451a603ed01SMatthew Barth } 452a603ed01SMatthew Barth else 453a603ed01SMatthew Barth { 454a603ed01SMatthew Barth // Path not found in cache, add and return 455a603ed01SMatthew Barth return addServices(path, intf, 0); 456a603ed01SMatthew Barth } 457a603ed01SMatthew Barth } 458a603ed01SMatthew Barth 459a603ed01SMatthew Barth const std::string& Zone::addServices(const std::string& path, 460*3e1bb274SMatthew Barth const std::string& intf, int32_t depth) 461a603ed01SMatthew Barth { 462a603ed01SMatthew Barth static const std::string empty = ""; 463a603ed01SMatthew Barth auto it = _servTree.end(); 464a603ed01SMatthew Barth 465a603ed01SMatthew Barth // Get all subtree objects for the given interface 466a603ed01SMatthew Barth auto objects = util::SDBusPlus::getSubTree(_bus, "/", intf, depth); 467a603ed01SMatthew Barth // Add what's returned to the cache of path->services 468a603ed01SMatthew Barth for (auto& pIter : objects) 469a603ed01SMatthew Barth { 470a603ed01SMatthew Barth auto pathIter = _servTree.find(pIter.first); 471a603ed01SMatthew Barth if (pathIter != _servTree.end()) 472a603ed01SMatthew Barth { 473a603ed01SMatthew Barth // Path found in cache 474a603ed01SMatthew Barth for (auto& sIter : pIter.second) 475a603ed01SMatthew Barth { 476a603ed01SMatthew Barth auto servIter = pathIter->second.find(sIter.first); 477a603ed01SMatthew Barth if (servIter != pathIter->second.end()) 478a603ed01SMatthew Barth { 479a603ed01SMatthew Barth // Service found in cache 480a603ed01SMatthew Barth for (auto& iIter : sIter.second) 481a603ed01SMatthew Barth { 482e8b340bdSMatthew Barth if (std::find(servIter->second.begin(), 483e8b340bdSMatthew Barth servIter->second.end(), 484e8b340bdSMatthew Barth iIter) == servIter->second.end()) 485e8b340bdSMatthew Barth { 486a603ed01SMatthew Barth // Add interface to cache 487a603ed01SMatthew Barth servIter->second.emplace_back(iIter); 488a603ed01SMatthew Barth } 489a603ed01SMatthew Barth } 490e8b340bdSMatthew Barth } 491a603ed01SMatthew Barth else 492a603ed01SMatthew Barth { 493a603ed01SMatthew Barth // Service not found in cache 494a603ed01SMatthew Barth pathIter->second.insert(sIter); 495a603ed01SMatthew Barth } 496a603ed01SMatthew Barth } 497a603ed01SMatthew Barth } 498a603ed01SMatthew Barth else 499a603ed01SMatthew Barth { 500a603ed01SMatthew Barth _servTree.insert(pIter); 501a603ed01SMatthew Barth } 502a603ed01SMatthew Barth // When the paths match, since a single interface constraint is given, 503a603ed01SMatthew Barth // that is the service to return 504a603ed01SMatthew Barth if (path == pIter.first) 505a603ed01SMatthew Barth { 506a603ed01SMatthew Barth it = _servTree.find(pIter.first); 507a603ed01SMatthew Barth } 508a603ed01SMatthew Barth } 509a603ed01SMatthew Barth 510a603ed01SMatthew Barth if (it != _servTree.end()) 511a603ed01SMatthew Barth { 512a603ed01SMatthew Barth return it->second.begin()->first; 513a603ed01SMatthew Barth } 514a603ed01SMatthew Barth 515a603ed01SMatthew Barth return empty; 516a603ed01SMatthew Barth } 517a603ed01SMatthew Barth 518*3e1bb274SMatthew Barth auto Zone::getPersisted(const std::string& intf, const std::string& prop) 51970b2e7daSMatthew Barth { 52070b2e7daSMatthew Barth auto persisted = false; 52170b2e7daSMatthew Barth 52270b2e7daSMatthew Barth auto it = _persisted.find(intf); 52370b2e7daSMatthew Barth if (it != _persisted.end()) 52470b2e7daSMatthew Barth { 525*3e1bb274SMatthew Barth return std::any_of(it->second.begin(), it->second.end(), 526*3e1bb274SMatthew Barth [&prop](auto& p) { return prop == p; }); 52770b2e7daSMatthew Barth } 52870b2e7daSMatthew Barth 52970b2e7daSMatthew Barth return persisted; 53070b2e7daSMatthew Barth } 53170b2e7daSMatthew Barth 5326faf8943SMatthew Barth std::string Zone::current(std::string value) 5336faf8943SMatthew Barth { 534b390df1eSMatthew Barth auto current = ThermalObject::current(); 535b390df1eSMatthew Barth std::transform(value.begin(), value.end(), value.begin(), toupper); 536b390df1eSMatthew Barth 537221c90c3SMatthew Barth auto supported = ThermalObject::supported(); 538*3e1bb274SMatthew Barth auto isSupported = 539*3e1bb274SMatthew Barth std::any_of(supported.begin(), supported.end(), [&value](auto& s) { 540221c90c3SMatthew Barth std::transform(s.begin(), s.end(), s.begin(), toupper); 541221c90c3SMatthew Barth return value == s; 542221c90c3SMatthew Barth }); 543221c90c3SMatthew Barth 544221c90c3SMatthew Barth if (value != current && isSupported) 5456faf8943SMatthew Barth { 5466faf8943SMatthew Barth current = ThermalObject::current(value); 54770b2e7daSMatthew Barth if (getPersisted("xyz.openbmc_project.Control.ThermalMode", "Current")) 54870b2e7daSMatthew Barth { 5496faf8943SMatthew Barth saveCurrentMode(); 55070b2e7daSMatthew Barth } 551b390df1eSMatthew Barth // Trigger event(s) for current mode property change 552*3e1bb274SMatthew Barth auto eData = _objects[_path]["xyz.openbmc_project.Control.ThermalMode"] 553baea6c3fSMatthew Barth ["Current"]; 554baea6c3fSMatthew Barth if (eData != nullptr) 555baea6c3fSMatthew Barth { 556baea6c3fSMatthew Barth sdbusplus::message::message nullMsg{nullptr}; 557baea6c3fSMatthew Barth handleEvent(nullMsg, eData); 558baea6c3fSMatthew Barth } 5596faf8943SMatthew Barth } 560b390df1eSMatthew Barth 5616faf8943SMatthew Barth return current; 5626faf8943SMatthew Barth } 5636faf8943SMatthew Barth 564cc8912e9SMatthew Barth void Zone::saveCurrentMode() 565cc8912e9SMatthew Barth { 566cc8912e9SMatthew Barth fs::path path{CONTROL_PERSIST_ROOT_PATH}; 567cc8912e9SMatthew Barth // Append zone and property description 568cc8912e9SMatthew Barth path /= std::to_string(_zoneNum); 569cc8912e9SMatthew Barth path /= "CurrentMode"; 570cc8912e9SMatthew Barth std::ofstream ofs(path.c_str(), std::ios::binary); 571cc8912e9SMatthew Barth cereal::JSONOutputArchive oArch(ofs); 572cc8912e9SMatthew Barth oArch(ThermalObject::current()); 573cc8912e9SMatthew Barth } 574cc8912e9SMatthew Barth 5759e4db25cSMatthew Barth void Zone::restoreCurrentMode() 5769e4db25cSMatthew Barth { 577a2bed6edSMatthew Barth auto current = ThermalObject::current(); 5789e4db25cSMatthew Barth fs::path path{CONTROL_PERSIST_ROOT_PATH}; 5799e4db25cSMatthew Barth path /= std::to_string(_zoneNum); 5809e4db25cSMatthew Barth path /= "CurrentMode"; 5819e4db25cSMatthew Barth fs::create_directories(path.parent_path()); 5829e4db25cSMatthew Barth 5839e4db25cSMatthew Barth try 5849e4db25cSMatthew Barth { 5859e4db25cSMatthew Barth if (fs::exists(path)) 5869e4db25cSMatthew Barth { 5879e4db25cSMatthew Barth std::ifstream ifs(path.c_str(), std::ios::in | std::ios::binary); 5889e4db25cSMatthew Barth cereal::JSONInputArchive iArch(ifs); 5899e4db25cSMatthew Barth iArch(current); 5909e4db25cSMatthew Barth } 5919e4db25cSMatthew Barth } 5929e4db25cSMatthew Barth catch (std::exception& e) 5939e4db25cSMatthew Barth { 5949e4db25cSMatthew Barth log<level::ERR>(e.what()); 5959e4db25cSMatthew Barth fs::remove(path); 596a2bed6edSMatthew Barth current = ThermalObject::current(); 5979e4db25cSMatthew Barth } 5989e4db25cSMatthew Barth 5999e4db25cSMatthew Barth this->current(current); 6009e4db25cSMatthew Barth } 6019e4db25cSMatthew Barth 602*3e1bb274SMatthew Barth } // namespace control 603*3e1bb274SMatthew Barth } // namespace fan 604*3e1bb274SMatthew Barth } // namespace phosphor 605