1e10416ecSMatt Spinler /** 2e10416ecSMatt Spinler * Copyright © 2017 IBM Corporation 3e10416ecSMatt Spinler * 4e10416ecSMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License"); 5e10416ecSMatt Spinler * you may not use this file except in compliance with the License. 6e10416ecSMatt Spinler * You may obtain a copy of the License at 7e10416ecSMatt Spinler * 8e10416ecSMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0 9e10416ecSMatt Spinler * 10e10416ecSMatt Spinler * Unless required by applicable law or agreed to in writing, software 11e10416ecSMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS, 12e10416ecSMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e10416ecSMatt Spinler * See the License for the specific language governing permissions and 14e10416ecSMatt Spinler * limitations under the License. 15e10416ecSMatt Spinler */ 1657352a31SMatt Spinler #include <algorithm> 17ee7f6428SMatt Spinler #include <phosphor-logging/log.hpp> 18*618027abSDinesh Chinari #include <phosphor-logging/elog.hpp> 19*618027abSDinesh Chinari #include <phosphor-logging/elog-errors.hpp> 20*618027abSDinesh Chinari #include <xyz/openbmc_project/Common/error.hpp> 21ee7f6428SMatt Spinler #include <unistd.h> 22e10416ecSMatt Spinler #include "manager.hpp" 23f96b01e2SGunnar Mills #include "utility.hpp" 24e10416ecSMatt Spinler 25e10416ecSMatt Spinler namespace phosphor 26e10416ecSMatt Spinler { 27e10416ecSMatt Spinler namespace fan 28e10416ecSMatt Spinler { 29e10416ecSMatt Spinler namespace control 30e10416ecSMatt Spinler { 31e10416ecSMatt Spinler 32ee7f6428SMatt Spinler using namespace phosphor::logging; 33ee7f6428SMatt Spinler 34ee7f6428SMatt Spinler constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 35ee7f6428SMatt Spinler constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 36ee7f6428SMatt Spinler constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 37ee7f6428SMatt Spinler constexpr auto FAN_CONTROL_READY_TARGET = "obmc-fan-control-ready@0.target"; 38ee7f6428SMatt Spinler 39f96b01e2SGunnar Mills constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; 40f96b01e2SGunnar Mills constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 41f96b01e2SGunnar Mills constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 42f96b01e2SGunnar Mills constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; 43f96b01e2SGunnar Mills 44f96b01e2SGunnar Mills 45f96b01e2SGunnar Mills /** 46f96b01e2SGunnar Mills * Get the current value of the D-Bus property under the specified path 47f96b01e2SGunnar Mills * and interface. 48f96b01e2SGunnar Mills * 49f96b01e2SGunnar Mills * @param[in] bus - The D-Bus bus object 50f96b01e2SGunnar Mills * @param[in] path - The D-Bus path 51f96b01e2SGunnar Mills * @param[in] interface - The D-Bus interface 52f96b01e2SGunnar Mills * @param[in] propertyName - The D-Bus property 53f96b01e2SGunnar Mills * @param[out] value - The D-Bus property's value 54f96b01e2SGunnar Mills */ 55f96b01e2SGunnar Mills template <typename T> 56f96b01e2SGunnar Mills void getProperty(sdbusplus::bus::bus& bus, 57f96b01e2SGunnar Mills const std::string& path, 58f96b01e2SGunnar Mills const std::string& interface, 59f96b01e2SGunnar Mills const std::string& propertyName, 60f96b01e2SGunnar Mills T& value) 61f96b01e2SGunnar Mills { 62f96b01e2SGunnar Mills sdbusplus::message::variant<T> property; 63f96b01e2SGunnar Mills std::string service = phosphor::fan::util::getService(path, interface, bus); 64f96b01e2SGunnar Mills 65f96b01e2SGunnar Mills auto method = bus.new_method_call(service.c_str(), 66f96b01e2SGunnar Mills path.c_str(), 67f96b01e2SGunnar Mills PROPERTY_INTERFACE, 68f96b01e2SGunnar Mills "Get"); 69f96b01e2SGunnar Mills 70f96b01e2SGunnar Mills method.append(interface, propertyName); 71f96b01e2SGunnar Mills auto reply = bus.call(method); 72f96b01e2SGunnar Mills 73f96b01e2SGunnar Mills if (reply.is_method_error()) 74f96b01e2SGunnar Mills { 75*618027abSDinesh Chinari log<level::ERR>("Error in call response for retrieving property"); 76*618027abSDinesh Chinari elog<InternalFailure>(); 77f96b01e2SGunnar Mills } 78f96b01e2SGunnar Mills reply.read(property); 79f96b01e2SGunnar Mills value = sdbusplus::message::variant_ns::get<T>(property); 80f96b01e2SGunnar Mills } 81f96b01e2SGunnar Mills 82f96b01e2SGunnar Mills 83f96b01e2SGunnar Mills /** 84f96b01e2SGunnar Mills * Check if a condition is true. Conditions are used to determine 85f96b01e2SGunnar Mills * which fan zone to use. 86f96b01e2SGunnar Mills * 87f96b01e2SGunnar Mills * @param[in] bus - The D-Bus bus object 88f96b01e2SGunnar Mills * @param[in] condition - The condition to check if true 89f96b01e2SGunnar Mills * @return result - True if the condition is true 90f96b01e2SGunnar Mills */ 91f96b01e2SGunnar Mills bool checkCondition(sdbusplus::bus::bus& bus, const auto& c) 92f96b01e2SGunnar Mills { 93f96b01e2SGunnar Mills auto& type = std::get<conditionTypePos>(c); 94f96b01e2SGunnar Mills auto& properties = std::get<conditionPropertyListPos>(c); 95f96b01e2SGunnar Mills 96f96b01e2SGunnar Mills for (auto& p : properties) 97f96b01e2SGunnar Mills { 98f96b01e2SGunnar Mills bool value = std::get<propertyValuePos>(p); 99f96b01e2SGunnar Mills bool propertyValue; 100f96b01e2SGunnar Mills 101f96b01e2SGunnar Mills // TODO openbmc/openbmc#1769: Support more types than just getProperty. 102f96b01e2SGunnar Mills if (type.compare("getProperty") == 0) 103f96b01e2SGunnar Mills { 104f96b01e2SGunnar Mills getProperty(bus, 105f96b01e2SGunnar Mills std::get<propertyPathPos>(p), 106f96b01e2SGunnar Mills std::get<propertyInterfacePos>(p), 107f96b01e2SGunnar Mills std::get<propertyNamePos>(p), 108f96b01e2SGunnar Mills propertyValue); 109f96b01e2SGunnar Mills 110f96b01e2SGunnar Mills if (value != propertyValue) 111f96b01e2SGunnar Mills { 112f96b01e2SGunnar Mills return false; 113f96b01e2SGunnar Mills } 114f96b01e2SGunnar Mills } 115f96b01e2SGunnar Mills } 116f96b01e2SGunnar Mills return true; 117f96b01e2SGunnar Mills } 118f96b01e2SGunnar Mills 119f96b01e2SGunnar Mills 120ee7f6428SMatt Spinler //Note: Future code will check 'mode' before starting control algorithm 121ee7f6428SMatt Spinler Manager::Manager(sdbusplus::bus::bus& bus, 122ee7f6428SMatt Spinler Mode mode) : 123e10416ecSMatt Spinler _bus(bus) 124e10416ecSMatt Spinler { 12557352a31SMatt Spinler //Create the appropriate Zone objects based on the 12657352a31SMatt Spinler //actual system configuration. 12757352a31SMatt Spinler 12857352a31SMatt Spinler //Find the 1 ZoneGroup that meets all of its conditions 12957352a31SMatt Spinler for (auto& group : _zoneLayouts) 13057352a31SMatt Spinler { 13157352a31SMatt Spinler auto& conditions = std::get<conditionListPos>(group); 13257352a31SMatt Spinler 13357352a31SMatt Spinler if (std::all_of(conditions.begin(), conditions.end(), 134f96b01e2SGunnar Mills [&bus](const auto& condition) 13557352a31SMatt Spinler { 136f96b01e2SGunnar Mills return checkCondition(bus, condition); 13757352a31SMatt Spinler })) 13857352a31SMatt Spinler { 13957352a31SMatt Spinler //Create a Zone object for each zone in this group 14057352a31SMatt Spinler auto& zones = std::get<zoneListPos>(group); 14157352a31SMatt Spinler 14257352a31SMatt Spinler for (auto& z : zones) 14357352a31SMatt Spinler { 14457352a31SMatt Spinler _zones.emplace(std::get<zoneNumPos>(z), 14514184131SMatthew Barth std::make_unique<Zone>(mode, _bus, z)); 14657352a31SMatt Spinler } 14757352a31SMatt Spinler 14857352a31SMatt Spinler break; 14957352a31SMatt Spinler } 15057352a31SMatt Spinler } 15157352a31SMatt Spinler 152ee7f6428SMatt Spinler } 153ee7f6428SMatt Spinler 154ee7f6428SMatt Spinler 155ee7f6428SMatt Spinler void Manager::doInit() 156ee7f6428SMatt Spinler { 15757352a31SMatt Spinler for (auto& z : _zones) 15857352a31SMatt Spinler { 15957352a31SMatt Spinler z.second->setFullSpeed(); 16057352a31SMatt Spinler } 161ee7f6428SMatt Spinler 162ee7f6428SMatt Spinler auto delay = _powerOnDelay; 163ee7f6428SMatt Spinler while (delay > 0) 164ee7f6428SMatt Spinler { 165ee7f6428SMatt Spinler delay = sleep(delay); 166e10416ecSMatt Spinler } 167e10416ecSMatt Spinler 168ee7f6428SMatt Spinler startFanControlReadyTarget(); 169ee7f6428SMatt Spinler } 170ee7f6428SMatt Spinler 171ee7f6428SMatt Spinler 172ee7f6428SMatt Spinler void Manager::startFanControlReadyTarget() 173ee7f6428SMatt Spinler { 174ee7f6428SMatt Spinler auto method = _bus.new_method_call(SYSTEMD_SERVICE, 175ee7f6428SMatt Spinler SYSTEMD_OBJ_PATH, 176ee7f6428SMatt Spinler SYSTEMD_INTERFACE, 177ee7f6428SMatt Spinler "StartUnit"); 178ee7f6428SMatt Spinler 179ee7f6428SMatt Spinler method.append(FAN_CONTROL_READY_TARGET); 180ee7f6428SMatt Spinler method.append("replace"); 181ee7f6428SMatt Spinler 182ee7f6428SMatt Spinler auto response = _bus.call(method); 183ee7f6428SMatt Spinler if (response.is_method_error()) 184ee7f6428SMatt Spinler { 185ee7f6428SMatt Spinler log<level::ERR>("Failed to start fan control ready target"); 186*618027abSDinesh Chinari elog<InternalFailure>(); 187ee7f6428SMatt Spinler } 188ee7f6428SMatt Spinler } 189e10416ecSMatt Spinler 190f96b01e2SGunnar Mills } // namespace control 191f96b01e2SGunnar Mills } // namespace fan 192f96b01e2SGunnar Mills } // namespace phosphor 193