blob: a356d5cdd8182cd6b629d92a853fb50ee925f55a [file] [log] [blame]
James Feist139cb572018-09-10 15:26:18 -07001/*
2// Copyright (c) 2018 Intel 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 <fcntl.h>
18#include <linux/peci-ioctl.h>
19
20#include <CPUSensor.hpp>
21#include <Utils.hpp>
22#include <VariantVisitors.hpp>
23#include <boost/algorithm/string/predicate.hpp>
24#include <boost/algorithm/string/replace.hpp>
25#include <boost/container/flat_set.hpp>
26#include <boost/date_time/posix_time/posix_time.hpp>
27#include <boost/process/child.hpp>
28#include <experimental/filesystem>
29#include <fstream>
30#include <regex>
31#include <sdbusplus/asio/connection.hpp>
32#include <sdbusplus/asio/object_server.hpp>
33
34static constexpr bool DEBUG = false;
35
36enum State
37{
38 OFF, // host powered down
39 ON, // host powered on
40 READY // host powered on and mem test passed - fully ready
41};
42
43struct CPUConfig
44{
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -070045 CPUConfig(const uint64_t& bus, const uint64_t& addr,
46 const std::string& name, const State& state) :
47 bus(bus),
48 addr(addr), name(name), state(state)
James Feist139cb572018-09-10 15:26:18 -070049 {
50 }
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -070051 int bus;
James Feist139cb572018-09-10 15:26:18 -070052 int addr;
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -070053 std::string name;
James Feist139cb572018-09-10 15:26:18 -070054 State state;
55
56 bool operator<(const CPUConfig& rhs) const
57 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -070058 return (name < rhs.name);
James Feist139cb572018-09-10 15:26:18 -070059 }
60};
61
Jae Hyun Yoo0003f462018-10-26 10:09:01 -070062static constexpr const char* peciDev = "/dev/peci-";
Jae Hyun Yoof78ec412018-10-25 10:42:39 -070063static constexpr const unsigned int rankNumMax = 8;
James Feist139cb572018-09-10 15:26:18 -070064
65namespace fs = std::experimental::filesystem;
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070066namespace variant_ns = sdbusplus::message::variant_ns;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -070067static constexpr const char* configPrefix =
James Feist139cb572018-09-10 15:26:18 -070068 "xyz.openbmc_project.Configuration.";
Jae Hyun Yoof78ec412018-10-25 10:42:39 -070069static constexpr std::array<const char*, 3> sensorTypes = {
James Feist139cb572018-09-10 15:26:18 -070070 "SkylakeCPU", "BroadwellCPU", "HaswellCPU"};
71
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -070072void detectCpuAsync(
73 boost::asio::deadline_timer& pingTimer,
74 boost::asio::deadline_timer& creationTimer, boost::asio::io_service& io,
75 sdbusplus::asio::object_server& objectServer,
76 boost::container::flat_map<std::string, std::unique_ptr<CPUSensor>>&
77 sensors,
78 boost::container::flat_set<CPUConfig>& configs,
79 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection);
80
Yoo, Jae Hyun60e14d32018-10-10 11:03:11 -070081bool createSensors(
James Feist139cb572018-09-10 15:26:18 -070082 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
83 boost::container::flat_map<std::string, std::unique_ptr<CPUSensor>>&
84 sensors,
85 boost::container::flat_set<CPUConfig>& configs,
86 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
87{
88 bool available = false;
89 for (CPUConfig cpu : configs)
90 {
91 if (cpu.state != State::OFF)
92 {
93 available = true;
94 break;
95 }
96 }
97 if (!available)
98 {
Yoo, Jae Hyun60e14d32018-10-10 11:03:11 -070099 return false;
James Feist139cb572018-09-10 15:26:18 -0700100 }
101
102 // use new data the first time, then refresh
103 ManagedObjectType sensorConfigurations;
104 bool useCache = false;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700105 for (const char* type : sensorTypes)
James Feist139cb572018-09-10 15:26:18 -0700106 {
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700107 if (!getSensorConfiguration(configPrefix + std::string(type),
James Feist139cb572018-09-10 15:26:18 -0700108 dbusConnection, sensorConfigurations,
109 useCache))
110 {
Yoo, Jae Hyun60e14d32018-10-10 11:03:11 -0700111 return false;
James Feist139cb572018-09-10 15:26:18 -0700112 }
113 useCache = true;
114 }
115
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700116 std::vector<fs::path> hwmonNamePaths;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700117 if (!findFiles(fs::path(R"(/sys/bus/peci/devices)"),
118 R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/name$)",
119 hwmonNamePaths, 1))
James Feist139cb572018-09-10 15:26:18 -0700120 {
121 std::cerr << "No CPU sensors in system\n";
Yoo, Jae Hyun60e14d32018-10-10 11:03:11 -0700122 return true;
James Feist139cb572018-09-10 15:26:18 -0700123 }
124
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700125 boost::container::flat_set<std::string> scannedDirectories;
126 boost::container::flat_set<std::string> createdSensors;
127
128 for (fs::path& hwmonNamePath : hwmonNamePaths)
James Feist139cb572018-09-10 15:26:18 -0700129 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700130 const std::string& pathStr = hwmonNamePath.string();
131 auto hwmonDirectory = hwmonNamePath.parent_path();
132
133 auto ret = scannedDirectories.insert(hwmonDirectory.string());
134 if (!ret.second)
James Feist139cb572018-09-10 15:26:18 -0700135 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700136 continue; // already searched this path
137 }
138
139 fs::path::iterator it = hwmonNamePath.begin();
140 std::advance(it, 6); // pick the 6th part for a PECI client device name
141 std::string deviceName = *it;
142 auto findHyphen = deviceName.find("-");
143 if (findHyphen == std::string::npos)
144 {
145 std::cerr << "found bad device " << deviceName << "\n";
James Feist139cb572018-09-10 15:26:18 -0700146 continue;
147 }
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700148 std::string busStr = deviceName.substr(0, findHyphen);
149 std::string addrStr = deviceName.substr(findHyphen + 1);
150
151 size_t bus = 0;
152 size_t addr = 0;
153 try
154 {
155 bus = std::stoi(busStr);
156 addr = std::stoi(addrStr, 0, 16);
157 }
158 catch (std::invalid_argument)
159 {
160 continue;
161 }
162
163 std::ifstream nameFile(hwmonNamePath);
164 if (!nameFile.good())
165 {
166 std::cerr << "Failure reading " << hwmonNamePath << "\n";
167 continue;
168 }
169 std::string hwmonName;
170 std::getline(nameFile, hwmonName);
James Feist139cb572018-09-10 15:26:18 -0700171 nameFile.close();
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700172 if (!hwmonName.size())
James Feist139cb572018-09-10 15:26:18 -0700173 {
174 // shouldn't have an empty name file
175 continue;
176 }
James Feist139cb572018-09-10 15:26:18 -0700177 if (DEBUG)
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700178 {
179 std::cout << "Checking: " << hwmonNamePath << ": " << hwmonName
180 << "\n";
181 }
James Feist139cb572018-09-10 15:26:18 -0700182
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700183 std::string sensorType;
James Feist139cb572018-09-10 15:26:18 -0700184 const SensorData* sensorData = nullptr;
185 const std::string* interfacePath = nullptr;
James Feist139cb572018-09-10 15:26:18 -0700186 const std::pair<std::string, boost::container::flat_map<
187 std::string, BasicVariantType>>*
188 baseConfiguration = nullptr;
James Feist139cb572018-09-10 15:26:18 -0700189
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700190 for (const std::pair<sdbusplus::message::object_path, SensorData>&
191 sensor : sensorConfigurations)
James Feist139cb572018-09-10 15:26:18 -0700192 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700193 sensorData = &(sensor.second);
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700194 for (const char* type : sensorTypes)
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700195 {
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700196 sensorType = configPrefix + std::string(type);
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700197 auto sensorBase = sensorData->find(sensorType);
198 if (sensorBase != sensorData->end())
199 {
200 baseConfiguration = &(*sensorBase);
201 break;
202 }
203 }
204 if (baseConfiguration == nullptr)
205 {
206 std::cerr << "error finding base configuration for" << hwmonName
207 << "\n";
208 continue;
209 }
210 auto configurationBus = baseConfiguration->second.find("Bus");
211 auto configurationAddress =
212 baseConfiguration->second.find("Address");
213
214 if (configurationBus == baseConfiguration->second.end() ||
215 configurationAddress == baseConfiguration->second.end())
216 {
217 std::cerr << "error finding bus or address in configuration";
218 continue;
219 }
220
221 if (sdbusplus::message::variant_ns::get<uint64_t>(
222 configurationBus->second) != bus ||
223 sdbusplus::message::variant_ns::get<uint64_t>(
224 configurationAddress->second) != addr)
225 {
226 continue;
227 }
228
229 interfacePath = &(sensor.first.str);
230 break;
231 }
232 if (interfacePath == nullptr)
233 {
234 std::cerr << "failed to find match for " << hwmonName << "\n";
James Feist139cb572018-09-10 15:26:18 -0700235 continue;
236 }
237
238 auto findCpuId = baseConfiguration->second.find("CpuID");
239 if (findCpuId == baseConfiguration->second.end())
240 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700241 std::cerr << "could not determine CPU ID for " << hwmonName << "\n";
James Feist139cb572018-09-10 15:26:18 -0700242 continue;
243 }
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700244 int cpuId =
245 variant_ns::visit(VariantToUnsignedIntVisitor(), findCpuId->second);
James Feist139cb572018-09-10 15:26:18 -0700246
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700247 auto directory = hwmonNamePath.parent_path();
James Feist139cb572018-09-10 15:26:18 -0700248 std::vector<fs::path> inputPaths;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700249 if (!findFiles(fs::path(directory), R"(temp\d+_input$)", inputPaths, 0))
James Feist139cb572018-09-10 15:26:18 -0700250 {
251 std::cerr << "No temperature sensors in system\n";
252 continue;
253 }
254
255 // iterate through all found temp sensors
256 for (auto& inputPath : inputPaths)
257 {
258 auto inputPathStr = inputPath.string();
259 auto labelPath =
260 boost::replace_all_copy(inputPathStr, "input", "label");
261 std::ifstream labelFile(labelPath);
262 if (!labelFile.good())
263 {
264 std::cerr << "Failure reading " << labelPath << "\n";
265 continue;
266 }
267 std::string label;
268 std::getline(labelFile, label);
269 labelFile.close();
270 std::string sensorName = label + " CPU" + std::to_string(cpuId);
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700271
272 auto findSensor = sensors.find(sensorName);
273 if (findSensor != sensors.end())
274 {
275 if (DEBUG)
276 {
277 std::cout << "Skipped: " << inputPath << ": " << sensorName
278 << " is already created\n";
279 }
280 continue;
281 }
282
James Feist139cb572018-09-10 15:26:18 -0700283 std::vector<thresholds::Threshold> sensorThresholds;
284 std::string labelHead = label.substr(0, label.find(" "));
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700285 parseThresholdsFromConfig(*sensorData, sensorThresholds,
Yoo, Jae Hyunac18e142018-10-09 16:38:58 -0700286 &labelHead);
James Feist139cb572018-09-10 15:26:18 -0700287 if (!sensorThresholds.size())
288 {
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700289 if (!parseThresholdsFromAttr(sensorThresholds, inputPathStr,
290 CPUSensor::sensorScaleFactor))
James Feist139cb572018-09-10 15:26:18 -0700291 {
Yoo, Jae Hyunac18e142018-10-09 16:38:58 -0700292 std::cerr << "error populating thresholds for "
293 << sensorName << "\n";
James Feist139cb572018-09-10 15:26:18 -0700294 }
295 }
296 sensors[sensorName] = std::make_unique<CPUSensor>(
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700297 inputPathStr, sensorType, objectServer, dbusConnection, io,
298 sensorName, std::move(sensorThresholds), *interfacePath);
299 createdSensors.insert(sensorName);
James Feist139cb572018-09-10 15:26:18 -0700300 if (DEBUG)
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700301 {
James Feist139cb572018-09-10 15:26:18 -0700302 std::cout << "Mapped: " << inputPath << " to " << sensorName
303 << "\n";
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700304 }
James Feist139cb572018-09-10 15:26:18 -0700305 }
306 }
Yoo, Jae Hyun60e14d32018-10-10 11:03:11 -0700307
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700308 if (createdSensors.size())
309 {
310 std::cout << "Sensor" << (createdSensors.size() == 1 ? " is" : "s are")
311 << " created\n";
312 }
Yoo, Jae Hyun5481fac2018-10-09 16:43:03 -0700313
Yoo, Jae Hyun60e14d32018-10-10 11:03:11 -0700314 return true;
James Feist139cb572018-09-10 15:26:18 -0700315}
316
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700317void exportDevice(const CPUConfig& config)
James Feist139cb572018-09-10 15:26:18 -0700318{
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700319 std::ostringstream hex;
320 hex << std::hex << config.addr;
321 const std::string& addrHexStr = hex.str();
322 std::string busStr = std::to_string(config.bus);
323
324 std::string parameters = "peci-client 0x" + addrHexStr;
325 std::string device = "/sys/bus/peci/devices/peci-" + busStr + "/new_device";
326
327 std::experimental::filesystem::path devicePath(device);
328 const std::string& dir = devicePath.parent_path().string();
329 for (const auto& path :
330 std::experimental::filesystem::directory_iterator(dir))
James Feist139cb572018-09-10 15:26:18 -0700331 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700332 if (!std::experimental::filesystem::is_directory(path))
James Feist139cb572018-09-10 15:26:18 -0700333 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700334 continue;
James Feist139cb572018-09-10 15:26:18 -0700335 }
336
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700337 const std::string& directoryName = path.path().filename();
338 if (boost::starts_with(directoryName, busStr) &&
339 boost::ends_with(directoryName, addrHexStr))
340 {
341 if (DEBUG)
342 {
343 std::cout << parameters << " on bus " << busStr
344 << " is already exported\n";
345 }
346 return;
347 }
James Feist139cb572018-09-10 15:26:18 -0700348 }
349
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700350 std::ofstream deviceFile(device);
351 if (!deviceFile.good())
James Feist139cb572018-09-10 15:26:18 -0700352 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700353 std::cerr << "Error writing " << device << "\n";
James Feist139cb572018-09-10 15:26:18 -0700354 return;
355 }
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700356 deviceFile << parameters;
357 deviceFile.close();
358
359 std::cout << parameters << " on bus " << busStr << " is exported\n";
James Feist139cb572018-09-10 15:26:18 -0700360}
361
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700362void detectCpu(boost::asio::deadline_timer& pingTimer,
363 boost::asio::deadline_timer& creationTimer,
364 boost::asio::io_service& io,
James Feist139cb572018-09-10 15:26:18 -0700365 sdbusplus::asio::object_server& objectServer,
366 boost::container::flat_map<std::string,
367 std::unique_ptr<CPUSensor>>& sensors,
368 boost::container::flat_set<CPUConfig>& configs,
369 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
370{
James Feist139cb572018-09-10 15:26:18 -0700371 size_t rescanDelaySeconds = 0;
372 bool keepPinging = false;
Jae Hyun Yoo0003f462018-10-26 10:09:01 -0700373
James Feist139cb572018-09-10 15:26:18 -0700374 for (CPUConfig& config : configs)
375 {
Jae Hyun Yoo0003f462018-10-26 10:09:01 -0700376 std::string peciDevPath = peciDev + std::to_string(config.bus);
377 auto file = open(peciDevPath.c_str(), O_RDWR | O_CLOEXEC);
378 if (file < 0)
379 {
380 std::cerr << "unable to open " << peciDevPath << "\n";
381 std::exit(EXIT_FAILURE);
382 }
383
James Feist139cb572018-09-10 15:26:18 -0700384 State state;
385 struct peci_ping_msg msg;
386 msg.addr = config.addr;
387 if (!ioctl(file, PECI_IOC_PING, &msg))
388 {
389 bool dimmReady = false;
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700390 for (unsigned int rank = 0; rank < rankNumMax; rank++)
James Feist139cb572018-09-10 15:26:18 -0700391 {
392 struct peci_rd_pkg_cfg_msg msg;
393 msg.addr = config.addr;
394 msg.index = MBX_INDEX_DDR_DIMM_TEMP;
395 msg.param = rank;
396 msg.rx_len = 4;
397 if (!ioctl(file, PECI_IOC_RD_PKG_CFG, &msg))
398 {
399 if (msg.pkg_config[0] || msg.pkg_config[1] ||
400 msg.pkg_config[2])
401 {
402 dimmReady = true;
403 break;
404 }
405 }
406 else
407 {
408 break;
409 }
410 }
Yoo, Jae Hyun5481fac2018-10-09 16:43:03 -0700411
James Feist139cb572018-09-10 15:26:18 -0700412 if (dimmReady)
413 {
414 state = State::READY;
415 }
416 else
417 {
418 state = State::ON;
419 }
420 }
421 else
422 {
423 state = State::OFF;
424 }
425
Jae Hyun Yoo0003f462018-10-26 10:09:01 -0700426 close(file);
427
James Feist139cb572018-09-10 15:26:18 -0700428 if (config.state != state)
429 {
430 if (config.state == State::OFF)
431 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700432 std::cout << config.name << " is detected\n";
433 exportDevice(config);
James Feist139cb572018-09-10 15:26:18 -0700434 }
Yoo, Jae Hyun5481fac2018-10-09 16:43:03 -0700435 if (state == State::READY)
436 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700437 std::cout << "DIMM(s) on " << config.name
Yoo, Jae Hyun5481fac2018-10-09 16:43:03 -0700438 << " is/are detected\n";
439 }
James Feist139cb572018-09-10 15:26:18 -0700440 config.state = state;
441 }
442
Yoo, Jae Hyun60e14d32018-10-10 11:03:11 -0700443 if (config.state != State::OFF)
444 {
445 if (config.state == State::ON)
446 {
447 rescanDelaySeconds = 1;
448 }
449 else
450 {
451 rescanDelaySeconds = 5;
452 }
453 }
454
455 if (config.state != State::READY)
James Feist139cb572018-09-10 15:26:18 -0700456 {
457 keepPinging = true;
458 }
459
460 if (DEBUG)
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700461 {
462 std::cout << config.name << ", state: " << config.state << "\n";
463 }
James Feist139cb572018-09-10 15:26:18 -0700464 }
465
James Feist139cb572018-09-10 15:26:18 -0700466 if (rescanDelaySeconds)
467 {
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700468 creationTimer.expires_from_now(
469 boost::posix_time::seconds(rescanDelaySeconds));
470 creationTimer.async_wait([&](const boost::system::error_code& ec) {
471 if (ec == boost::asio::error::operation_aborted)
472 {
473 return; // we're being canceled
474 }
475
476 if (!createSensors(io, objectServer, sensors, configs,
477 dbusConnection))
478 {
479 detectCpuAsync(pingTimer, creationTimer, io, objectServer,
480 sensors, configs, dbusConnection);
481 }
482 });
James Feist139cb572018-09-10 15:26:18 -0700483 }
484
485 if (keepPinging)
486 {
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700487 detectCpuAsync(pingTimer, creationTimer, io, objectServer, sensors,
488 configs, dbusConnection);
James Feist139cb572018-09-10 15:26:18 -0700489 }
490}
491
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700492void detectCpuAsync(
493 boost::asio::deadline_timer& pingTimer,
494 boost::asio::deadline_timer& creationTimer, boost::asio::io_service& io,
495 sdbusplus::asio::object_server& objectServer,
496 boost::container::flat_map<std::string, std::unique_ptr<CPUSensor>>&
497 sensors,
498 boost::container::flat_set<CPUConfig>& configs,
499 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
500{
501 pingTimer.expires_from_now(boost::posix_time::seconds(1));
502 pingTimer.async_wait([&](const boost::system::error_code& ec) {
503 if (ec == boost::asio::error::operation_aborted)
504 {
505 return; // we're being canceled
506 }
507
508 detectCpu(pingTimer, creationTimer, io, objectServer, sensors, configs,
509 dbusConnection);
510 });
511}
512
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700513bool getCpuConfig(const std::shared_ptr<sdbusplus::asio::connection>& systemBus,
James Feist139cb572018-09-10 15:26:18 -0700514 boost::container::flat_set<CPUConfig>& configs)
515{
516 ManagedObjectType sensorConfigurations;
517 bool useCache = false;
518 // use new data the first time, then refresh
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700519 for (const char* type : sensorTypes)
James Feist139cb572018-09-10 15:26:18 -0700520 {
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700521 if (!getSensorConfiguration(configPrefix + std::string(type), systemBus,
522 sensorConfigurations, useCache))
James Feist139cb572018-09-10 15:26:18 -0700523 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700524 return false;
James Feist139cb572018-09-10 15:26:18 -0700525 }
526 useCache = true;
527 }
528
529 // check PECI client addresses and DT overlay names from CPU configuration
530 // before starting ping operation
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700531 for (const char* type : sensorTypes)
James Feist139cb572018-09-10 15:26:18 -0700532 {
533 for (const std::pair<sdbusplus::message::object_path, SensorData>&
534 sensor : sensorConfigurations)
535 {
536 for (const std::pair<
537 std::string,
538 boost::container::flat_map<std::string, BasicVariantType>>&
539 config : sensor.second)
540 {
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700541 if ((configPrefix + std::string(type)) != config.first)
James Feist139cb572018-09-10 15:26:18 -0700542 {
543 continue;
544 }
545
James Feist139cb572018-09-10 15:26:18 -0700546 auto findName = config.second.find("Name");
547 if (findName == config.second.end())
548 {
549 continue;
550 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700551 std::string nameRaw = variant_ns::visit(
James Feist139cb572018-09-10 15:26:18 -0700552 VariantToStringVisitor(), findName->second);
553 std::string name =
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700554 std::regex_replace(nameRaw, illegalDbusRegex, "_");
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700555
556 auto findBus = config.second.find("Bus");
557 if (findBus == config.second.end())
558 {
559 std::cerr << "Can't find 'Bus' setting in " << name << "\n";
560 continue;
561 }
562 uint64_t bus = variant_ns::visit(VariantToUnsignedIntVisitor(),
563 findBus->second);
564
565 auto findAddress = config.second.find("Address");
566 if (findAddress == config.second.end())
567 {
568 std::cerr << "Can't find 'Address' setting in " << name
569 << "\n";
570 continue;
571 }
572 uint64_t addr = variant_ns::visit(VariantToUnsignedIntVisitor(),
573 findAddress->second);
James Feist139cb572018-09-10 15:26:18 -0700574
575 if (DEBUG)
576 {
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700577 std::cout << "bus: " << bus << "\n";
James Feist139cb572018-09-10 15:26:18 -0700578 std::cout << "addr: " << addr << "\n";
579 std::cout << "name: " << name << "\n";
580 std::cout << "type: " << type << "\n";
James Feist139cb572018-09-10 15:26:18 -0700581 }
582
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700583 configs.emplace(bus, addr, name, State::OFF);
James Feist139cb572018-09-10 15:26:18 -0700584 }
585 }
586 }
Yoo, Jae Hyun5481fac2018-10-09 16:43:03 -0700587
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700588 if (configs.size())
589 {
590 std::cout << "CPU config" << (configs.size() == 1 ? " is" : "s are")
591 << " parsed\n";
592 return true;
593 }
594
595 return false;
James Feist139cb572018-09-10 15:26:18 -0700596}
597
598int main(int argc, char** argv)
599{
600 boost::asio::io_service io;
601 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
602 boost::container::flat_set<CPUConfig> configs;
603
604 systemBus->request_name("xyz.openbmc_project.CPUSensor");
605 sdbusplus::asio::object_server objectServer(systemBus);
606 boost::container::flat_map<std::string, std::unique_ptr<CPUSensor>> sensors;
607 std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
608 boost::asio::deadline_timer pingTimer(io);
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700609 boost::asio::deadline_timer creationTimer(io);
James Feist139cb572018-09-10 15:26:18 -0700610 boost::asio::deadline_timer filterTimer(io);
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700611
612 filterTimer.expires_from_now(boost::posix_time::seconds(1));
613 filterTimer.async_wait([&](const boost::system::error_code& ec) {
614 if (ec == boost::asio::error::operation_aborted)
615 {
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700616 return; // we're being canceled
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700617 }
618
619 if (getCpuConfig(systemBus, configs))
620 {
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700621 detectCpuAsync(pingTimer, creationTimer, io, objectServer, sensors,
622 configs, systemBus);
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700623 }
624 });
625
James Feist139cb572018-09-10 15:26:18 -0700626 std::function<void(sdbusplus::message::message&)> eventHandler =
627 [&](sdbusplus::message::message& message) {
628 if (message.is_method_error())
629 {
630 std::cerr << "callback method error\n";
631 return;
632 }
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700633
634 if (DEBUG)
635 {
636 std::cout << message.get_path() << " is changed\n";
637 }
638
James Feist139cb572018-09-10 15:26:18 -0700639 // this implicitly cancels the timer
640 filterTimer.expires_from_now(boost::posix_time::seconds(1));
James Feist139cb572018-09-10 15:26:18 -0700641 filterTimer.async_wait([&](const boost::system::error_code& ec) {
642 if (ec == boost::asio::error::operation_aborted)
643 {
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700644 return; // we're being canceled
James Feist139cb572018-09-10 15:26:18 -0700645 }
646
Jae Hyun Yooa8fa4d22018-10-22 15:24:29 -0700647 if (getCpuConfig(systemBus, configs))
James Feist139cb572018-09-10 15:26:18 -0700648 {
Jae Hyun Yoo95ca3a52018-11-01 13:31:16 -0700649 detectCpuAsync(pingTimer, creationTimer, io, objectServer,
650 sensors, configs, systemBus);
James Feist139cb572018-09-10 15:26:18 -0700651 }
652 });
653 };
654
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700655 for (const char* type : sensorTypes)
James Feist139cb572018-09-10 15:26:18 -0700656 {
657 auto match = std::make_unique<sdbusplus::bus::match::match>(
658 static_cast<sdbusplus::bus::bus&>(*systemBus),
659 "type='signal',member='PropertiesChanged',path_namespace='" +
Jae Hyun Yoof78ec412018-10-25 10:42:39 -0700660 std::string(inventoryPath) + "',arg0namespace='" +
661 configPrefix + type + "'",
James Feist139cb572018-09-10 15:26:18 -0700662 eventHandler);
663 matches.emplace_back(std::move(match));
664 }
665
666 io.run();
667}