blob: 6e44d71ec840555f7164c8e364d0a9706a3569fd [file] [log] [blame]
Zhikui Ren18a5ab92020-09-01 21:35:20 -07001/*
2// Copyright (c) 2020 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 "cpuinfo.hpp"
Jonathan Doman703a1852020-11-11 13:04:02 -080018#include "cpuinfo_utils.hpp"
Jonathan Doman94c94bf2020-10-05 23:25:45 -070019#include "speed_select.hpp"
Zhikui Ren18a5ab92020-09-01 21:35:20 -070020
21#include <errno.h>
22#include <fcntl.h>
23#include <stdio.h>
24#include <sys/ioctl.h>
25
26#include <boost/asio/io_service.hpp>
27#include <boost/asio/steady_timer.hpp>
28
Zhikui Ren6d3ad582020-09-11 21:25:59 -070029#include <iostream>
Jonathan Doman2285be42021-03-08 14:54:12 -080030#include <list>
Zhikui Ren18a5ab92020-09-01 21:35:20 -070031#include <optional>
32#include <sstream>
33#include <string>
34
35extern "C"
36{
37#include <i2c/smbus.h>
38#include <linux/i2c-dev.h>
39}
40
41#include <peci.h>
42
43#include <phosphor-logging/log.hpp>
44#include <sdbusplus/asio/object_server.hpp>
45
Zhikui Ren18a5ab92020-09-01 21:35:20 -070046namespace cpu_info
47{
Zhikui Ren6d3ad582020-09-11 21:25:59 -070048static constexpr bool debug = false;
Jonathan Doman2285be42021-03-08 14:54:12 -080049static constexpr const char* assetInterfaceName =
Zhikui Ren18a5ab92020-09-01 21:35:20 -070050 "xyz.openbmc_project.Inventory.Decorator.Asset";
51static constexpr const char* cpuProcessName =
52 "xyz.openbmc_project.Smbios.MDR_V2";
53
Zhikui Ren6d3ad582020-09-11 21:25:59 -070054// constants for reading SSPEC or QDF string from PIROM
55// Currently, they are the same for platforms with icx
56static constexpr uint8_t defaultI2cBus = 13;
57static constexpr uint8_t defaultI2cSlaveAddr0 = 0x50;
58static constexpr uint8_t sspecRegAddr = 0xd;
59static constexpr uint8_t sspecSize = 6;
Zhikui Ren18a5ab92020-09-01 21:35:20 -070060
Zhikui Ren6d3ad582020-09-11 21:25:59 -070061using CPUInfoMap = boost::container::flat_map<size_t, std::shared_ptr<CPUInfo>>;
Zhikui Ren18a5ab92020-09-01 21:35:20 -070062
Zhikui Ren6d3ad582020-09-11 21:25:59 -070063static CPUInfoMap cpuInfoMap = {};
Zhikui Ren18a5ab92020-09-01 21:35:20 -070064
Jonathan Doman2285be42021-03-08 14:54:12 -080065/**
66 * Simple aggregate to define an external D-Bus property which needs to be set
67 * by this application.
68 */
69struct CpuProperty
70{
71 std::string object;
72 std::string interface;
73 std::string name;
74 std::string value;
75};
76
77/**
78 * List of properties we want to set on other D-Bus objects. This list is kept
79 * around so that if any target objects are removed+readded, then we can set the
80 * values again.
81 */
82static std::list<CpuProperty> propertiesToSet;
83
84static std::ostream& logStream(int cpu)
85{
86 return std::cerr << "[CPU " << cpu << "] ";
87}
88
89static void
90 setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
91 size_t cpu, const std::string& interface,
92 const std::string& propName, const std::string& propVal);
93static void
94 setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
95 size_t cpu, const CpuProperty& newProp);
96static void createCpuUpdatedMatch(
97 const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu);
Zhikui Ren18a5ab92020-09-01 21:35:20 -070098
99static std::optional<std::string> readSSpec(uint8_t bus, uint8_t slaveAddr,
100 uint8_t regAddr, size_t count)
101{
102 unsigned long funcs = 0;
103 std::string devPath = "/dev/i2c-" + std::to_string(bus);
104
105 int fd = ::open(devPath.c_str(), O_RDWR);
106 if (fd < 0)
107 {
108 phosphor::logging::log<phosphor::logging::level::ERR>(
109 "Error in open!",
110 phosphor::logging::entry("PATH=%s", devPath.c_str()),
111 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
112 return std::nullopt;
113 }
114
115 if (::ioctl(fd, I2C_FUNCS, &funcs) < 0)
116 {
117 phosphor::logging::log<phosphor::logging::level::ERR>(
118 "Error in I2C_FUNCS!",
119 phosphor::logging::entry("PATH=%s", devPath.c_str()),
120 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
121 ::close(fd);
122 return std::nullopt;
123 }
124
125 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
126 {
127 phosphor::logging::log<phosphor::logging::level::ERR>(
128 "i2c bus does not support read!",
129 phosphor::logging::entry("PATH=%s", devPath.c_str()),
130 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
131 ::close(fd);
132 return std::nullopt;
133 }
134
135 if (::ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
136 {
137 phosphor::logging::log<phosphor::logging::level::ERR>(
138 "Error in I2C_SLAVE_FORCE!",
139 phosphor::logging::entry("PATH=%s", devPath.c_str()),
140 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
141 ::close(fd);
142 return std::nullopt;
143 }
144
145 int value = 0;
146 std::string sspec;
147 sspec.reserve(count);
148
149 for (size_t i = 0; i < count; i++)
150 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700151 value = ::i2c_smbus_read_byte_data(fd, regAddr + i);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700152 if (value < 0)
153 {
154 phosphor::logging::log<phosphor::logging::level::ERR>(
155 "Error in i2c read!",
156 phosphor::logging::entry("PATH=%s", devPath.c_str()),
157 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
158 ::close(fd);
159 return std::nullopt;
160 }
161 if (!std::isprint(static_cast<unsigned char>(value)))
162 {
163 phosphor::logging::log<phosphor::logging::level::ERR>(
164 "Non printable value in sspec, ignored.");
165 continue;
166 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700167 // sspec always starts with S,
168 // if not assume it is QDF string which starts at offset 2
169 if (i == 0 && static_cast<unsigned char>(value) != 'S')
170 {
171 i = 1;
172 continue;
173 }
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700174 sspec.push_back(static_cast<unsigned char>(value));
175 }
176 ::close(fd);
Jonathan Doman2285be42021-03-08 14:54:12 -0800177
178 if (sspec.size() < 4)
179 {
180 return std::nullopt;
181 }
182
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700183 return sspec;
184}
185
Jonathan Doman2285be42021-03-08 14:54:12 -0800186/**
187 * Higher level SSpec logic.
188 * This handles retrying the PIROM reads until two subsequent reads are
189 * successful and return matching data. When we have confidence that the data
190 * read is correct, then set the property on D-Bus.
191 *
192 * @param[in,out] conn D-Bus connection.
193 * @param[in] cpuInfo CPU to read from.
194 */
195static void
196 tryReadSSpec(const std::shared_ptr<sdbusplus::asio::connection>& conn,
197 const std::shared_ptr<CPUInfo>& cpuInfo)
198{
199 static int failedReads = 0;
200
201 std::optional<std::string> newSSpec =
202 readSSpec(cpuInfo->i2cBus, cpuInfo->i2cDevice, sspecRegAddr, sspecSize);
203 logStream(cpuInfo->id) << "SSpec read status: "
204 << static_cast<bool>(newSSpec) << "\n";
205 if (newSSpec && newSSpec == cpuInfo->sSpec)
206 {
207 setCpuProperty(conn, cpuInfo->id, assetInterfaceName, "Model",
208 *newSSpec);
209 return;
210 }
211
212 // If this read failed, back off for a little longer so that hopefully the
213 // transient condition affecting PIROM reads will pass, but give up after
214 // several consecutive failures. But if this read looked OK, try again
215 // sooner to confirm it.
216 int retrySeconds;
217 if (newSSpec)
218 {
219 retrySeconds = 1;
220 failedReads = 0;
221 cpuInfo->sSpec = *newSSpec;
222 }
223 else
224 {
225 retrySeconds = 5;
226 if (++failedReads > 10)
227 {
228 logStream(cpuInfo->id) << "PIROM Read failed too many times\n";
229 return;
230 }
231 }
232
233 auto sspecTimer = std::make_shared<boost::asio::steady_timer>(
234 conn->get_io_context(), std::chrono::seconds(retrySeconds));
235 sspecTimer->async_wait(
236 [sspecTimer, conn, cpuInfo](boost::system::error_code ec) {
237 if (ec)
238 {
239 return;
240 }
241 tryReadSSpec(conn, cpuInfo);
242 });
243}
244
245/**
246 * Add a D-Bus property to the global list, and attempt to set it by calling
247 * `setDbusProperty`.
248 *
249 * @param[in,out] conn D-Bus connection.
250 * @param[in] cpu 1-based CPU index.
251 * @param[in] interface Interface to set.
252 * @param[in] propName Property to set.
253 * @param[in] propVal Value to set.
254 */
255static void
256 setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
257 size_t cpu, const std::string& interface,
258 const std::string& propName, const std::string& propVal)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700259{
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700260 // cpuId from configuration is one based as
261 // dbus object path used by smbios is 0 based
262 const std::string objectPath = cpuPath + std::to_string(cpu - 1);
Jonathan Doman2285be42021-03-08 14:54:12 -0800263
264 // Can switch to emplace_back if you define a CpuProperty constructor.
265 propertiesToSet.push_back(
266 CpuProperty{objectPath, interface, propName, propVal});
267
268 setDbusProperty(conn, cpu, propertiesToSet.back());
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700269}
270
Jonathan Doman2285be42021-03-08 14:54:12 -0800271/**
272 * Set a D-Bus property which is already contained in the global list, and also
273 * setup a D-Bus match to make sure the target property stays correct.
274 *
275 * @param[in,out] conn D-Bus connection.
276 * @param[in] cpu 1-baesd CPU index.
277 * @param[in] newProp Property to set.
278 */
279static void
280 setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
281 size_t cpu, const CpuProperty& newProp)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700282{
Jonathan Doman2285be42021-03-08 14:54:12 -0800283 createCpuUpdatedMatch(conn, cpu);
284 conn->async_method_call(
285 [](const boost::system::error_code ec) {
286 if (ec)
287 {
288 phosphor::logging::log<phosphor::logging::level::ERR>(
289 "Cannot set CPU property!");
290 return;
291 }
292 },
293 cpuProcessName, newProp.object.c_str(),
294 "org.freedesktop.DBus.Properties", "Set", newProp.interface,
295 newProp.name, std::variant<std::string>{newProp.value});
296}
297
298/**
299 * Set up a D-Bus match (if one does not already exist) to watch for any new
300 * interfaces on the cpu object. When new interfaces are added, re-send all
301 * properties targeting that object/interface.
302 *
303 * @param[in,out] conn D-Bus connection.
304 * @param[in] cpu 1-based CPU index.
305 */
306static void createCpuUpdatedMatch(
307 const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu)
308{
309 static boost::container::flat_map<size_t,
310 std::unique_ptr<sdbusplus::bus::match_t>>
311 cpuUpdatedMatch;
312
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700313 if (cpuUpdatedMatch[cpu])
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700314 {
315 return;
316 }
317
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700318 const std::string objectPath = cpuPath + std::to_string(cpu - 1);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700319
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700320 cpuUpdatedMatch.insert_or_assign(
321 cpu,
322 std::make_unique<sdbusplus::bus::match::match>(
323 static_cast<sdbusplus::bus::bus&>(*conn),
324 sdbusplus::bus::match::rules::interfacesAdded() +
325 sdbusplus::bus::match::rules::argNpath(0, objectPath.c_str()),
Jonathan Doman2285be42021-03-08 14:54:12 -0800326 [conn, cpu](sdbusplus::message::message& msg) {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700327 sdbusplus::message::object_path objectName;
328 boost::container::flat_map<
329 std::string,
330 boost::container::flat_map<
331 std::string, std::variant<std::string, uint64_t>>>
332 msgData;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700333
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700334 msg.read(objectName, msgData);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700335
Jonathan Doman2285be42021-03-08 14:54:12 -0800336 // Go through all the property changes, and retry all of them
337 // targeting this object/interface which was just added.
338 for (const CpuProperty& prop : propertiesToSet)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700339 {
Jonathan Doman2285be42021-03-08 14:54:12 -0800340 if (prop.object == objectName &&
341 msgData.contains(prop.interface))
342 {
343 setDbusProperty(conn, cpu, prop);
344 }
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700345 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700346 }));
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700347}
348
349static void
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700350 getProcessorInfo(boost::asio::io_service& io,
351 const std::shared_ptr<sdbusplus::asio::connection>& conn,
352 const size_t& cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700353{
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700354 if (cpuInfoMap.find(cpu) == cpuInfoMap.end() || cpuInfoMap[cpu] == nullptr)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700355 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700356 std::cerr << "No information found for cpu " << cpu << "\n";
357 return;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700358 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700359
Jonathan Doman2285be42021-03-08 14:54:12 -0800360 std::shared_ptr<CPUInfo> cpuInfo = cpuInfoMap[cpu];
361
362 if (cpuInfo->id != cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700363 {
Jonathan Doman2285be42021-03-08 14:54:12 -0800364 std::cerr << "Incorrect CPU id " << (unsigned)cpuInfo->id << " expect "
365 << cpu << "\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700366 return;
367 }
368
Jonathan Doman2285be42021-03-08 14:54:12 -0800369 uint8_t cpuAddr = cpuInfo->peciAddr;
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700370
371 uint8_t cc = 0;
372 CPUModel model{};
373 uint8_t stepping = 0;
374
Jonathan Doman0a385372021-03-08 17:04:13 -0800375 // Wait for POST to complete to ensure that BIOS has time to enable the
376 // PPIN. Before BIOS enables it, we would get a 0x90 CC on PECI.
377 if (hostState != HostState::postComplete ||
378 peci_GetCPUID(cpuAddr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700379 {
380 // Start the PECI check loop
381 auto waitTimer = std::make_shared<boost::asio::steady_timer>(io);
382 waitTimer->expires_after(
Jonathan Doman0a385372021-03-08 17:04:13 -0800383 std::chrono::seconds(cpu_info::peciCheckInterval));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700384
385 waitTimer->async_wait(
386 [waitTimer, &io, conn, cpu](const boost::system::error_code& ec) {
387 if (ec)
388 {
389 // operation_aborted is expected if timer is canceled
390 // before completion.
391 if (ec != boost::asio::error::operation_aborted)
392 {
393 phosphor::logging::log<phosphor::logging::level::ERR>(
394 "info update timer async_wait failed ",
395 phosphor::logging::entry("EC=0x%x", ec.value()));
396 }
397 return;
398 }
399 getProcessorInfo(io, conn, cpu);
400 });
401 return;
402 }
403
404 switch (model)
405 {
406 case icx:
407 {
408 // PPIN can be read through PCS 19
409 static constexpr uint8_t u8Size = 4; // default to a DWORD
410 static constexpr uint8_t u8PPINPkgIndex = 19;
411 static constexpr uint16_t u16PPINPkgParamHigh = 2;
412 static constexpr uint16_t u16PPINPkgParamLow = 1;
413 uint64_t cpuPPIN = 0;
414 uint32_t u32PkgValue = 0;
415
416 int ret =
417 peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamLow,
418 u8Size, (uint8_t*)&u32PkgValue, &cc);
419 if (0 != ret)
420 {
421 phosphor::logging::log<phosphor::logging::level::ERR>(
422 "peci read package config failed at address",
423 phosphor::logging::entry("PECIADDR=0x%x",
424 (unsigned)cpuAddr),
425 phosphor::logging::entry("CC=0x%x", cc));
426 u32PkgValue = 0;
427 }
428
429 cpuPPIN = u32PkgValue;
430 ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamHigh,
431 u8Size, (uint8_t*)&u32PkgValue, &cc);
432 if (0 != ret)
433 {
434 phosphor::logging::log<phosphor::logging::level::ERR>(
435 "peci read package config failed at address",
436 phosphor::logging::entry("PECIADDR=0x%x",
437 (unsigned)cpuAddr),
438 phosphor::logging::entry("CC=0x%x", cc));
439 cpuPPIN = 0;
440 u32PkgValue = 0;
441 }
442
443 cpuPPIN |= static_cast<uint64_t>(u32PkgValue) << 32;
444
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700445 // set SerialNumber if cpuPPIN is valid
446 if (0 != cpuPPIN)
447 {
448 std::stringstream stream;
449 stream << std::hex << cpuPPIN;
450 std::string serialNumber(stream.str());
Jonathan Doman5b285892021-03-03 13:10:58 -0800451 cpuInfo->uniqueIdentifier(serialNumber);
452 // Signal that the iface is added now so that ObjectMapper and
453 // others can find it.
454 cpuInfo->emit_added();
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700455 }
456
Jonathan Doman2285be42021-03-08 14:54:12 -0800457 tryReadSSpec(conn, cpuInfo);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700458 break;
459 }
460 default:
461 phosphor::logging::log<phosphor::logging::level::INFO>(
462 "in-compatible cpu for cpu asset info");
463 break;
464 }
465}
466
467/**
468 * Get cpu and pirom address
469 */
470static void
471 getCpuAddress(boost::asio::io_service& io,
472 const std::shared_ptr<sdbusplus::asio::connection>& conn,
473 const std::string& service, const std::string& object,
474 const std::string& interface)
475{
476 conn->async_method_call(
477 [&io, conn](boost::system::error_code ec,
478 const boost::container::flat_map<
479 std::string,
480 std::variant<std::string, uint64_t, uint32_t, uint16_t,
481 std::vector<std::string>>>& properties) {
482 const uint64_t* value = nullptr;
483 uint8_t peciAddress = 0;
484 uint8_t i2cBus = defaultI2cBus;
485 uint8_t i2cDevice;
486 bool i2cDeviceFound = false;
487 size_t cpu = 0;
488
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700489 if (ec)
490 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700491 std::cerr << "DBUS response error " << ec.value() << ": "
492 << ec.message() << "\n";
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700493 return;
494 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700495
496 for (const auto& property : properties)
497 {
498 std::cerr << "property " << property.first << "\n";
499 if (property.first == "Address")
500 {
501 value = std::get_if<uint64_t>(&property.second);
502 if (value != nullptr)
503 {
504 peciAddress = static_cast<uint8_t>(*value);
505 }
506 }
507 if (property.first == "CpuID")
508 {
509 value = std::get_if<uint64_t>(&property.second);
510 if (value != nullptr)
511 {
512 cpu = static_cast<size_t>(*value);
513 }
514 }
515 if (property.first == "PiromI2cAddress")
516 {
517 value = std::get_if<uint64_t>(&property.second);
518 if (value != nullptr)
519 {
520 i2cDevice = static_cast<uint8_t>(*value);
521 i2cDeviceFound = true;
522 }
523 }
524 if (property.first == "PiromI2cBus")
525 {
526 value = std::get_if<uint64_t>(&property.second);
527 if (value != nullptr)
528 {
529 i2cBus = static_cast<uint8_t>(*value);
530 }
531 }
532 }
533
534 ///\todo replace this with present + power state
535 if (cpu != 0 && peciAddress != 0)
536 {
537 if (!i2cDeviceFound)
538 {
539 i2cDevice = defaultI2cSlaveAddr0 + cpu - 1;
540 }
541 cpuInfoMap.insert_or_assign(
Jonathan Doman5b285892021-03-03 13:10:58 -0800542 cpu, std::make_shared<CPUInfo>(*conn, cpu, peciAddress,
543 i2cBus, i2cDevice));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700544
545 getProcessorInfo(io, conn, cpu);
546 }
547 },
548 service, object, "org.freedesktop.DBus.Properties", "GetAll",
549 interface);
550}
551
552/**
553 * D-Bus client: to get platform specific configs
554 */
555static void getCpuConfiguration(
556 boost::asio::io_service& io,
557 const std::shared_ptr<sdbusplus::asio::connection>& conn,
558 sdbusplus::asio::object_server& objServer)
559{
560 // Get the Cpu configuration
561 // In case it's not available, set a match for it
562 static std::unique_ptr<sdbusplus::bus::match::match> cpuConfigMatch =
563 std::make_unique<sdbusplus::bus::match::match>(
564 *conn,
565 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
566 "PropertiesChanged',arg0='xyz.openbmc_project."
567 "Configuration.XeonCPU'",
568 [&io, conn, &objServer](sdbusplus::message::message& msg) {
569 std::cerr << "get cpu configuration match\n";
570 static boost::asio::steady_timer filterTimer(io);
571 filterTimer.expires_after(
572 std::chrono::seconds(configCheckInterval));
573
574 filterTimer.async_wait(
575 [&io, conn,
576 &objServer](const boost::system::error_code& ec) {
577 if (ec == boost::asio::error::operation_aborted)
578 {
579 return; // we're being canceled
580 }
581 else if (ec)
582 {
583 std::cerr << "Error: " << ec.message() << "\n";
584 return;
585 }
586 getCpuConfiguration(io, conn, objServer);
587 });
588 });
589
590 conn->async_method_call(
591 [&io, conn](
592 boost::system::error_code ec,
593 const std::vector<std::pair<
594 std::string,
595 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
596 subtree) {
597 if constexpr (debug)
598 std::cerr << "async_method_call callback\n";
599
600 if (ec)
601 {
602 std::cerr << "error with async_method_call\n";
603 return;
604 }
605 if (subtree.empty())
606 {
607 // No config data yet, so wait for the match
608 return;
609 }
610
611 for (const auto& object : subtree)
612 {
613 for (const auto& service : object.second)
614 {
615 getCpuAddress(io, conn, service.first, object.first,
616 "xyz.openbmc_project.Configuration.XeonCPU");
617 }
618 }
619 if constexpr (debug)
620 std::cerr << "getCpuConfiguration callback complete\n";
621
622 return;
623 },
624 "xyz.openbmc_project.ObjectMapper",
625 "/xyz/openbmc_project/object_mapper",
626 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
627 "/xyz/openbmc_project/", 0,
628 std::array<const char*, 1>{
629 "xyz.openbmc_project.Configuration.XeonCPU"});
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700630}
631
632} // namespace cpu_info
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700633
634int main(int argc, char* argv[])
635{
636 // setup connection to dbus
637 boost::asio::io_service io;
638 std::shared_ptr<sdbusplus::asio::connection> conn =
639 std::make_shared<sdbusplus::asio::connection>(io);
640
641 // CPUInfo Object
Jonathan Doman0a385372021-03-08 17:04:13 -0800642 conn->request_name(cpu_info::cpuInfoObject);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700643 sdbusplus::asio::object_server server =
644 sdbusplus::asio::object_server(conn);
645 sdbusplus::bus::bus& bus = static_cast<sdbusplus::bus::bus&>(*conn);
646 sdbusplus::server::manager::manager objManager(
647 bus, "/xyz/openbmc_project/inventory");
648
Jonathan Doman703a1852020-11-11 13:04:02 -0800649 cpu_info::hostStateSetup(conn);
650
Jonathan Doman94c94bf2020-10-05 23:25:45 -0700651 cpu_info::sst::init(io, conn);
652
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700653 // shared_ptr conn is global for the service
654 // const reference of conn is passed to async calls
Jonathan Doman0a385372021-03-08 17:04:13 -0800655 cpu_info::getCpuConfiguration(io, conn, server);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700656
657 io.run();
658
659 return 0;
660}