1 /** 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 */ 16 #include <phosphor-logging/log.hpp> 17 #include <phosphor-logging/elog.hpp> 18 #include <phosphor-logging/elog-errors.hpp> 19 #include <xyz/openbmc_project/Common/error.hpp> 20 #include "zone.hpp" 21 #include "utility.hpp" 22 23 namespace phosphor 24 { 25 namespace fan 26 { 27 namespace control 28 { 29 30 using namespace phosphor::logging; 31 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 32 Error::InternalFailure; 33 34 Zone::Zone(Mode mode, 35 sdbusplus::bus::bus& bus, 36 const ZoneDefinition& def) : 37 _bus(bus), 38 _fullSpeed(std::get<fullSpeedPos>(def)), 39 _zoneNum(std::get<zoneNumPos>(def)), 40 _defFloorSpeed(std::get<floorSpeedPos>(def)) 41 { 42 auto& fanDefs = std::get<fanListPos>(def); 43 44 for (auto& def : fanDefs) 45 { 46 _fans.emplace_back(std::make_unique<Fan>(bus, def)); 47 } 48 49 // Do not enable set speed events when in init mode 50 if (mode != Mode::init) 51 { 52 // Setup signal trigger for set speed events 53 for (auto& event : std::get<setSpeedEventsPos>(def)) 54 { 55 // Get the current value for each property 56 for (auto& entry : std::get<groupPos>(event)) 57 { 58 try 59 { 60 PropertyVariantType property; 61 getProperty(_bus, 62 entry.first, 63 std::get<intfPos>(entry.second), 64 std::get<propPos>(entry.second), 65 property); 66 setPropertyValue(entry.first.c_str(), 67 std::get<intfPos>(entry.second).c_str(), 68 std::get<propPos>(entry.second).c_str(), 69 property); 70 } 71 catch (const std::exception& e) 72 { 73 log<level::ERR>(e.what()); 74 } 75 } 76 // Setup signal matches for property change events 77 for (auto& prop : std::get<propChangeListPos>(event)) 78 { 79 _signalEvents.emplace_back( 80 std::make_unique<EventData>( 81 EventData 82 { 83 std::get<groupPos>(event), 84 std::get<handlerObjPos>(prop), 85 std::get<actionPos>(event) 86 })); 87 _matches.emplace_back( 88 bus, 89 std::get<signaturePos>(prop).c_str(), 90 std::bind(std::mem_fn(&Zone::handleEvent), 91 this, 92 std::placeholders::_1, 93 _signalEvents.back().get())); 94 } 95 // Run action function for initial event state 96 std::get<actionPos>(event)(*this, 97 std::get<groupPos>(event)); 98 } 99 } 100 } 101 102 103 void Zone::setSpeed(uint64_t speed) 104 { 105 for (auto& fan : _fans) 106 { 107 //TODO openbmc/openbmc#1626 Move to control algorithm function 108 if (speed < _floorSpeed) 109 { 110 speed = _floorSpeed; 111 } 112 fan->setSpeed(speed); 113 } 114 } 115 116 void Zone::setActiveAllow(const Group* group, bool isActiveAllow) 117 { 118 _active[group] = isActiveAllow; 119 if (!isActiveAllow) 120 { 121 _isActive = false; 122 } 123 else 124 { 125 // Check all entries are set to allow control active 126 auto actPred = [](auto const& entry) {return entry.second;}; 127 _isActive = std::all_of(_active.begin(), 128 _active.end(), 129 actPred); 130 } 131 } 132 133 void Zone::getProperty(sdbusplus::bus::bus& bus, 134 const std::string& path, 135 const std::string& iface, 136 const std::string& prop, 137 PropertyVariantType& value) 138 { 139 auto serv = phosphor::fan::util::getService(path, iface, bus); 140 auto hostCall = bus.new_method_call(serv.c_str(), 141 path.c_str(), 142 "org.freedesktop.DBus.Properties", 143 "Get"); 144 hostCall.append(iface); 145 hostCall.append(prop); 146 auto hostResponseMsg = bus.call(hostCall); 147 if (hostResponseMsg.is_method_error()) 148 { 149 log<level::ERR>("Error in host call response for retrieving property"); 150 elog<InternalFailure>(); 151 } 152 hostResponseMsg.read(value); 153 } 154 155 void Zone::handleEvent(sdbusplus::message::message& msg, 156 const EventData* eventData) 157 { 158 // Handle the callback 159 std::get<eventHandlerPos>(*eventData)(_bus, msg, *this); 160 // Perform the action 161 std::get<eventActionPos>(*eventData)(*this, 162 std::get<eventGroupPos>(*eventData)); 163 } 164 165 } 166 } 167 } 168