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