blob: 46331744d2892641333246a3bc04146336732cd1 [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,
Patrick Williams77b9c472022-07-22 19:26:57 -0500322 std::make_unique<sdbusplus::bus::match_t>(
323 static_cast<sdbusplus::bus_t&>(*conn),
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700324 sdbusplus::bus::match::rules::interfacesAdded() +
325 sdbusplus::bus::match::rules::argNpath(0, objectPath.c_str()),
Patrick Williams77b9c472022-07-22 19:26:57 -0500326 [conn, cpu](sdbusplus::message_t& 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:
Jonathan Doman631388e2021-11-04 10:48:35 -0700407 case icxd:
408 case spr:
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700409 {
410 // PPIN can be read through PCS 19
411 static constexpr uint8_t u8Size = 4; // default to a DWORD
412 static constexpr uint8_t u8PPINPkgIndex = 19;
413 static constexpr uint16_t u16PPINPkgParamHigh = 2;
414 static constexpr uint16_t u16PPINPkgParamLow = 1;
415 uint64_t cpuPPIN = 0;
416 uint32_t u32PkgValue = 0;
417
418 int ret =
419 peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamLow,
420 u8Size, (uint8_t*)&u32PkgValue, &cc);
421 if (0 != ret)
422 {
423 phosphor::logging::log<phosphor::logging::level::ERR>(
424 "peci read package config failed at address",
425 phosphor::logging::entry("PECIADDR=0x%x",
426 (unsigned)cpuAddr),
427 phosphor::logging::entry("CC=0x%x", cc));
428 u32PkgValue = 0;
429 }
430
431 cpuPPIN = u32PkgValue;
432 ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamHigh,
433 u8Size, (uint8_t*)&u32PkgValue, &cc);
434 if (0 != ret)
435 {
436 phosphor::logging::log<phosphor::logging::level::ERR>(
437 "peci read package config failed at address",
438 phosphor::logging::entry("PECIADDR=0x%x",
439 (unsigned)cpuAddr),
440 phosphor::logging::entry("CC=0x%x", cc));
441 cpuPPIN = 0;
442 u32PkgValue = 0;
443 }
444
445 cpuPPIN |= static_cast<uint64_t>(u32PkgValue) << 32;
446
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700447 // set SerialNumber if cpuPPIN is valid
448 if (0 != cpuPPIN)
449 {
450 std::stringstream stream;
451 stream << std::hex << cpuPPIN;
452 std::string serialNumber(stream.str());
Jonathan Doman5b285892021-03-03 13:10:58 -0800453 cpuInfo->uniqueIdentifier(serialNumber);
454 // Signal that the iface is added now so that ObjectMapper and
455 // others can find it.
456 cpuInfo->emit_added();
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700457 }
458
Jonathan Doman2285be42021-03-08 14:54:12 -0800459 tryReadSSpec(conn, cpuInfo);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700460 break;
461 }
462 default:
463 phosphor::logging::log<phosphor::logging::level::INFO>(
464 "in-compatible cpu for cpu asset info");
465 break;
466 }
467}
468
469/**
470 * Get cpu and pirom address
471 */
472static void
473 getCpuAddress(boost::asio::io_service& io,
474 const std::shared_ptr<sdbusplus::asio::connection>& conn,
475 const std::string& service, const std::string& object,
476 const std::string& interface)
477{
478 conn->async_method_call(
479 [&io, conn](boost::system::error_code ec,
480 const boost::container::flat_map<
481 std::string,
482 std::variant<std::string, uint64_t, uint32_t, uint16_t,
483 std::vector<std::string>>>& properties) {
484 const uint64_t* value = nullptr;
485 uint8_t peciAddress = 0;
486 uint8_t i2cBus = defaultI2cBus;
487 uint8_t i2cDevice;
488 bool i2cDeviceFound = false;
489 size_t cpu = 0;
490
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700491 if (ec)
492 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700493 std::cerr << "DBUS response error " << ec.value() << ": "
494 << ec.message() << "\n";
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700495 return;
496 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700497
498 for (const auto& property : properties)
499 {
500 std::cerr << "property " << property.first << "\n";
501 if (property.first == "Address")
502 {
503 value = std::get_if<uint64_t>(&property.second);
504 if (value != nullptr)
505 {
506 peciAddress = static_cast<uint8_t>(*value);
507 }
508 }
509 if (property.first == "CpuID")
510 {
511 value = std::get_if<uint64_t>(&property.second);
512 if (value != nullptr)
513 {
514 cpu = static_cast<size_t>(*value);
515 }
516 }
517 if (property.first == "PiromI2cAddress")
518 {
519 value = std::get_if<uint64_t>(&property.second);
520 if (value != nullptr)
521 {
522 i2cDevice = static_cast<uint8_t>(*value);
523 i2cDeviceFound = true;
524 }
525 }
526 if (property.first == "PiromI2cBus")
527 {
528 value = std::get_if<uint64_t>(&property.second);
529 if (value != nullptr)
530 {
531 i2cBus = static_cast<uint8_t>(*value);
532 }
533 }
534 }
535
536 ///\todo replace this with present + power state
537 if (cpu != 0 && peciAddress != 0)
538 {
539 if (!i2cDeviceFound)
540 {
541 i2cDevice = defaultI2cSlaveAddr0 + cpu - 1;
542 }
543 cpuInfoMap.insert_or_assign(
Jonathan Doman5b285892021-03-03 13:10:58 -0800544 cpu, std::make_shared<CPUInfo>(*conn, cpu, peciAddress,
545 i2cBus, i2cDevice));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700546
547 getProcessorInfo(io, conn, cpu);
548 }
549 },
550 service, object, "org.freedesktop.DBus.Properties", "GetAll",
551 interface);
552}
553
554/**
555 * D-Bus client: to get platform specific configs
556 */
557static void getCpuConfiguration(
558 boost::asio::io_service& io,
559 const std::shared_ptr<sdbusplus::asio::connection>& conn,
560 sdbusplus::asio::object_server& objServer)
561{
562 // Get the Cpu configuration
563 // In case it's not available, set a match for it
Patrick Williams77b9c472022-07-22 19:26:57 -0500564 static std::unique_ptr<sdbusplus::bus::match_t> cpuConfigMatch =
565 std::make_unique<sdbusplus::bus::match_t>(
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700566 *conn,
567 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
568 "PropertiesChanged',arg0='xyz.openbmc_project."
569 "Configuration.XeonCPU'",
Patrick Williams77b9c472022-07-22 19:26:57 -0500570 [&io, conn, &objServer](sdbusplus::message_t& msg) {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700571 std::cerr << "get cpu configuration match\n";
572 static boost::asio::steady_timer filterTimer(io);
573 filterTimer.expires_after(
574 std::chrono::seconds(configCheckInterval));
575
576 filterTimer.async_wait(
577 [&io, conn,
578 &objServer](const boost::system::error_code& ec) {
579 if (ec == boost::asio::error::operation_aborted)
580 {
581 return; // we're being canceled
582 }
583 else if (ec)
584 {
585 std::cerr << "Error: " << ec.message() << "\n";
586 return;
587 }
588 getCpuConfiguration(io, conn, objServer);
589 });
590 });
591
592 conn->async_method_call(
593 [&io, conn](
594 boost::system::error_code ec,
595 const std::vector<std::pair<
596 std::string,
597 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
598 subtree) {
599 if constexpr (debug)
600 std::cerr << "async_method_call callback\n";
601
602 if (ec)
603 {
604 std::cerr << "error with async_method_call\n";
605 return;
606 }
607 if (subtree.empty())
608 {
609 // No config data yet, so wait for the match
610 return;
611 }
612
613 for (const auto& object : subtree)
614 {
615 for (const auto& service : object.second)
616 {
617 getCpuAddress(io, conn, service.first, object.first,
618 "xyz.openbmc_project.Configuration.XeonCPU");
619 }
620 }
621 if constexpr (debug)
622 std::cerr << "getCpuConfiguration callback complete\n";
623
624 return;
625 },
626 "xyz.openbmc_project.ObjectMapper",
627 "/xyz/openbmc_project/object_mapper",
628 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
629 "/xyz/openbmc_project/", 0,
630 std::array<const char*, 1>{
631 "xyz.openbmc_project.Configuration.XeonCPU"});
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700632}
633
634} // namespace cpu_info
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700635
636int main(int argc, char* argv[])
637{
638 // setup connection to dbus
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700639 boost::asio::io_service& io = cpu_info::dbus::getIOContext();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700640 std::shared_ptr<sdbusplus::asio::connection> conn =
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700641 cpu_info::dbus::getConnection();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700642
643 // CPUInfo Object
Jonathan Doman0a385372021-03-08 17:04:13 -0800644 conn->request_name(cpu_info::cpuInfoObject);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700645 sdbusplus::asio::object_server server =
646 sdbusplus::asio::object_server(conn);
Patrick Williams77b9c472022-07-22 19:26:57 -0500647 sdbusplus::bus_t& bus = static_cast<sdbusplus::bus_t&>(*conn);
648 sdbusplus::server::manager_t objManager(bus,
649 "/xyz/openbmc_project/inventory");
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700650
Jonathan Doman703a1852020-11-11 13:04:02 -0800651 cpu_info::hostStateSetup(conn);
652
Jonathan Doman49ea8302022-05-26 14:29:46 -0700653 cpu_info::sst::init();
Jonathan Doman94c94bf2020-10-05 23:25:45 -0700654
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700655 // shared_ptr conn is global for the service
656 // const reference of conn is passed to async calls
Jonathan Doman0a385372021-03-08 17:04:13 -0800657 cpu_info::getCpuConfiguration(io, conn, server);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700658
659 io.run();
660
661 return 0;
662}