blob: eac04d51816e96854088c8825653dac2f1f952fd [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>
Jason M. Bills1e1ca732022-09-21 12:37:52 -070028#include <boost/container/flat_map.hpp>
Zhikui Ren18a5ab92020-09-01 21:35:20 -070029
Zhikui Ren6d3ad582020-09-11 21:25:59 -070030#include <iostream>
Jonathan Doman2285be42021-03-08 14:54:12 -080031#include <list>
Zhikui Ren18a5ab92020-09-01 21:35:20 -070032#include <optional>
33#include <sstream>
34#include <string>
35
36extern "C"
37{
38#include <i2c/smbus.h>
39#include <linux/i2c-dev.h>
40}
41
42#include <peci.h>
43
44#include <phosphor-logging/log.hpp>
45#include <sdbusplus/asio/object_server.hpp>
46
Zhikui Ren18a5ab92020-09-01 21:35:20 -070047namespace cpu_info
48{
Zhikui Ren6d3ad582020-09-11 21:25:59 -070049static constexpr bool debug = false;
Jonathan Doman2285be42021-03-08 14:54:12 -080050static constexpr const char* assetInterfaceName =
Zhikui Ren18a5ab92020-09-01 21:35:20 -070051 "xyz.openbmc_project.Inventory.Decorator.Asset";
52static constexpr const char* cpuProcessName =
53 "xyz.openbmc_project.Smbios.MDR_V2";
54
Zhikui Ren6d3ad582020-09-11 21:25:59 -070055// constants for reading SSPEC or QDF string from PIROM
56// Currently, they are the same for platforms with icx
57static constexpr uint8_t defaultI2cBus = 13;
58static constexpr uint8_t defaultI2cSlaveAddr0 = 0x50;
59static constexpr uint8_t sspecRegAddr = 0xd;
60static constexpr uint8_t sspecSize = 6;
Zhikui Ren18a5ab92020-09-01 21:35:20 -070061
Zhikui Ren6d3ad582020-09-11 21:25:59 -070062using CPUInfoMap = boost::container::flat_map<size_t, std::shared_ptr<CPUInfo>>;
Zhikui Ren18a5ab92020-09-01 21:35:20 -070063
Zhikui Ren6d3ad582020-09-11 21:25:59 -070064static CPUInfoMap cpuInfoMap = {};
Zhikui Ren18a5ab92020-09-01 21:35:20 -070065
Jonathan Doman2285be42021-03-08 14:54:12 -080066/**
67 * Simple aggregate to define an external D-Bus property which needs to be set
68 * by this application.
69 */
70struct CpuProperty
71{
72 std::string object;
73 std::string interface;
74 std::string name;
75 std::string value;
76};
77
78/**
79 * List of properties we want to set on other D-Bus objects. This list is kept
80 * around so that if any target objects are removed+readded, then we can set the
81 * values again.
82 */
83static std::list<CpuProperty> propertiesToSet;
84
85static std::ostream& logStream(int cpu)
86{
87 return std::cerr << "[CPU " << cpu << "] ";
88}
89
90static void
91 setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
92 size_t cpu, const std::string& interface,
93 const std::string& propName, const std::string& propVal);
94static void
95 setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
96 size_t cpu, const CpuProperty& newProp);
97static void createCpuUpdatedMatch(
98 const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu);
Zhikui Ren18a5ab92020-09-01 21:35:20 -070099
100static std::optional<std::string> readSSpec(uint8_t bus, uint8_t slaveAddr,
101 uint8_t regAddr, size_t count)
102{
103 unsigned long funcs = 0;
104 std::string devPath = "/dev/i2c-" + std::to_string(bus);
105
106 int fd = ::open(devPath.c_str(), O_RDWR);
107 if (fd < 0)
108 {
109 phosphor::logging::log<phosphor::logging::level::ERR>(
110 "Error in open!",
111 phosphor::logging::entry("PATH=%s", devPath.c_str()),
112 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
113 return std::nullopt;
114 }
115
116 if (::ioctl(fd, I2C_FUNCS, &funcs) < 0)
117 {
118 phosphor::logging::log<phosphor::logging::level::ERR>(
119 "Error in I2C_FUNCS!",
120 phosphor::logging::entry("PATH=%s", devPath.c_str()),
121 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
122 ::close(fd);
123 return std::nullopt;
124 }
125
126 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
127 {
128 phosphor::logging::log<phosphor::logging::level::ERR>(
129 "i2c bus does not support read!",
130 phosphor::logging::entry("PATH=%s", devPath.c_str()),
131 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
132 ::close(fd);
133 return std::nullopt;
134 }
135
136 if (::ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
137 {
138 phosphor::logging::log<phosphor::logging::level::ERR>(
139 "Error in I2C_SLAVE_FORCE!",
140 phosphor::logging::entry("PATH=%s", devPath.c_str()),
141 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
142 ::close(fd);
143 return std::nullopt;
144 }
145
146 int value = 0;
147 std::string sspec;
148 sspec.reserve(count);
149
150 for (size_t i = 0; i < count; i++)
151 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700152 value = ::i2c_smbus_read_byte_data(fd, regAddr + i);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700153 if (value < 0)
154 {
155 phosphor::logging::log<phosphor::logging::level::ERR>(
156 "Error in i2c read!",
157 phosphor::logging::entry("PATH=%s", devPath.c_str()),
158 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
159 ::close(fd);
160 return std::nullopt;
161 }
162 if (!std::isprint(static_cast<unsigned char>(value)))
163 {
164 phosphor::logging::log<phosphor::logging::level::ERR>(
165 "Non printable value in sspec, ignored.");
166 continue;
167 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700168 // sspec always starts with S,
169 // if not assume it is QDF string which starts at offset 2
170 if (i == 0 && static_cast<unsigned char>(value) != 'S')
171 {
172 i = 1;
173 continue;
174 }
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700175 sspec.push_back(static_cast<unsigned char>(value));
176 }
177 ::close(fd);
Jonathan Doman2285be42021-03-08 14:54:12 -0800178
179 if (sspec.size() < 4)
180 {
181 return std::nullopt;
182 }
183
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700184 return sspec;
185}
186
Jonathan Doman2285be42021-03-08 14:54:12 -0800187/**
188 * Higher level SSpec logic.
189 * This handles retrying the PIROM reads until two subsequent reads are
190 * successful and return matching data. When we have confidence that the data
191 * read is correct, then set the property on D-Bus.
192 *
193 * @param[in,out] conn D-Bus connection.
194 * @param[in] cpuInfo CPU to read from.
195 */
196static void
197 tryReadSSpec(const std::shared_ptr<sdbusplus::asio::connection>& conn,
198 const std::shared_ptr<CPUInfo>& cpuInfo)
199{
200 static int failedReads = 0;
201
202 std::optional<std::string> newSSpec =
203 readSSpec(cpuInfo->i2cBus, cpuInfo->i2cDevice, sspecRegAddr, sspecSize);
204 logStream(cpuInfo->id) << "SSpec read status: "
205 << static_cast<bool>(newSSpec) << "\n";
206 if (newSSpec && newSSpec == cpuInfo->sSpec)
207 {
208 setCpuProperty(conn, cpuInfo->id, assetInterfaceName, "Model",
209 *newSSpec);
210 return;
211 }
212
213 // If this read failed, back off for a little longer so that hopefully the
214 // transient condition affecting PIROM reads will pass, but give up after
215 // several consecutive failures. But if this read looked OK, try again
216 // sooner to confirm it.
217 int retrySeconds;
218 if (newSSpec)
219 {
220 retrySeconds = 1;
221 failedReads = 0;
222 cpuInfo->sSpec = *newSSpec;
223 }
224 else
225 {
226 retrySeconds = 5;
227 if (++failedReads > 10)
228 {
229 logStream(cpuInfo->id) << "PIROM Read failed too many times\n";
230 return;
231 }
232 }
233
234 auto sspecTimer = std::make_shared<boost::asio::steady_timer>(
235 conn->get_io_context(), std::chrono::seconds(retrySeconds));
236 sspecTimer->async_wait(
237 [sspecTimer, conn, cpuInfo](boost::system::error_code ec) {
238 if (ec)
239 {
240 return;
241 }
242 tryReadSSpec(conn, cpuInfo);
243 });
244}
245
246/**
247 * Add a D-Bus property to the global list, and attempt to set it by calling
248 * `setDbusProperty`.
249 *
250 * @param[in,out] conn D-Bus connection.
251 * @param[in] cpu 1-based CPU index.
252 * @param[in] interface Interface to set.
253 * @param[in] propName Property to set.
254 * @param[in] propVal Value to set.
255 */
256static void
257 setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
258 size_t cpu, const std::string& interface,
259 const std::string& propName, const std::string& propVal)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700260{
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700261 // cpuId from configuration is one based as
262 // dbus object path used by smbios is 0 based
263 const std::string objectPath = cpuPath + std::to_string(cpu - 1);
Jonathan Doman2285be42021-03-08 14:54:12 -0800264
265 // Can switch to emplace_back if you define a CpuProperty constructor.
266 propertiesToSet.push_back(
267 CpuProperty{objectPath, interface, propName, propVal});
268
269 setDbusProperty(conn, cpu, propertiesToSet.back());
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700270}
271
Jonathan Doman2285be42021-03-08 14:54:12 -0800272/**
273 * Set a D-Bus property which is already contained in the global list, and also
274 * setup a D-Bus match to make sure the target property stays correct.
275 *
276 * @param[in,out] conn D-Bus connection.
277 * @param[in] cpu 1-baesd CPU index.
278 * @param[in] newProp Property to set.
279 */
280static void
281 setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
282 size_t cpu, const CpuProperty& newProp)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700283{
Jonathan Doman2285be42021-03-08 14:54:12 -0800284 createCpuUpdatedMatch(conn, cpu);
285 conn->async_method_call(
286 [](const boost::system::error_code ec) {
287 if (ec)
288 {
289 phosphor::logging::log<phosphor::logging::level::ERR>(
290 "Cannot set CPU property!");
291 return;
292 }
293 },
294 cpuProcessName, newProp.object.c_str(),
295 "org.freedesktop.DBus.Properties", "Set", newProp.interface,
296 newProp.name, std::variant<std::string>{newProp.value});
297}
298
299/**
300 * Set up a D-Bus match (if one does not already exist) to watch for any new
301 * interfaces on the cpu object. When new interfaces are added, re-send all
302 * properties targeting that object/interface.
303 *
304 * @param[in,out] conn D-Bus connection.
305 * @param[in] cpu 1-based CPU index.
306 */
307static void createCpuUpdatedMatch(
308 const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu)
309{
310 static boost::container::flat_map<size_t,
311 std::unique_ptr<sdbusplus::bus::match_t>>
312 cpuUpdatedMatch;
313
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700314 if (cpuUpdatedMatch[cpu])
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700315 {
316 return;
317 }
318
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700319 const std::string objectPath = cpuPath + std::to_string(cpu - 1);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700320
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700321 cpuUpdatedMatch.insert_or_assign(
322 cpu,
Patrick Williams77b9c472022-07-22 19:26:57 -0500323 std::make_unique<sdbusplus::bus::match_t>(
324 static_cast<sdbusplus::bus_t&>(*conn),
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700325 sdbusplus::bus::match::rules::interfacesAdded() +
326 sdbusplus::bus::match::rules::argNpath(0, objectPath.c_str()),
Patrick Williams77b9c472022-07-22 19:26:57 -0500327 [conn, cpu](sdbusplus::message_t& msg) {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700328 sdbusplus::message::object_path objectName;
329 boost::container::flat_map<
330 std::string,
331 boost::container::flat_map<
332 std::string, std::variant<std::string, uint64_t>>>
333 msgData;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700334
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700335 msg.read(objectName, msgData);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700336
Jonathan Doman2285be42021-03-08 14:54:12 -0800337 // Go through all the property changes, and retry all of them
338 // targeting this object/interface which was just added.
339 for (const CpuProperty& prop : propertiesToSet)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700340 {
Jonathan Doman2285be42021-03-08 14:54:12 -0800341 if (prop.object == objectName &&
342 msgData.contains(prop.interface))
343 {
344 setDbusProperty(conn, cpu, prop);
345 }
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700346 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700347 }));
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700348}
349
350static void
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700351 getProcessorInfo(boost::asio::io_service& io,
352 const std::shared_ptr<sdbusplus::asio::connection>& conn,
353 const size_t& cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700354{
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700355 if (cpuInfoMap.find(cpu) == cpuInfoMap.end() || cpuInfoMap[cpu] == nullptr)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700356 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700357 std::cerr << "No information found for cpu " << cpu << "\n";
358 return;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700359 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700360
Jonathan Doman2285be42021-03-08 14:54:12 -0800361 std::shared_ptr<CPUInfo> cpuInfo = cpuInfoMap[cpu];
362
363 if (cpuInfo->id != cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700364 {
Jonathan Doman2285be42021-03-08 14:54:12 -0800365 std::cerr << "Incorrect CPU id " << (unsigned)cpuInfo->id << " expect "
366 << cpu << "\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700367 return;
368 }
369
Jonathan Doman2285be42021-03-08 14:54:12 -0800370 uint8_t cpuAddr = cpuInfo->peciAddr;
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700371
372 uint8_t cc = 0;
373 CPUModel model{};
374 uint8_t stepping = 0;
375
Jonathan Doman0a385372021-03-08 17:04:13 -0800376 // Wait for POST to complete to ensure that BIOS has time to enable the
377 // PPIN. Before BIOS enables it, we would get a 0x90 CC on PECI.
378 if (hostState != HostState::postComplete ||
379 peci_GetCPUID(cpuAddr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700380 {
381 // Start the PECI check loop
382 auto waitTimer = std::make_shared<boost::asio::steady_timer>(io);
383 waitTimer->expires_after(
Jonathan Doman0a385372021-03-08 17:04:13 -0800384 std::chrono::seconds(cpu_info::peciCheckInterval));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700385
386 waitTimer->async_wait(
387 [waitTimer, &io, conn, cpu](const boost::system::error_code& ec) {
388 if (ec)
389 {
390 // operation_aborted is expected if timer is canceled
391 // before completion.
392 if (ec != boost::asio::error::operation_aborted)
393 {
394 phosphor::logging::log<phosphor::logging::level::ERR>(
395 "info update timer async_wait failed ",
396 phosphor::logging::entry("EC=0x%x", ec.value()));
397 }
398 return;
399 }
400 getProcessorInfo(io, conn, cpu);
401 });
402 return;
403 }
404
405 switch (model)
406 {
407 case icx:
Jonathan Doman631388e2021-11-04 10:48:35 -0700408 case icxd:
409 case spr:
Jonathan Doman949f6342023-04-20 12:54:50 -0700410 case emr:
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700411 {
412 // PPIN can be read through PCS 19
413 static constexpr uint8_t u8Size = 4; // default to a DWORD
414 static constexpr uint8_t u8PPINPkgIndex = 19;
415 static constexpr uint16_t u16PPINPkgParamHigh = 2;
416 static constexpr uint16_t u16PPINPkgParamLow = 1;
417 uint64_t cpuPPIN = 0;
418 uint32_t u32PkgValue = 0;
419
420 int ret =
421 peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamLow,
422 u8Size, (uint8_t*)&u32PkgValue, &cc);
423 if (0 != ret)
424 {
425 phosphor::logging::log<phosphor::logging::level::ERR>(
426 "peci read package config failed at address",
427 phosphor::logging::entry("PECIADDR=0x%x",
428 (unsigned)cpuAddr),
429 phosphor::logging::entry("CC=0x%x", cc));
430 u32PkgValue = 0;
431 }
432
433 cpuPPIN = u32PkgValue;
434 ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamHigh,
435 u8Size, (uint8_t*)&u32PkgValue, &cc);
436 if (0 != ret)
437 {
438 phosphor::logging::log<phosphor::logging::level::ERR>(
439 "peci read package config failed at address",
440 phosphor::logging::entry("PECIADDR=0x%x",
441 (unsigned)cpuAddr),
442 phosphor::logging::entry("CC=0x%x", cc));
443 cpuPPIN = 0;
444 u32PkgValue = 0;
445 }
446
447 cpuPPIN |= static_cast<uint64_t>(u32PkgValue) << 32;
448
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700449 // set SerialNumber if cpuPPIN is valid
450 if (0 != cpuPPIN)
451 {
452 std::stringstream stream;
453 stream << std::hex << cpuPPIN;
454 std::string serialNumber(stream.str());
Jonathan Doman5b285892021-03-03 13:10:58 -0800455 cpuInfo->uniqueIdentifier(serialNumber);
456 // Signal that the iface is added now so that ObjectMapper and
457 // others can find it.
458 cpuInfo->emit_added();
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700459 }
460
Jonathan Doman2285be42021-03-08 14:54:12 -0800461 tryReadSSpec(conn, cpuInfo);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700462 break;
463 }
464 default:
465 phosphor::logging::log<phosphor::logging::level::INFO>(
466 "in-compatible cpu for cpu asset info");
467 break;
468 }
469}
470
471/**
472 * Get cpu and pirom address
473 */
474static void
475 getCpuAddress(boost::asio::io_service& io,
476 const std::shared_ptr<sdbusplus::asio::connection>& conn,
477 const std::string& service, const std::string& object,
478 const std::string& interface)
479{
480 conn->async_method_call(
481 [&io, conn](boost::system::error_code ec,
482 const boost::container::flat_map<
483 std::string,
484 std::variant<std::string, uint64_t, uint32_t, uint16_t,
485 std::vector<std::string>>>& properties) {
486 const uint64_t* value = nullptr;
487 uint8_t peciAddress = 0;
488 uint8_t i2cBus = defaultI2cBus;
489 uint8_t i2cDevice;
490 bool i2cDeviceFound = false;
491 size_t cpu = 0;
492
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700493 if (ec)
494 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700495 std::cerr << "DBUS response error " << ec.value() << ": "
496 << ec.message() << "\n";
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700497 return;
498 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700499
500 for (const auto& property : properties)
501 {
502 std::cerr << "property " << property.first << "\n";
503 if (property.first == "Address")
504 {
505 value = std::get_if<uint64_t>(&property.second);
506 if (value != nullptr)
507 {
508 peciAddress = static_cast<uint8_t>(*value);
509 }
510 }
511 if (property.first == "CpuID")
512 {
513 value = std::get_if<uint64_t>(&property.second);
514 if (value != nullptr)
515 {
516 cpu = static_cast<size_t>(*value);
517 }
518 }
519 if (property.first == "PiromI2cAddress")
520 {
521 value = std::get_if<uint64_t>(&property.second);
522 if (value != nullptr)
523 {
524 i2cDevice = static_cast<uint8_t>(*value);
525 i2cDeviceFound = true;
526 }
527 }
528 if (property.first == "PiromI2cBus")
529 {
530 value = std::get_if<uint64_t>(&property.second);
531 if (value != nullptr)
532 {
533 i2cBus = static_cast<uint8_t>(*value);
534 }
535 }
536 }
537
538 ///\todo replace this with present + power state
539 if (cpu != 0 && peciAddress != 0)
540 {
541 if (!i2cDeviceFound)
542 {
543 i2cDevice = defaultI2cSlaveAddr0 + cpu - 1;
544 }
545 cpuInfoMap.insert_or_assign(
Jonathan Doman5b285892021-03-03 13:10:58 -0800546 cpu, std::make_shared<CPUInfo>(*conn, cpu, peciAddress,
547 i2cBus, i2cDevice));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700548
549 getProcessorInfo(io, conn, cpu);
550 }
551 },
552 service, object, "org.freedesktop.DBus.Properties", "GetAll",
553 interface);
554}
555
556/**
557 * D-Bus client: to get platform specific configs
558 */
559static void getCpuConfiguration(
560 boost::asio::io_service& io,
561 const std::shared_ptr<sdbusplus::asio::connection>& conn,
562 sdbusplus::asio::object_server& objServer)
563{
564 // Get the Cpu configuration
565 // In case it's not available, set a match for it
Patrick Williams77b9c472022-07-22 19:26:57 -0500566 static std::unique_ptr<sdbusplus::bus::match_t> cpuConfigMatch =
567 std::make_unique<sdbusplus::bus::match_t>(
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700568 *conn,
569 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
570 "PropertiesChanged',arg0='xyz.openbmc_project."
571 "Configuration.XeonCPU'",
Patrick Williams77b9c472022-07-22 19:26:57 -0500572 [&io, conn, &objServer](sdbusplus::message_t& msg) {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700573 std::cerr << "get cpu configuration match\n";
574 static boost::asio::steady_timer filterTimer(io);
575 filterTimer.expires_after(
576 std::chrono::seconds(configCheckInterval));
577
578 filterTimer.async_wait(
579 [&io, conn,
580 &objServer](const boost::system::error_code& ec) {
581 if (ec == boost::asio::error::operation_aborted)
582 {
583 return; // we're being canceled
584 }
585 else if (ec)
586 {
587 std::cerr << "Error: " << ec.message() << "\n";
588 return;
589 }
590 getCpuConfiguration(io, conn, objServer);
591 });
592 });
593
594 conn->async_method_call(
595 [&io, conn](
596 boost::system::error_code ec,
597 const std::vector<std::pair<
598 std::string,
599 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
600 subtree) {
601 if constexpr (debug)
602 std::cerr << "async_method_call callback\n";
603
604 if (ec)
605 {
606 std::cerr << "error with async_method_call\n";
607 return;
608 }
609 if (subtree.empty())
610 {
611 // No config data yet, so wait for the match
612 return;
613 }
614
615 for (const auto& object : subtree)
616 {
617 for (const auto& service : object.second)
618 {
619 getCpuAddress(io, conn, service.first, object.first,
620 "xyz.openbmc_project.Configuration.XeonCPU");
621 }
622 }
623 if constexpr (debug)
624 std::cerr << "getCpuConfiguration callback complete\n";
625
626 return;
627 },
628 "xyz.openbmc_project.ObjectMapper",
629 "/xyz/openbmc_project/object_mapper",
630 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
631 "/xyz/openbmc_project/", 0,
632 std::array<const char*, 1>{
633 "xyz.openbmc_project.Configuration.XeonCPU"});
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700634}
635
636} // namespace cpu_info
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700637
638int main(int argc, char* argv[])
639{
640 // setup connection to dbus
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700641 boost::asio::io_service& io = cpu_info::dbus::getIOContext();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700642 std::shared_ptr<sdbusplus::asio::connection> conn =
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700643 cpu_info::dbus::getConnection();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700644
645 // CPUInfo Object
Jonathan Doman0a385372021-03-08 17:04:13 -0800646 conn->request_name(cpu_info::cpuInfoObject);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700647 sdbusplus::asio::object_server server =
648 sdbusplus::asio::object_server(conn);
Patrick Williams77b9c472022-07-22 19:26:57 -0500649 sdbusplus::bus_t& bus = static_cast<sdbusplus::bus_t&>(*conn);
650 sdbusplus::server::manager_t objManager(bus,
651 "/xyz/openbmc_project/inventory");
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700652
Jonathan Doman703a1852020-11-11 13:04:02 -0800653 cpu_info::hostStateSetup(conn);
654
Jonathan Doman49ea8302022-05-26 14:29:46 -0700655 cpu_info::sst::init();
Jonathan Doman94c94bf2020-10-05 23:25:45 -0700656
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700657 // shared_ptr conn is global for the service
658 // const reference of conn is passed to async calls
Jonathan Doman0a385372021-03-08 17:04:13 -0800659 cpu_info::getCpuConfiguration(io, conn, server);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700660
661 io.run();
662
663 return 0;
664}