From ee7f64283f2fe728fd4bd67280bf59daaec9df54 Mon Sep 17 00:00:00 2001 From: Matt Spinler Date: Tue, 9 May 2017 11:03:14 -0500 Subject: Add modes to phosphor-fan-control phosphor-fan-control can behave differently based on its command line arguments --init: Set fans to full speed, delay for a configurable amount of time to allow fans to ramp up, start the fan control ready target, and then exit. --control: Start the control algorithm. Never exits. Will be started as part of the fan control ready target. Change-Id: I453daf8cc05a5c85a19c098e1cca64cac2ad9520 Signed-off-by: Matt Spinler --- control/Makefile.am | 1 + control/example/zones.yaml | 56 ++++++++++++++++++++++++++------------------ control/gen-fan-zone-defs.py | 15 +++++++++--- control/main.cpp | 35 ++++++++++++++++++++++++++- control/manager.cpp | 46 ++++++++++++++++++++++++++++++++++-- control/manager.hpp | 34 ++++++++++++++++++++++++++- 6 files changed, 157 insertions(+), 30 deletions(-) (limited to 'control') diff --git a/control/Makefile.am b/control/Makefile.am index 04d7d96..7599977 100644 --- a/control/Makefile.am +++ b/control/Makefile.am @@ -5,6 +5,7 @@ sbin_PROGRAMS = \ phosphor-fan-control phosphor_fan_control_SOURCES = \ + argument.cpp \ fan.cpp \ main.cpp \ manager.cpp \ diff --git a/control/example/zones.yaml b/control/example/zones.yaml index 5f3b549..00929cd 100644 --- a/control/example/zones.yaml +++ b/control/example/zones.yaml @@ -17,33 +17,43 @@ #case, the fan yaml would have a cooling_profile of 'air' to match #the zone cooling profile. -#- zone_conditions: -# - name: [Name of a condition, if any. Valid names are TBD] +#manager_configuration: +# power_on_delay: [Number of seconds that phosphor-fan-control --init +# should delay after setting fans to full speed on +# a power on.] # -# zones: -# - zone: [zone number] -# cooling_profiles: -# - [cooling profile] -# initial_speed: [Speed to set the zone to when app starts] +#zone_configuration: +# - zone_conditions: +# - name: [Name of a condition, if any. Valid names are TBD.] +# +# zones: +# - zone: [zone number] +# cooling_profiles: +# - [cooling profile] +# initial_speed: [Speed to set the zone to when app starts.] #Example: -#- zone_conditions: -# - name: air_cooled_chassis +#manager_configuration: +# power_on_delay: 20 +# +#zone_configuration: +# - zone_conditions: +# - name: air_cooled_chassis # -# zones: -# - zone: 0 -# cooling_profiles: -# - air -# - all -# initial_speed: 10500 +# zones: +# - zone: 0 +# cooling_profiles: +# - air +# - all +# initial_speed: 10500 # -#- zone_conditions: -# - name: water_and_air_cooled_chassis +# - zone_conditions: +# - name: water_and_air_cooled_chassis # -# zones: -# - zone: 0 -# cooling_profiles: -# - water -# - all -# initial_speed: 4000 +# zones: +# - zone: 0 +# cooling_profiles: +# - water +# - all +# initial_speed: 4000 diff --git a/control/gen-fan-zone-defs.py b/control/gen-fan-zone-defs.py index 3457d41..04f206f 100755 --- a/control/gen-fan-zone-defs.py +++ b/control/gen-fan-zone-defs.py @@ -11,12 +11,14 @@ import yaml from argparse import ArgumentParser from mako.template import Template -#Note: Condition is a TODO +#Note: Condition is a TODO (openbmc/openbmc#1500) tmpl = '''/* This is a generated file. */ #include "manager.hpp" using namespace phosphor::fan::control; +const unsigned int Manager::_powerOnDelay{${mgr_data['power_on_delay']}}; + const std::vector Manager::_zoneLayouts { %for zone_group in zones: @@ -151,8 +153,15 @@ if __name__ == '__main__': with open(args.fan_yaml, 'r') as fan_input: fan_data = yaml.safe_load(fan_input) or {} - zone_data = buildZoneData(zone_data, fan_data) + zone_config = buildZoneData(zone_data.get('zone_configuration', {}), + fan_data) + + manager_config = zone_data.get('manager_configuration', {}) + + if manager_config.get('power_on_delay') is None: + manager_config['power_on_delay'] = 0 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp") with open(output_file, 'w') as output: - output.write(Template(tmpl).render(zones=zone_data)) + output.write(Template(tmpl).render(zones=zone_config, + mgr_data=manager_config)) diff --git a/control/main.cpp b/control/main.cpp index 08a7dc9..be5b59e 100644 --- a/control/main.cpp +++ b/control/main.cpp @@ -14,13 +14,46 @@ * limitations under the License. */ #include +#include "argument.hpp" #include "manager.hpp" +using namespace phosphor::fan::control; + int main(int argc, char* argv[]) { auto bus = sdbusplus::bus::new_default(); + phosphor::fan::util::ArgumentParser args(argc, argv); + + if (argc != 2) + { + args.usage(argv); + exit(-1); + } - phosphor::fan::control::Manager manager(bus); + Manager::Mode mode; + + if (args["init"] == "true") + { + mode = Manager::Mode::init; + } + else if (args["control"] == "true") + { + mode = Manager::Mode::control; + } + else + { + args.usage(argv); + exit(-1); + } + + Manager manager(bus, mode); + + //Init mode will just set fans to max and delay + if (mode == Manager::Mode::init) + { + manager.doInit(); + return 0; + } while (true) { diff --git a/control/manager.cpp b/control/manager.cpp index 9359a6b..6c773a7 100644 --- a/control/manager.cpp +++ b/control/manager.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ #include +#include +#include #include "manager.hpp" namespace phosphor @@ -23,7 +25,16 @@ namespace fan namespace control { -Manager::Manager(sdbusplus::bus::bus& bus) : +using namespace phosphor::logging; + +constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; +constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; +constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; +constexpr auto FAN_CONTROL_READY_TARGET = "obmc-fan-control-ready@0.target"; + +//Note: Future code will check 'mode' before starting control algorithm +Manager::Manager(sdbusplus::bus::bus& bus, + Mode mode) : _bus(bus) { //Create the appropriate Zone objects based on the @@ -55,14 +66,45 @@ Manager::Manager(sdbusplus::bus::bus& bus) : } } - //Set to full since we don't know state of system yet. +} + + +void Manager::doInit() +{ for (auto& z: _zones) { z.second->setFullSpeed(); } + + auto delay = _powerOnDelay; + while (delay > 0) + { + delay = sleep(delay); + } + + startFanControlReadyTarget(); } +void Manager::startFanControlReadyTarget() +{ + auto method = _bus.new_method_call(SYSTEMD_SERVICE, + SYSTEMD_OBJ_PATH, + SYSTEMD_INTERFACE, + "StartUnit"); + + method.append(FAN_CONTROL_READY_TARGET); + method.append("replace"); + + auto response = _bus.call(method); + if (response.is_method_error()) + { + //TODO openbmc/openbmc#1555 create an elog + log("Failed to start fan control ready target"); + throw std::runtime_error("Failed to start fan control ready target"); + } +} + } } } diff --git a/control/manager.hpp b/control/manager.hpp index 7f8baa3..675dfb8 100644 --- a/control/manager.hpp +++ b/control/manager.hpp @@ -23,6 +23,17 @@ class Manager { public: + /** + * The mode the manager will run in: + * - init - only do the initialization steps + * - control - run normal control algorithms + */ + enum class Mode + { + init, + control + }; + Manager() = delete; Manager(const Manager&) = delete; Manager(Manager&&) = default; @@ -36,11 +47,25 @@ class Manager * _zoneLayouts data. * * @param[in] bus - The dbus object + * @param[in] mode - The control mode + */ + Manager(sdbusplus::bus::bus& bus, + Mode mode); + + /** + * Does the fan control inititialization, which is + * setting fans to full, delaying so they + * can get there, and starting a target. */ - Manager(sdbusplus::bus::bus& bus); + void doInit(); private: + /** + * Starts the obmc-fan-control-ready dbus target + */ + void startFanControlReadyTarget(); + /** * The dbus object */ @@ -56,6 +81,13 @@ class Manager * This is generated data. */ static const std::vector _zoneLayouts; + + /** + * The number of seconds to delay after + * fans get set to high speed on a power on + * to give them a chance to get there. + */ + static const unsigned int _powerOnDelay; }; -- cgit v1.2.1