blob: 51ae8482d59699c703dc7257bfe7493f7915b08a [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) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500238 if (ec)
239 {
240 return;
241 }
242 tryReadSSpec(conn, cpuInfo);
243 });
Jonathan Doman2285be42021-03-08 14:54:12 -0800244}
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) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500287 if (ec)
288 {
289 phosphor::logging::log<phosphor::logging::level::ERR>(
290 "Cannot set CPU property!");
291 return;
292 }
Patrick Williamsbadedf12023-10-20 11:19:42 -0500293 },
Jonathan Doman2285be42021-03-08 14:54:12 -0800294 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) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500328 sdbusplus::message::object_path objectName;
329 boost::container::flat_map<
330 std::string, boost::container::flat_map<
331 std::string, std::variant<std::string, uint64_t>>>
332 msgData;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700333
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500334 msg.read(objectName, msgData);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700335
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500336 // 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)
339 {
340 if (prop.object == objectName && msgData.contains(prop.interface))
341 {
342 setDbusProperty(conn, cpu, prop);
343 }
344 }
Patrick Williamsbadedf12023-10-20 11:19:42 -0500345 }));
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700346}
347
348static void
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700349 getProcessorInfo(boost::asio::io_service& io,
350 const std::shared_ptr<sdbusplus::asio::connection>& conn,
351 const size_t& cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700352{
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700353 if (cpuInfoMap.find(cpu) == cpuInfoMap.end() || cpuInfoMap[cpu] == nullptr)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700354 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700355 std::cerr << "No information found for cpu " << cpu << "\n";
356 return;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700357 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700358
Jonathan Doman2285be42021-03-08 14:54:12 -0800359 std::shared_ptr<CPUInfo> cpuInfo = cpuInfoMap[cpu];
360
361 if (cpuInfo->id != cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700362 {
Jonathan Doman2285be42021-03-08 14:54:12 -0800363 std::cerr << "Incorrect CPU id " << (unsigned)cpuInfo->id << " expect "
364 << cpu << "\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700365 return;
366 }
367
Jonathan Doman2285be42021-03-08 14:54:12 -0800368 uint8_t cpuAddr = cpuInfo->peciAddr;
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700369
370 uint8_t cc = 0;
371 CPUModel model{};
372 uint8_t stepping = 0;
373
Jonathan Doman0a385372021-03-08 17:04:13 -0800374 // Wait for POST to complete to ensure that BIOS has time to enable the
375 // PPIN. Before BIOS enables it, we would get a 0x90 CC on PECI.
376 if (hostState != HostState::postComplete ||
377 peci_GetCPUID(cpuAddr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700378 {
379 // Start the PECI check loop
380 auto waitTimer = std::make_shared<boost::asio::steady_timer>(io);
381 waitTimer->expires_after(
Jonathan Doman0a385372021-03-08 17:04:13 -0800382 std::chrono::seconds(cpu_info::peciCheckInterval));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700383
384 waitTimer->async_wait(
385 [waitTimer, &io, conn, cpu](const boost::system::error_code& ec) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500386 if (ec)
387 {
388 // operation_aborted is expected if timer is canceled
389 // before completion.
390 if (ec != boost::asio::error::operation_aborted)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700391 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500392 phosphor::logging::log<phosphor::logging::level::ERR>(
393 "info update timer async_wait failed ",
394 phosphor::logging::entry("EC=0x%x", ec.value()));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700395 }
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500396 return;
397 }
398 getProcessorInfo(io, conn, cpu);
399 });
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700400 return;
401 }
402
403 switch (model)
404 {
405 case icx:
Jonathan Doman631388e2021-11-04 10:48:35 -0700406 case icxd:
407 case spr:
Jonathan Doman949f6342023-04-20 12:54:50 -0700408 case emr:
Jonathan Domanca2b38a2023-05-08 18:21:07 -0700409 case gnr:
Saitwal, Meghan226357e2023-07-20 15:28:39 +0000410 case gnrd:
Jonathan Domanca2b38a2023-05-08 18:21:07 -0700411 case srf:
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700412 {
413 // PPIN can be read through PCS 19
414 static constexpr uint8_t u8Size = 4; // default to a DWORD
415 static constexpr uint8_t u8PPINPkgIndex = 19;
416 static constexpr uint16_t u16PPINPkgParamHigh = 2;
417 static constexpr uint16_t u16PPINPkgParamLow = 1;
418 uint64_t cpuPPIN = 0;
419 uint32_t u32PkgValue = 0;
420
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500421 int ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex,
422 u16PPINPkgParamLow, u8Size,
423 (uint8_t*)&u32PkgValue, &cc);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700424 if (0 != ret)
425 {
426 phosphor::logging::log<phosphor::logging::level::ERR>(
427 "peci read package config failed at address",
428 phosphor::logging::entry("PECIADDR=0x%x",
429 (unsigned)cpuAddr),
430 phosphor::logging::entry("CC=0x%x", cc));
431 u32PkgValue = 0;
432 }
433
434 cpuPPIN = u32PkgValue;
435 ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamHigh,
436 u8Size, (uint8_t*)&u32PkgValue, &cc);
437 if (0 != ret)
438 {
439 phosphor::logging::log<phosphor::logging::level::ERR>(
440 "peci read package config failed at address",
441 phosphor::logging::entry("PECIADDR=0x%x",
442 (unsigned)cpuAddr),
443 phosphor::logging::entry("CC=0x%x", cc));
444 cpuPPIN = 0;
445 u32PkgValue = 0;
446 }
447
448 cpuPPIN |= static_cast<uint64_t>(u32PkgValue) << 32;
449
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700450 // set SerialNumber if cpuPPIN is valid
451 if (0 != cpuPPIN)
452 {
453 std::stringstream stream;
454 stream << std::hex << cpuPPIN;
455 std::string serialNumber(stream.str());
Jonathan Doman5b285892021-03-03 13:10:58 -0800456 cpuInfo->uniqueIdentifier(serialNumber);
457 // Signal that the iface is added now so that ObjectMapper and
458 // others can find it.
459 cpuInfo->emit_added();
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700460 }
461
Jonathan Doman2285be42021-03-08 14:54:12 -0800462 tryReadSSpec(conn, cpuInfo);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700463 break;
464 }
465 default:
466 phosphor::logging::log<phosphor::logging::level::INFO>(
467 "in-compatible cpu for cpu asset info");
468 break;
469 }
470}
471
472/**
473 * Get cpu and pirom address
474 */
475static void
476 getCpuAddress(boost::asio::io_service& io,
477 const std::shared_ptr<sdbusplus::asio::connection>& conn,
478 const std::string& service, const std::string& object,
479 const std::string& interface)
480{
481 conn->async_method_call(
482 [&io, conn](boost::system::error_code ec,
483 const boost::container::flat_map<
484 std::string,
485 std::variant<std::string, uint64_t, uint32_t, uint16_t,
486 std::vector<std::string>>>& properties) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500487 const uint64_t* value = nullptr;
488 uint8_t peciAddress = 0;
489 uint8_t i2cBus = defaultI2cBus;
490 uint8_t i2cDevice;
491 bool i2cDeviceFound = false;
492 size_t cpu = 0;
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700493
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500494 if (ec)
495 {
496 std::cerr << "DBUS response error " << ec.value() << ": "
497 << ec.message() << "\n";
498 return;
499 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700500
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500501 for (const auto& property : properties)
502 {
503 std::cerr << "property " << property.first << "\n";
504 if (property.first == "Address")
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700505 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500506 value = std::get_if<uint64_t>(&property.second);
507 if (value != nullptr)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700508 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500509 peciAddress = static_cast<uint8_t>(*value);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700510 }
511 }
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500512 if (property.first == "CpuID")
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700513 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500514 value = std::get_if<uint64_t>(&property.second);
515 if (value != nullptr)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700516 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500517 cpu = static_cast<size_t>(*value);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700518 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700519 }
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500520 if (property.first == "PiromI2cAddress")
521 {
522 value = std::get_if<uint64_t>(&property.second);
523 if (value != nullptr)
524 {
525 i2cDevice = static_cast<uint8_t>(*value);
526 i2cDeviceFound = true;
527 }
528 }
529 if (property.first == "PiromI2cBus")
530 {
531 value = std::get_if<uint64_t>(&property.second);
532 if (value != nullptr)
533 {
534 i2cBus = static_cast<uint8_t>(*value);
535 }
536 }
537 }
538
539 ///\todo replace this with present + power state
540 if (cpu != 0 && peciAddress != 0)
541 {
542 if (!i2cDeviceFound)
543 {
544 i2cDevice = defaultI2cSlaveAddr0 + cpu - 1;
545 }
Ankita Vilas Gawade132d0372023-06-19 17:53:30 +0530546
547 auto key = cpuInfoMap.find(cpu);
548
549 if (key != cpuInfoMap.end())
550 {
551 cpuInfoMap.erase(key);
552 }
553
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500554 cpuInfoMap.insert_or_assign(
555 cpu, std::make_shared<CPUInfo>(*conn, cpu, peciAddress, i2cBus,
556 i2cDevice));
557
558 getProcessorInfo(io, conn, cpu);
559 }
Patrick Williamsbadedf12023-10-20 11:19:42 -0500560 },
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700561 service, object, "org.freedesktop.DBus.Properties", "GetAll",
562 interface);
563}
564
565/**
566 * D-Bus client: to get platform specific configs
567 */
568static void getCpuConfiguration(
569 boost::asio::io_service& io,
570 const std::shared_ptr<sdbusplus::asio::connection>& conn,
571 sdbusplus::asio::object_server& objServer)
572{
573 // Get the Cpu configuration
574 // In case it's not available, set a match for it
Patrick Williams77b9c472022-07-22 19:26:57 -0500575 static std::unique_ptr<sdbusplus::bus::match_t> cpuConfigMatch =
576 std::make_unique<sdbusplus::bus::match_t>(
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700577 *conn,
578 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
579 "PropertiesChanged',arg0='xyz.openbmc_project."
580 "Configuration.XeonCPU'",
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700581 [&io, conn, &objServer](sdbusplus::message_t& /* msg */) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500582 std::cerr << "get cpu configuration match\n";
583 static boost::asio::steady_timer filterTimer(io);
584 filterTimer.expires_after(std::chrono::seconds(configCheckInterval));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700585
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500586 filterTimer.async_wait(
587 [&io, conn, &objServer](const boost::system::error_code& ec) {
588 if (ec == boost::asio::error::operation_aborted)
589 {
590 return; // we're being canceled
591 }
592 else if (ec)
593 {
594 std::cerr << "Error: " << ec.message() << "\n";
595 return;
596 }
597 getCpuConfiguration(io, conn, objServer);
598 });
Patrick Williamsbadedf12023-10-20 11:19:42 -0500599 });
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700600
601 conn->async_method_call(
602 [&io, conn](
603 boost::system::error_code ec,
604 const std::vector<std::pair<
605 std::string,
606 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
607 subtree) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500608 if constexpr (debug)
609 std::cerr << "async_method_call callback\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700610
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500611 if (ec)
612 {
613 std::cerr << "error with async_method_call\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700614 return;
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500615 }
616 if (subtree.empty())
617 {
618 // No config data yet, so wait for the match
619 return;
620 }
621
622 for (const auto& object : subtree)
623 {
624 for (const auto& service : object.second)
625 {
626 getCpuAddress(io, conn, service.first, object.first,
627 "xyz.openbmc_project.Configuration.XeonCPU");
628 }
629 }
630 if constexpr (debug)
631 std::cerr << "getCpuConfiguration callback complete\n";
632
633 return;
Patrick Williamsbadedf12023-10-20 11:19:42 -0500634 },
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700635 "xyz.openbmc_project.ObjectMapper",
636 "/xyz/openbmc_project/object_mapper",
637 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
638 "/xyz/openbmc_project/", 0,
639 std::array<const char*, 1>{
640 "xyz.openbmc_project.Configuration.XeonCPU"});
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700641}
642
643} // namespace cpu_info
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700644
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700645int main()
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700646{
647 // setup connection to dbus
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700648 boost::asio::io_service& io = cpu_info::dbus::getIOContext();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700649 std::shared_ptr<sdbusplus::asio::connection> conn =
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700650 cpu_info::dbus::getConnection();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700651
652 // CPUInfo Object
Jonathan Doman0a385372021-03-08 17:04:13 -0800653 conn->request_name(cpu_info::cpuInfoObject);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700654 sdbusplus::asio::object_server server =
655 sdbusplus::asio::object_server(conn);
Patrick Williams77b9c472022-07-22 19:26:57 -0500656 sdbusplus::bus_t& bus = static_cast<sdbusplus::bus_t&>(*conn);
657 sdbusplus::server::manager_t objManager(bus,
658 "/xyz/openbmc_project/inventory");
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700659
Jonathan Doman703a1852020-11-11 13:04:02 -0800660 cpu_info::hostStateSetup(conn);
661
Jonathan Doman49ea8302022-05-26 14:29:46 -0700662 cpu_info::sst::init();
Jonathan Doman94c94bf2020-10-05 23:25:45 -0700663
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700664 // shared_ptr conn is global for the service
665 // const reference of conn is passed to async calls
Jonathan Doman0a385372021-03-08 17:04:13 -0800666 cpu_info::getCpuConfiguration(io, conn, server);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700667
668 io.run();
669
670 return 0;
671}