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