blob: 1bffe24c06c57d5b426d020fafa8a3ea152003d3 [file] [log] [blame]
Matthew Barth29e9e382020-01-23 13:40:49 -06001/**
2 * Copyright © 2020 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
17#include "manager.hpp"
18
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050019#include "chassis.hpp"
20#include "config_file_parser.hpp"
21#include "exception_utils.hpp"
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050022#include "rule.hpp"
Matthew Barthbbc7c582020-02-03 15:55:15 -060023#include "utility.hpp"
24
Matthew Barth29e9e382020-01-23 13:40:49 -060025#include <sdbusplus/bus.hpp>
26
Matthew Barthf2bcf1f2020-01-29 14:42:47 -060027#include <chrono>
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050028#include <exception>
29#include <stdexcept>
30#include <tuple>
31#include <utility>
Matthew Barth250d0a92020-02-28 13:04:24 -060032#include <variant>
Matthew Barthf2bcf1f2020-01-29 14:42:47 -060033
Shawn McCarney84807b92020-04-30 18:40:03 -050034namespace phosphor::power::regulators
Matthew Barth29e9e382020-01-23 13:40:49 -060035{
36
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050037namespace fs = std::filesystem;
38
39/**
40 * Standard configuration file directory. This directory is part of the
41 * firmware install image. It contains the standard version of the config file.
42 */
43const fs::path standardConfigFileDir{"/usr/share/phosphor-regulators"};
44
45/**
46 * Test configuration file directory. This directory can contain a test version
47 * of the config file. The test version will override the standard version.
48 */
49const fs::path testConfigFileDir{"/etc/phosphor-regulators"};
50
Matthew Barthf2bcf1f2020-01-29 14:42:47 -060051Manager::Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event) :
Shawn McCarneyb464c8b2020-07-16 17:51:38 -050052 ManagerObject{bus, objPath, true}, bus{bus}, eventLoop{event}, services{bus}
Matthew Barth29e9e382020-01-23 13:40:49 -060053{
Shawn McCarney84807b92020-04-30 18:40:03 -050054 /* Temporarily comment out until D-Bus interface is defined and available.
55 // Subscribe to interfacesAdded signal for filename property
56 std::unique_ptr<sdbusplus::server::match::match> matchPtr =
57 std::make_unique<sdbusplus::server::match::match>(
58 bus,
59 sdbusplus::bus::match::rules::interfacesAdded(sysDbusObj).c_str(),
60 std::bind(std::mem_fn(&Manager::signalHandler), this,
61 std::placeholders::_1));
62 signals.emplace_back(std::move(matchPtr));
Matthew Barth250d0a92020-02-28 13:04:24 -060063
Shawn McCarney84807b92020-04-30 18:40:03 -050064 // Attempt to get the filename property from dbus
65 setFileName(getFileNameDbus());
66 */
67
68 // Temporarily hard-code JSON config file name to first system that will use
69 // this application. Remove this when D-Bus interface is available.
70 fileName = "ibm_rainier.json";
Matthew Barthbbc7c582020-02-03 15:55:15 -060071
Matthew Barthbbc7c582020-02-03 15:55:15 -060072 if (!fileName.empty())
73 {
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -050074 loadConfigFile();
Matthew Barthbbc7c582020-02-03 15:55:15 -060075 }
Matthew Barth29e9e382020-01-23 13:40:49 -060076
77 // Obtain dbus service name
78 bus.request_name(busName);
79}
80
81void Manager::configure()
82{
Shawn McCarney6345c6c2020-05-04 10:35:05 -050083 // Verify System object exists; this means config file has been loaded
84 if (system)
85 {
86 // Configure the regulator devices in the system
Bob King23243f82020-07-29 10:38:57 +080087 system->configure(services);
Shawn McCarney6345c6c2020-05-04 10:35:05 -050088 }
89 else
90 {
Shawn McCarneyb464c8b2020-07-16 17:51:38 -050091 services.getJournal().logError("Unable to configure regulator devices: "
92 "Configuration file not loaded");
Shawn McCarney6345c6c2020-05-04 10:35:05 -050093 // TODO: Log error
94 }
95
Matthew Barth29e9e382020-01-23 13:40:49 -060096 // TODO Configuration errors that should halt poweron,
97 // throw InternalFailure exception (or similar) to
98 // fail the call(busctl) to this method
99}
100
Shawn McCarney5b19ea52020-06-02 18:52:56 -0500101void Manager::monitor(bool enable)
Matthew Barth29e9e382020-01-23 13:40:49 -0600102{
103 if (enable)
104 {
Shawn McCarney5b19ea52020-06-02 18:52:56 -0500105 /* Temporarily comment out until monitoring is supported.
106 Timer timer(eventLoop, std::bind(&Manager::timerExpired, this));
107 // Set timer as a repeating 1sec timer
108 timer.restart(std::chrono::milliseconds(1000));
109 timers.emplace_back(std::move(timer));
110 */
Matthew Barth29e9e382020-01-23 13:40:49 -0600111 }
112 else
113 {
Shawn McCarney5b19ea52020-06-02 18:52:56 -0500114 /* Temporarily comment out until monitoring is supported.
115 // Delete all timers to disable monitoring
116 timers.clear();
117 */
118
119 // Verify System object exists; this means config file has been loaded
120 if (system)
121 {
122 // Close the regulator devices in the system. Monitoring is
123 // normally disabled because the system is being powered off. The
124 // devices should be closed in case hardware is removed or replaced
125 // while the system is at standby.
Bob Kingd692d6d2020-09-14 13:42:57 +0800126 system->closeDevices(services);
Shawn McCarney5b19ea52020-06-02 18:52:56 -0500127 }
Matthew Barth29e9e382020-01-23 13:40:49 -0600128 }
129}
130
Matthew Barthf2bcf1f2020-01-29 14:42:47 -0600131void Manager::timerExpired()
132{
133 // TODO Analyze, refresh sensor status, and
134 // collect/update telemetry for each regulator
135}
136
Matthew Barth7cbc5532020-01-29 15:13:13 -0600137void Manager::sighupHandler(sdeventplus::source::Signal& /*sigSrc*/,
138 const struct signalfd_siginfo* /*sigInfo*/)
139{
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500140 if (!fileName.empty())
141 {
142 loadConfigFile();
143 }
Matthew Barth7cbc5532020-01-29 15:13:13 -0600144}
145
Matthew Barth250d0a92020-02-28 13:04:24 -0600146void Manager::signalHandler(sdbusplus::message::message& msg)
147{
148 if (msg)
149 {
150 sdbusplus::message::object_path op;
151 msg.read(op);
152 if (static_cast<const std::string&>(op) != sysDbusPath)
153 {
154 // Object path does not match the path
155 return;
156 }
157
158 // An interfacesAdded signal returns a dictionary of interface
159 // names to a dictionary of properties and their values
160 // https://dbus.freedesktop.org/doc/dbus-specification.html
161 std::map<std::string, std::map<std::string, std::variant<std::string>>>
162 intfProp;
163 msg.read(intfProp);
164 auto itIntf = intfProp.find(sysDbusIntf);
165 if (itIntf == intfProp.cend())
166 {
167 // Interface not found on the path
168 return;
169 }
170 auto itProp = itIntf->second.find(sysDbusProp);
171 if (itProp == itIntf->second.cend())
172 {
173 // Property not found on the interface
174 return;
175 }
176 // Set fileName and call parse json function
177 setFileName(std::get<std::string>(itProp->second));
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500178 if (!fileName.empty())
179 {
180 loadConfigFile();
181 }
Matthew Barth250d0a92020-02-28 13:04:24 -0600182 }
183}
184
Matthew Barthbbc7c582020-02-03 15:55:15 -0600185const std::string Manager::getFileNameDbus()
186{
187 std::string fileName = "";
188 using namespace phosphor::power::util;
189
190 try
191 {
192 // Do not log an error when service or property are not found
193 auto service = getService(sysDbusPath, sysDbusIntf, bus, false);
194 if (!service.empty())
195 {
196 getProperty(sysDbusIntf, sysDbusProp, sysDbusPath, service, bus,
197 fileName);
198 }
199 }
200 catch (const sdbusplus::exception::SdBusError&)
201 {
202 // File name property not available on dbus
203 fileName = "";
204 }
205
206 return fileName;
207}
208
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500209fs::path Manager::findConfigFile()
210{
211 // First look in the test directory
212 fs::path pathName{testConfigFileDir / fileName};
213 if (!fs::exists(pathName))
214 {
215 // Look in the standard directory
216 pathName = standardConfigFileDir / fileName;
217 if (!fs::exists(pathName))
218 {
219 throw std::runtime_error{"Configuration file does not exist: " +
220 pathName.string()};
221 }
222 }
223
224 return pathName;
225}
226
227void Manager::loadConfigFile()
228{
229 try
230 {
231 // Find the absolute path to the config file
232 fs::path pathName = findConfigFile();
233
234 // Log info message in journal; config file path is important
Shawn McCarneyb464c8b2020-07-16 17:51:38 -0500235 services.getJournal().logInfo("Loading configuration file " +
236 pathName.string());
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500237
238 // Parse the config file
239 std::vector<std::unique_ptr<Rule>> rules{};
240 std::vector<std::unique_ptr<Chassis>> chassis{};
241 std::tie(rules, chassis) = config_file_parser::parse(pathName);
242
243 // Store config file information in a new System object. The old System
244 // object, if any, is automatically deleted.
245 system = std::make_unique<System>(std::move(rules), std::move(chassis));
246 }
247 catch (const std::exception& e)
248 {
249 // Log error messages in journal
Shawn McCarneyb464c8b2020-07-16 17:51:38 -0500250 services.getJournal().logError(exception_utils::getMessages(e));
251 services.getJournal().logError("Unable to load configuration file");
Shawn McCarneye0c6a2d2020-05-01 11:37:08 -0500252
253 // TODO: Create error log entry
254 }
255}
256
Shawn McCarney84807b92020-04-30 18:40:03 -0500257} // namespace phosphor::power::regulators