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 "config.h" 17 18 #include "manager.hpp" 19 20 #include "dbus_paths.hpp" 21 #include "sdbusplus.hpp" 22 #include "utility.hpp" 23 24 #include <unistd.h> 25 26 #include <phosphor-logging/elog-errors.hpp> 27 #include <phosphor-logging/elog.hpp> 28 #include <phosphor-logging/log.hpp> 29 #include <sdbusplus/bus.hpp> 30 #include <xyz/openbmc_project/Common/error.hpp> 31 32 #include <algorithm> 33 #include <filesystem> 34 35 namespace phosphor 36 { 37 namespace fan 38 { 39 namespace control 40 { 41 42 using namespace phosphor::logging; 43 namespace fs = std::filesystem; 44 45 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 46 constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 47 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 48 constexpr auto FAN_CONTROL_READY_TARGET = "obmc-fan-control-ready@0.target"; 49 50 /** 51 * Check if a condition is true. Conditions are used to determine 52 * which fan zone to use. 53 * 54 * @param[in] bus - The D-Bus bus object 55 * @param[in] condition - The condition to check if true 56 * @return result - True if the condition is true 57 */ 58 bool checkCondition(sdbusplus::bus_t& bus, const Condition& c) 59 { 60 auto& type = std::get<conditionTypePos>(c); 61 auto& properties = std::get<conditionPropertyListPos>(c); 62 63 for (auto& p : properties) 64 { 65 auto value = std::get<propertyValuePos>(p); 66 67 // TODO openbmc/openbmc#1769: Support more types than just getProperty. 68 if (type.compare("getProperty") == 0) 69 { 70 auto propertyValue = util::SDBusPlus::getProperty<decltype(value)>( 71 bus, std::get<propertyPathPos>(p), 72 std::get<propertyInterfacePos>(p), 73 std::get<propertyNamePos>(p)); 74 75 if (value != propertyValue) 76 { 77 return false; 78 } 79 } 80 } 81 return true; 82 } 83 84 // Note: Future code will check 'mode' before starting control algorithm 85 Manager::Manager(sdbusplus::bus_t& bus, const sdeventplus::Event& event, 86 Mode mode) : 87 _bus(bus), 88 _objMgr(bus, CONTROL_OBJPATH) 89 { 90 // Create the appropriate Zone objects based on the 91 // actual system configuration. 92 93 // Find the 1 ZoneGroup that meets all of its conditions 94 for (auto& group : _zoneLayouts) 95 { 96 auto& conditions = std::get<conditionListPos>(group); 97 98 if (std::all_of(conditions.begin(), conditions.end(), 99 [&bus](const auto& condition) { 100 return checkCondition(bus, condition); 101 })) 102 { 103 // Create a Zone object for each zone in this group 104 auto& zones = std::get<zoneListPos>(group); 105 106 for (auto& z : zones) 107 { 108 fs::path path{CONTROL_OBJPATH}; 109 path /= std::to_string(std::get<zoneNumPos>(z)); 110 _zones.emplace(std::get<zoneNumPos>(z), 111 std::make_unique<Zone>(mode, _bus, path.string(), 112 event, z)); 113 } 114 115 break; 116 } 117 } 118 119 if (mode == Mode::control) 120 { 121 bus.request_name(CONTROL_BUSNAME); 122 } 123 } 124 125 void Manager::doInit(const sdeventplus::Event& /*event*/) 126 { 127 for (auto& z : _zones) 128 { 129 z.second->setFullSpeed(); 130 } 131 auto delay = _powerOnDelay; 132 while (delay > 0) 133 { 134 delay = sleep(delay); 135 } 136 137 util::SDBusPlus::callMethod(_bus, SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, 138 SYSTEMD_INTERFACE, "StartUnit", 139 FAN_CONTROL_READY_TARGET, "replace"); 140 } 141 142 } // namespace control 143 } // namespace fan 144 } // namespace phosphor 145