blob: a159714de6a59b56a525bf8544e44178f7d99beb [file] [log] [blame]
James Feist6714a252018-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>
James Feist6714a252018-09-10 15:26:18 -070018
19#include <CPUSensor.hpp>
20#include <Utils.hpp>
21#include <VariantVisitors.hpp>
22#include <boost/algorithm/string/predicate.hpp>
23#include <boost/algorithm/string/replace.hpp>
24#include <boost/container/flat_set.hpp>
25#include <boost/date_time/posix_time/posix_time.hpp>
26#include <boost/process/child.hpp>
James Feist24f02f22019-04-15 11:05:39 -070027#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070028#include <fstream>
29#include <regex>
30#include <sdbusplus/asio/connection.hpp>
31#include <sdbusplus/asio/object_server.hpp>
32
James Feistf87dc4c2018-12-05 14:39:51 -080033// clang-format off
34// this needs to be included last or we'll have build issues
35#include <linux/peci-ioctl.h>
Jae Hyun Yoo201c8d92019-02-27 15:41:56 -080036#if !defined(PECI_MBX_INDEX_DDR_DIMM_TEMP)
37#define PECI_MBX_INDEX_DDR_DIMM_TEMP MBX_INDEX_DDR_DIMM_TEMP
38#endif
James Feistf87dc4c2018-12-05 14:39:51 -080039// clang-format on
40
James Feist6714a252018-09-10 15:26:18 -070041static constexpr bool DEBUG = false;
42
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -080043boost::container::flat_map<std::string, std::unique_ptr<CPUSensor>> gCpuSensors;
44
James Feist6714a252018-09-10 15:26:18 -070045enum State
46{
47 OFF, // host powered down
48 ON, // host powered on
49 READY // host powered on and mem test passed - fully ready
50};
51
52struct CPUConfig
53{
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -070054 CPUConfig(const uint64_t& bus, const uint64_t& addr,
55 const std::string& name, const State& state) :
56 bus(bus),
57 addr(addr), name(name), state(state)
James Feist6714a252018-09-10 15:26:18 -070058 {
59 }
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -070060 int bus;
James Feist6714a252018-09-10 15:26:18 -070061 int addr;
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -070062 std::string name;
James Feist6714a252018-09-10 15:26:18 -070063 State state;
64
65 bool operator<(const CPUConfig& rhs) const
66 {
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -070067 return (name < rhs.name);
James Feist6714a252018-09-10 15:26:18 -070068 }
69};
70
Jae Hyun Yoo9c55e6a2018-10-26 10:09:01 -070071static constexpr const char* peciDev = "/dev/peci-";
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070072static constexpr const unsigned int rankNumMax = 8;
James Feist6714a252018-09-10 15:26:18 -070073
James Feistcf3bce62019-01-08 10:07:19 -080074namespace fs = std::filesystem;
James Feist3eb82622019-02-08 13:10:22 -080075
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070076static constexpr const char* configPrefix =
James Feist6714a252018-09-10 15:26:18 -070077 "xyz.openbmc_project.Configuration.";
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070078static constexpr std::array<const char*, 3> sensorTypes = {
James Feist6714a252018-09-10 15:26:18 -070079 "SkylakeCPU", "BroadwellCPU", "HaswellCPU"};
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -080080static constexpr std::array<const char*, 3> hiddenProps = {
81 CPUSensor::labelTcontrol, "Tthrottle", "Tjmax"};
James Feist6714a252018-09-10 15:26:18 -070082
Jae Hyun Yood64262b2018-11-01 13:31:16 -070083void detectCpuAsync(
84 boost::asio::deadline_timer& pingTimer,
85 boost::asio::deadline_timer& creationTimer, boost::asio::io_service& io,
86 sdbusplus::asio::object_server& objectServer,
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -080087 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -080088 boost::container::flat_set<CPUConfig>& cpuConfigs,
89 ManagedObjectType& sensorConfigs);
Jae Hyun Yood64262b2018-11-01 13:31:16 -070090
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -080091bool createSensors(boost::asio::io_service& io,
92 sdbusplus::asio::object_server& objectServer,
93 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
94 boost::container::flat_set<CPUConfig>& cpuConfigs,
95 ManagedObjectType& sensorConfigs)
James Feist6714a252018-09-10 15:26:18 -070096{
97 bool available = false;
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -080098 for (const CPUConfig& cpu : cpuConfigs)
James Feist6714a252018-09-10 15:26:18 -070099 {
100 if (cpu.state != State::OFF)
101 {
102 available = true;
103 break;
104 }
105 }
106 if (!available)
107 {
Yoo, Jae Hyunf78d0a42018-10-10 11:03:11 -0700108 return false;
James Feist6714a252018-09-10 15:26:18 -0700109 }
110
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800111 if (sensorConfigs.empty())
James Feist6714a252018-09-10 15:26:18 -0700112 {
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800113 return false;
James Feist6714a252018-09-10 15:26:18 -0700114 }
115
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700116 std::vector<fs::path> hwmonNamePaths;
Jae Hyun Yoo9ced0a32018-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 Feist6714a252018-09-10 15:26:18 -0700120 {
121 std::cerr << "No CPU sensors in system\n";
Yoo, Jae Hyunf78d0a42018-10-10 11:03:11 -0700122 return true;
James Feist6714a252018-09-10 15:26:18 -0700123 }
124
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700125 boost::container::flat_set<std::string> scannedDirectories;
126 boost::container::flat_set<std::string> createdSensors;
127
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800128 for (const fs::path& hwmonNamePath : hwmonNamePaths)
James Feist6714a252018-09-10 15:26:18 -0700129 {
Jae Hyun Yoo8d9886d2018-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 Feist6714a252018-09-10 15:26:18 -0700135 {
Jae Hyun Yoo8d9886d2018-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 Feist6714a252018-09-10 15:26:18 -0700146 continue;
147 }
Jae Hyun Yoo8d9886d2018-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 Feist6714a252018-09-10 15:26:18 -0700171 nameFile.close();
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800172 if (hwmonName.empty())
James Feist6714a252018-09-10 15:26:18 -0700173 {
174 // shouldn't have an empty name file
175 continue;
176 }
James Feist6714a252018-09-10 15:26:18 -0700177 if (DEBUG)
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700178 {
179 std::cout << "Checking: " << hwmonNamePath << ": " << hwmonName
180 << "\n";
181 }
James Feist6714a252018-09-10 15:26:18 -0700182
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700183 std::string sensorType;
James Feist6714a252018-09-10 15:26:18 -0700184 const SensorData* sensorData = nullptr;
185 const std::string* interfacePath = nullptr;
James Feist6714a252018-09-10 15:26:18 -0700186 const std::pair<std::string, boost::container::flat_map<
187 std::string, BasicVariantType>>*
188 baseConfiguration = nullptr;
James Feist6714a252018-09-10 15:26:18 -0700189
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700190 for (const std::pair<sdbusplus::message::object_path, SensorData>&
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800191 sensor : sensorConfigs)
James Feist6714a252018-09-10 15:26:18 -0700192 {
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700193 sensorData = &(sensor.second);
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700194 for (const char* type : sensorTypes)
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700195 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700196 sensorType = configPrefix + std::string(type);
Jae Hyun Yoo8d9886d2018-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
James Feist3eb82622019-02-08 13:10:22 -0800221 if (std::get<uint64_t>(configurationBus->second) != bus ||
222 std::get<uint64_t>(configurationAddress->second) != addr)
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700223 {
224 continue;
225 }
226
227 interfacePath = &(sensor.first.str);
228 break;
229 }
230 if (interfacePath == nullptr)
231 {
232 std::cerr << "failed to find match for " << hwmonName << "\n";
James Feist6714a252018-09-10 15:26:18 -0700233 continue;
234 }
235
236 auto findCpuId = baseConfiguration->second.find("CpuID");
237 if (findCpuId == baseConfiguration->second.end())
238 {
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700239 std::cerr << "could not determine CPU ID for " << hwmonName << "\n";
James Feist6714a252018-09-10 15:26:18 -0700240 continue;
241 }
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700242 int cpuId =
James Feist3eb82622019-02-08 13:10:22 -0800243 std::visit(VariantToUnsignedIntVisitor(), findCpuId->second);
James Feist6714a252018-09-10 15:26:18 -0700244
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700245 auto directory = hwmonNamePath.parent_path();
James Feist6714a252018-09-10 15:26:18 -0700246 std::vector<fs::path> inputPaths;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700247 if (!findFiles(fs::path(directory), R"(temp\d+_input$)", inputPaths, 0))
James Feist6714a252018-09-10 15:26:18 -0700248 {
249 std::cerr << "No temperature sensors in system\n";
250 continue;
251 }
252
253 // iterate through all found temp sensors
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800254 for (const auto& inputPath : inputPaths)
James Feist6714a252018-09-10 15:26:18 -0700255 {
256 auto inputPathStr = inputPath.string();
257 auto labelPath =
258 boost::replace_all_copy(inputPathStr, "input", "label");
259 std::ifstream labelFile(labelPath);
260 if (!labelFile.good())
261 {
262 std::cerr << "Failure reading " << labelPath << "\n";
263 continue;
264 }
265 std::string label;
266 std::getline(labelFile, label);
267 labelFile.close();
Jae Hyun Yoo13f48882019-02-19 13:37:07 -0800268
James Feist6714a252018-09-10 15:26:18 -0700269 std::string sensorName = label + " CPU" + std::to_string(cpuId);
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700270
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800271 auto findSensor = gCpuSensors.find(sensorName);
272 if (findSensor != gCpuSensors.end())
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700273 {
274 if (DEBUG)
275 {
276 std::cout << "Skipped: " << inputPath << ": " << sensorName
277 << " is already created\n";
278 }
279 continue;
280 }
281
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800282 // check hidden properties
283 bool show = true;
284 for (const char* prop : hiddenProps)
285 {
286 if (label == prop)
287 {
288 show = false;
289 break;
290 }
291 }
292
James Feist6714a252018-09-10 15:26:18 -0700293 std::vector<thresholds::Threshold> sensorThresholds;
294 std::string labelHead = label.substr(0, label.find(" "));
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700295 parseThresholdsFromConfig(*sensorData, sensorThresholds,
Yoo, Jae Hyun81a464c2018-10-09 16:38:58 -0700296 &labelHead);
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800297 if (sensorThresholds.empty())
James Feist6714a252018-09-10 15:26:18 -0700298 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700299 if (!parseThresholdsFromAttr(sensorThresholds, inputPathStr,
300 CPUSensor::sensorScaleFactor))
James Feist6714a252018-09-10 15:26:18 -0700301 {
Yoo, Jae Hyun81a464c2018-10-09 16:38:58 -0700302 std::cerr << "error populating thresholds for "
303 << sensorName << "\n";
James Feist6714a252018-09-10 15:26:18 -0700304 }
305 }
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800306 gCpuSensors[sensorName] = std::make_unique<CPUSensor>(
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700307 inputPathStr, sensorType, objectServer, dbusConnection, io,
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800308 sensorName, std::move(sensorThresholds), *interfacePath, cpuId,
309 show);
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700310 createdSensors.insert(sensorName);
James Feist6714a252018-09-10 15:26:18 -0700311 if (DEBUG)
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700312 {
James Feist6714a252018-09-10 15:26:18 -0700313 std::cout << "Mapped: " << inputPath << " to " << sensorName
314 << "\n";
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700315 }
James Feist6714a252018-09-10 15:26:18 -0700316 }
317 }
Yoo, Jae Hyunf78d0a42018-10-10 11:03:11 -0700318
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700319 if (createdSensors.size())
320 {
321 std::cout << "Sensor" << (createdSensors.size() == 1 ? " is" : "s are")
322 << " created\n";
323 }
Yoo, Jae Hyuna441f3c2018-10-09 16:43:03 -0700324
Yoo, Jae Hyunf78d0a42018-10-10 11:03:11 -0700325 return true;
James Feist6714a252018-09-10 15:26:18 -0700326}
327
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700328void exportDevice(const CPUConfig& config)
James Feist6714a252018-09-10 15:26:18 -0700329{
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700330 std::ostringstream hex;
331 hex << std::hex << config.addr;
332 const std::string& addrHexStr = hex.str();
333 std::string busStr = std::to_string(config.bus);
334
335 std::string parameters = "peci-client 0x" + addrHexStr;
336 std::string device = "/sys/bus/peci/devices/peci-" + busStr + "/new_device";
337
James Feistcf3bce62019-01-08 10:07:19 -0800338 std::filesystem::path devicePath(device);
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700339 const std::string& dir = devicePath.parent_path().string();
James Feistcf3bce62019-01-08 10:07:19 -0800340 for (const auto& path : std::filesystem::directory_iterator(dir))
James Feist6714a252018-09-10 15:26:18 -0700341 {
James Feistcf3bce62019-01-08 10:07:19 -0800342 if (!std::filesystem::is_directory(path))
James Feist6714a252018-09-10 15:26:18 -0700343 {
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700344 continue;
James Feist6714a252018-09-10 15:26:18 -0700345 }
346
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700347 const std::string& directoryName = path.path().filename();
348 if (boost::starts_with(directoryName, busStr) &&
349 boost::ends_with(directoryName, addrHexStr))
350 {
351 if (DEBUG)
352 {
353 std::cout << parameters << " on bus " << busStr
354 << " is already exported\n";
355 }
356 return;
357 }
James Feist6714a252018-09-10 15:26:18 -0700358 }
359
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700360 std::ofstream deviceFile(device);
361 if (!deviceFile.good())
James Feist6714a252018-09-10 15:26:18 -0700362 {
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700363 std::cerr << "Error writing " << device << "\n";
James Feist6714a252018-09-10 15:26:18 -0700364 return;
365 }
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700366 deviceFile << parameters;
367 deviceFile.close();
368
369 std::cout << parameters << " on bus " << busStr << " is exported\n";
James Feist6714a252018-09-10 15:26:18 -0700370}
371
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800372void detectCpu(boost::asio::deadline_timer& pingTimer,
373 boost::asio::deadline_timer& creationTimer,
374 boost::asio::io_service& io,
375 sdbusplus::asio::object_server& objectServer,
376 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
377 boost::container::flat_set<CPUConfig>& cpuConfigs,
378 ManagedObjectType& sensorConfigs)
James Feist6714a252018-09-10 15:26:18 -0700379{
James Feist6714a252018-09-10 15:26:18 -0700380 size_t rescanDelaySeconds = 0;
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700381 static bool keepPinging = false;
Jae Hyun Yoo9c55e6a2018-10-26 10:09:01 -0700382
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800383 for (CPUConfig& config : cpuConfigs)
James Feist6714a252018-09-10 15:26:18 -0700384 {
Jae Hyun Yoo9c55e6a2018-10-26 10:09:01 -0700385 std::string peciDevPath = peciDev + std::to_string(config.bus);
386 auto file = open(peciDevPath.c_str(), O_RDWR | O_CLOEXEC);
387 if (file < 0)
388 {
389 std::cerr << "unable to open " << peciDevPath << "\n";
390 std::exit(EXIT_FAILURE);
391 }
392
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700393 State newState;
James Feist6714a252018-09-10 15:26:18 -0700394 struct peci_ping_msg msg;
395 msg.addr = config.addr;
396 if (!ioctl(file, PECI_IOC_PING, &msg))
397 {
398 bool dimmReady = false;
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700399 for (unsigned int rank = 0; rank < rankNumMax; rank++)
James Feist6714a252018-09-10 15:26:18 -0700400 {
401 struct peci_rd_pkg_cfg_msg msg;
402 msg.addr = config.addr;
Jae Hyun Yoo201c8d92019-02-27 15:41:56 -0800403 msg.index = PECI_MBX_INDEX_DDR_DIMM_TEMP;
James Feist6714a252018-09-10 15:26:18 -0700404 msg.param = rank;
405 msg.rx_len = 4;
406 if (!ioctl(file, PECI_IOC_RD_PKG_CFG, &msg))
407 {
408 if (msg.pkg_config[0] || msg.pkg_config[1] ||
409 msg.pkg_config[2])
410 {
411 dimmReady = true;
412 break;
413 }
414 }
415 else
416 {
417 break;
418 }
419 }
Yoo, Jae Hyuna441f3c2018-10-09 16:43:03 -0700420
James Feist6714a252018-09-10 15:26:18 -0700421 if (dimmReady)
422 {
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700423 newState = State::READY;
James Feist6714a252018-09-10 15:26:18 -0700424 }
425 else
426 {
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700427 newState = State::ON;
James Feist6714a252018-09-10 15:26:18 -0700428 }
429 }
430 else
431 {
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700432 newState = State::OFF;
James Feist6714a252018-09-10 15:26:18 -0700433 }
434
Jae Hyun Yoo9c55e6a2018-10-26 10:09:01 -0700435 close(file);
436
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700437 if (config.state != newState)
James Feist6714a252018-09-10 15:26:18 -0700438 {
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700439 if (newState != State::OFF)
James Feist6714a252018-09-10 15:26:18 -0700440 {
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700441 if (config.state == State::OFF)
442 {
443 std::cout << config.name << " is detected\n";
444 exportDevice(config);
445 }
James Feist6714a252018-09-10 15:26:18 -0700446
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700447 if (newState == State::ON)
448 {
449 rescanDelaySeconds = 3;
450 }
451 else if (newState == State::READY)
452 {
453 rescanDelaySeconds = 5;
454 std::cout << "DIMM(s) on " << config.name
455 << " is/are detected\n";
456 }
Yoo, Jae Hyunf78d0a42018-10-10 11:03:11 -0700457 }
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700458
459 config.state = newState;
Yoo, Jae Hyunf78d0a42018-10-10 11:03:11 -0700460 }
461
462 if (config.state != State::READY)
James Feist6714a252018-09-10 15:26:18 -0700463 {
464 keepPinging = true;
465 }
466
467 if (DEBUG)
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700468 {
469 std::cout << config.name << ", state: " << config.state << "\n";
470 }
James Feist6714a252018-09-10 15:26:18 -0700471 }
472
James Feist6714a252018-09-10 15:26:18 -0700473 if (rescanDelaySeconds)
474 {
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700475 creationTimer.expires_from_now(
476 boost::posix_time::seconds(rescanDelaySeconds));
477 creationTimer.async_wait([&](const boost::system::error_code& ec) {
478 if (ec == boost::asio::error::operation_aborted)
479 {
480 return; // we're being canceled
481 }
482
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800483 if (!createSensors(io, objectServer, dbusConnection, cpuConfigs,
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700484 sensorConfigs) ||
485 keepPinging)
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700486 {
487 detectCpuAsync(pingTimer, creationTimer, io, objectServer,
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800488 dbusConnection, cpuConfigs, sensorConfigs);
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700489 }
490 });
James Feist6714a252018-09-10 15:26:18 -0700491 }
Jae Hyun Yoo18ae22f2019-04-02 10:11:30 -0700492 else if (keepPinging)
James Feist6714a252018-09-10 15:26:18 -0700493 {
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800494 detectCpuAsync(pingTimer, creationTimer, io, objectServer,
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800495 dbusConnection, cpuConfigs, sensorConfigs);
James Feist6714a252018-09-10 15:26:18 -0700496 }
497}
498
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700499void detectCpuAsync(
500 boost::asio::deadline_timer& pingTimer,
501 boost::asio::deadline_timer& creationTimer, boost::asio::io_service& io,
502 sdbusplus::asio::object_server& objectServer,
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800503 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800504 boost::container::flat_set<CPUConfig>& cpuConfigs,
505 ManagedObjectType& sensorConfigs)
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700506{
507 pingTimer.expires_from_now(boost::posix_time::seconds(1));
508 pingTimer.async_wait([&](const boost::system::error_code& ec) {
509 if (ec == boost::asio::error::operation_aborted)
510 {
511 return; // we're being canceled
512 }
513
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800514 detectCpu(pingTimer, creationTimer, io, objectServer, dbusConnection,
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800515 cpuConfigs, sensorConfigs);
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700516 });
517}
518
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700519bool getCpuConfig(const std::shared_ptr<sdbusplus::asio::connection>& systemBus,
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800520 boost::container::flat_set<CPUConfig>& cpuConfigs,
521 ManagedObjectType& sensorConfigs)
James Feist6714a252018-09-10 15:26:18 -0700522{
James Feist6714a252018-09-10 15:26:18 -0700523 bool useCache = false;
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800524 sensorConfigs.clear();
James Feist6714a252018-09-10 15:26:18 -0700525 // use new data the first time, then refresh
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700526 for (const char* type : sensorTypes)
James Feist6714a252018-09-10 15:26:18 -0700527 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700528 if (!getSensorConfiguration(configPrefix + std::string(type), systemBus,
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800529 sensorConfigs, useCache))
James Feist6714a252018-09-10 15:26:18 -0700530 {
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700531 return false;
James Feist6714a252018-09-10 15:26:18 -0700532 }
533 useCache = true;
534 }
535
536 // check PECI client addresses and DT overlay names from CPU configuration
537 // before starting ping operation
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700538 for (const char* type : sensorTypes)
James Feist6714a252018-09-10 15:26:18 -0700539 {
540 for (const std::pair<sdbusplus::message::object_path, SensorData>&
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800541 sensor : sensorConfigs)
James Feist6714a252018-09-10 15:26:18 -0700542 {
543 for (const std::pair<
544 std::string,
545 boost::container::flat_map<std::string, BasicVariantType>>&
546 config : sensor.second)
547 {
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700548 if ((configPrefix + std::string(type)) != config.first)
James Feist6714a252018-09-10 15:26:18 -0700549 {
550 continue;
551 }
552
James Feist6714a252018-09-10 15:26:18 -0700553 auto findName = config.second.find("Name");
554 if (findName == config.second.end())
555 {
556 continue;
557 }
James Feist3eb82622019-02-08 13:10:22 -0800558 std::string nameRaw =
559 std::visit(VariantToStringVisitor(), findName->second);
James Feist6714a252018-09-10 15:26:18 -0700560 std::string name =
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700561 std::regex_replace(nameRaw, illegalDbusRegex, "_");
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700562
563 auto findBus = config.second.find("Bus");
564 if (findBus == config.second.end())
565 {
566 std::cerr << "Can't find 'Bus' setting in " << name << "\n";
567 continue;
568 }
James Feist3eb82622019-02-08 13:10:22 -0800569 uint64_t bus =
570 std::visit(VariantToUnsignedIntVisitor(), findBus->second);
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700571
572 auto findAddress = config.second.find("Address");
573 if (findAddress == config.second.end())
574 {
575 std::cerr << "Can't find 'Address' setting in " << name
576 << "\n";
577 continue;
578 }
James Feist3eb82622019-02-08 13:10:22 -0800579 uint64_t addr = std::visit(VariantToUnsignedIntVisitor(),
580 findAddress->second);
James Feist6714a252018-09-10 15:26:18 -0700581
582 if (DEBUG)
583 {
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700584 std::cout << "bus: " << bus << "\n";
James Feist6714a252018-09-10 15:26:18 -0700585 std::cout << "addr: " << addr << "\n";
586 std::cout << "name: " << name << "\n";
587 std::cout << "type: " << type << "\n";
James Feist6714a252018-09-10 15:26:18 -0700588 }
589
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800590 cpuConfigs.emplace(bus, addr, name, State::OFF);
James Feist6714a252018-09-10 15:26:18 -0700591 }
592 }
593 }
Yoo, Jae Hyuna441f3c2018-10-09 16:43:03 -0700594
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800595 if (cpuConfigs.size())
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700596 {
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800597 std::cout << "CPU config" << (cpuConfigs.size() == 1 ? " is" : "s are")
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700598 << " parsed\n";
599 return true;
600 }
601
602 return false;
James Feist6714a252018-09-10 15:26:18 -0700603}
604
605int main(int argc, char** argv)
606{
607 boost::asio::io_service io;
608 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800609 boost::container::flat_set<CPUConfig> cpuConfigs;
James Feist6714a252018-09-10 15:26:18 -0700610
611 systemBus->request_name("xyz.openbmc_project.CPUSensor");
612 sdbusplus::asio::object_server objectServer(systemBus);
James Feist6714a252018-09-10 15:26:18 -0700613 std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
614 boost::asio::deadline_timer pingTimer(io);
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700615 boost::asio::deadline_timer creationTimer(io);
James Feist6714a252018-09-10 15:26:18 -0700616 boost::asio::deadline_timer filterTimer(io);
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800617 ManagedObjectType sensorConfigs;
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700618
619 filterTimer.expires_from_now(boost::posix_time::seconds(1));
620 filterTimer.async_wait([&](const boost::system::error_code& ec) {
621 if (ec == boost::asio::error::operation_aborted)
622 {
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700623 return; // we're being canceled
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700624 }
625
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800626 if (getCpuConfig(systemBus, cpuConfigs, sensorConfigs))
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700627 {
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800628 detectCpuAsync(pingTimer, creationTimer, io, objectServer,
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800629 systemBus, cpuConfigs, sensorConfigs);
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700630 }
631 });
632
James Feist6714a252018-09-10 15:26:18 -0700633 std::function<void(sdbusplus::message::message&)> eventHandler =
634 [&](sdbusplus::message::message& message) {
635 if (message.is_method_error())
636 {
637 std::cerr << "callback method error\n";
638 return;
639 }
Jae Hyun Yoo8d9886d2018-10-22 15:24:29 -0700640
641 if (DEBUG)
642 {
643 std::cout << message.get_path() << " is changed\n";
644 }
645
James Feist6714a252018-09-10 15:26:18 -0700646 // this implicitly cancels the timer
647 filterTimer.expires_from_now(boost::posix_time::seconds(1));
James Feist6714a252018-09-10 15:26:18 -0700648 filterTimer.async_wait([&](const boost::system::error_code& ec) {
649 if (ec == boost::asio::error::operation_aborted)
650 {
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700651 return; // we're being canceled
James Feist6714a252018-09-10 15:26:18 -0700652 }
653
Jae Hyun Yooe8b60d02019-01-14 15:27:13 -0800654 if (getCpuConfig(systemBus, cpuConfigs, sensorConfigs))
James Feist6714a252018-09-10 15:26:18 -0700655 {
Jae Hyun Yood64262b2018-11-01 13:31:16 -0700656 detectCpuAsync(pingTimer, creationTimer, io, objectServer,
Jae Hyun Yoo73ca5512019-02-28 21:20:17 -0800657 systemBus, cpuConfigs, sensorConfigs);
James Feist6714a252018-09-10 15:26:18 -0700658 }
659 });
660 };
661
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700662 for (const char* type : sensorTypes)
James Feist6714a252018-09-10 15:26:18 -0700663 {
664 auto match = std::make_unique<sdbusplus::bus::match::match>(
665 static_cast<sdbusplus::bus::bus&>(*systemBus),
666 "type='signal',member='PropertiesChanged',path_namespace='" +
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700667 std::string(inventoryPath) + "',arg0namespace='" +
668 configPrefix + type + "'",
James Feist6714a252018-09-10 15:26:18 -0700669 eventHandler);
670 matches.emplace_back(std::move(match));
671 }
672
673 io.run();
674}