blob: 9860a00bb45e21e210a5f8b3074a15a946fe9122 [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"
Zhikui Ren18a5ab92020-09-01 21:35:20 -070019
20#include <errno.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <sys/ioctl.h>
24
25#include <boost/asio/io_service.hpp>
26#include <boost/asio/steady_timer.hpp>
Jason M. Bills1e1ca732022-09-21 12:37:52 -070027#include <boost/container/flat_map.hpp>
Zhikui Ren18a5ab92020-09-01 21:35:20 -070028
Zhikui Ren6d3ad582020-09-11 21:25:59 -070029#include <iostream>
Jonathan Doman2285be42021-03-08 14:54:12 -080030#include <list>
Zhikui Ren18a5ab92020-09-01 21:35:20 -070031#include <optional>
32#include <sstream>
33#include <string>
34
35extern "C"
36{
37#include <i2c/smbus.h>
38#include <linux/i2c-dev.h>
39}
40
Jonathan Doman4e1cf092024-03-08 19:57:56 -080041#if PECI_ENABLED
42#include "speed_select.hpp"
43
Zhikui Ren18a5ab92020-09-01 21:35:20 -070044#include <peci.h>
Jonathan Doman4e1cf092024-03-08 19:57:56 -080045#endif
Zhikui Ren18a5ab92020-09-01 21:35:20 -070046
47#include <phosphor-logging/log.hpp>
48#include <sdbusplus/asio/object_server.hpp>
49
Zhikui Ren18a5ab92020-09-01 21:35:20 -070050namespace cpu_info
51{
Zhikui Ren6d3ad582020-09-11 21:25:59 -070052static constexpr bool debug = false;
Jonathan Doman2285be42021-03-08 14:54:12 -080053static constexpr const char* assetInterfaceName =
Zhikui Ren18a5ab92020-09-01 21:35:20 -070054 "xyz.openbmc_project.Inventory.Decorator.Asset";
55static constexpr const char* cpuProcessName =
56 "xyz.openbmc_project.Smbios.MDR_V2";
57
Zhikui Ren6d3ad582020-09-11 21:25:59 -070058// constants for reading SSPEC or QDF string from PIROM
Jason M. Billsb86e4f12024-04-01 13:19:19 -070059// Currently, they are the same for platforms with Ice Lake
Zhikui Ren6d3ad582020-09-11 21:25:59 -070060static constexpr uint8_t defaultI2cBus = 13;
61static constexpr uint8_t defaultI2cSlaveAddr0 = 0x50;
62static constexpr uint8_t sspecRegAddr = 0xd;
63static constexpr uint8_t sspecSize = 6;
Zhikui Ren18a5ab92020-09-01 21:35:20 -070064
Zhikui Ren6d3ad582020-09-11 21:25:59 -070065using CPUInfoMap = boost::container::flat_map<size_t, std::shared_ptr<CPUInfo>>;
Zhikui Ren18a5ab92020-09-01 21:35:20 -070066
Zhikui Ren6d3ad582020-09-11 21:25:59 -070067static CPUInfoMap cpuInfoMap = {};
Zhikui Ren18a5ab92020-09-01 21:35:20 -070068
Jonathan Doman2285be42021-03-08 14:54:12 -080069/**
70 * Simple aggregate to define an external D-Bus property which needs to be set
71 * by this application.
72 */
73struct CpuProperty
74{
75 std::string object;
76 std::string interface;
77 std::string name;
78 std::string value;
79};
80
81/**
82 * List of properties we want to set on other D-Bus objects. This list is kept
Manojkiran Eda0fe13ab2024-06-17 14:55:10 +053083 * around so that if any target objects are removed+re-added, then we can set
84 * the values again.
Jonathan Doman2285be42021-03-08 14:54:12 -080085 */
86static std::list<CpuProperty> propertiesToSet;
87
88static std::ostream& logStream(int cpu)
89{
90 return std::cerr << "[CPU " << cpu << "] ";
91}
92
93static void
94 setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
95 size_t cpu, const std::string& interface,
96 const std::string& propName, const std::string& propVal);
97static void
98 setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
99 size_t cpu, const CpuProperty& newProp);
100static void createCpuUpdatedMatch(
101 const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700102
103static std::optional<std::string> readSSpec(uint8_t bus, uint8_t slaveAddr,
104 uint8_t regAddr, size_t count)
105{
106 unsigned long funcs = 0;
107 std::string devPath = "/dev/i2c-" + std::to_string(bus);
108
109 int fd = ::open(devPath.c_str(), O_RDWR);
110 if (fd < 0)
111 {
112 phosphor::logging::log<phosphor::logging::level::ERR>(
113 "Error in open!",
114 phosphor::logging::entry("PATH=%s", devPath.c_str()),
115 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
116 return std::nullopt;
117 }
118
119 if (::ioctl(fd, I2C_FUNCS, &funcs) < 0)
120 {
121 phosphor::logging::log<phosphor::logging::level::ERR>(
122 "Error in I2C_FUNCS!",
123 phosphor::logging::entry("PATH=%s", devPath.c_str()),
124 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
125 ::close(fd);
126 return std::nullopt;
127 }
128
129 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
130 {
131 phosphor::logging::log<phosphor::logging::level::ERR>(
132 "i2c bus does not support read!",
133 phosphor::logging::entry("PATH=%s", devPath.c_str()),
134 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
135 ::close(fd);
136 return std::nullopt;
137 }
138
139 if (::ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
140 {
141 phosphor::logging::log<phosphor::logging::level::ERR>(
142 "Error in I2C_SLAVE_FORCE!",
143 phosphor::logging::entry("PATH=%s", devPath.c_str()),
144 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
145 ::close(fd);
146 return std::nullopt;
147 }
148
149 int value = 0;
150 std::string sspec;
151 sspec.reserve(count);
152
153 for (size_t i = 0; i < count; i++)
154 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700155 value = ::i2c_smbus_read_byte_data(fd, regAddr + i);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700156 if (value < 0)
157 {
158 phosphor::logging::log<phosphor::logging::level::ERR>(
159 "Error in i2c read!",
160 phosphor::logging::entry("PATH=%s", devPath.c_str()),
161 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
162 ::close(fd);
163 return std::nullopt;
164 }
165 if (!std::isprint(static_cast<unsigned char>(value)))
166 {
167 phosphor::logging::log<phosphor::logging::level::ERR>(
168 "Non printable value in sspec, ignored.");
169 continue;
170 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700171 // sspec always starts with S,
172 // if not assume it is QDF string which starts at offset 2
173 if (i == 0 && static_cast<unsigned char>(value) != 'S')
174 {
175 i = 1;
176 continue;
177 }
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700178 sspec.push_back(static_cast<unsigned char>(value));
179 }
180 ::close(fd);
Jonathan Doman2285be42021-03-08 14:54:12 -0800181
182 if (sspec.size() < 4)
183 {
184 return std::nullopt;
185 }
186
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700187 return sspec;
188}
189
Jonathan Doman2285be42021-03-08 14:54:12 -0800190/**
191 * Higher level SSpec logic.
192 * This handles retrying the PIROM reads until two subsequent reads are
193 * successful and return matching data. When we have confidence that the data
194 * read is correct, then set the property on D-Bus.
Jonathan Doman2285be42021-03-08 14:54:12 -0800195 */
196static void
197 tryReadSSpec(const std::shared_ptr<sdbusplus::asio::connection>& conn,
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800198 size_t cpuIndex)
Jonathan Doman2285be42021-03-08 14:54:12 -0800199{
200 static int failedReads = 0;
201
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800202 auto cpuInfoIt = cpuInfoMap.find(cpuIndex);
203 if (cpuInfoIt == cpuInfoMap.end())
204 {
205 return;
206 }
207 auto cpuInfo = cpuInfoIt->second;
208
Jonathan Doman2285be42021-03-08 14:54:12 -0800209 std::optional<std::string> newSSpec =
210 readSSpec(cpuInfo->i2cBus, cpuInfo->i2cDevice, sspecRegAddr, sspecSize);
211 logStream(cpuInfo->id) << "SSpec read status: "
212 << static_cast<bool>(newSSpec) << "\n";
213 if (newSSpec && newSSpec == cpuInfo->sSpec)
214 {
215 setCpuProperty(conn, cpuInfo->id, assetInterfaceName, "Model",
216 *newSSpec);
217 return;
218 }
219
220 // If this read failed, back off for a little longer so that hopefully the
221 // transient condition affecting PIROM reads will pass, but give up after
222 // several consecutive failures. But if this read looked OK, try again
223 // sooner to confirm it.
224 int retrySeconds;
225 if (newSSpec)
226 {
227 retrySeconds = 1;
228 failedReads = 0;
229 cpuInfo->sSpec = *newSSpec;
230 }
231 else
232 {
233 retrySeconds = 5;
234 if (++failedReads > 10)
235 {
236 logStream(cpuInfo->id) << "PIROM Read failed too many times\n";
237 return;
238 }
239 }
240
241 auto sspecTimer = std::make_shared<boost::asio::steady_timer>(
242 conn->get_io_context(), std::chrono::seconds(retrySeconds));
243 sspecTimer->async_wait(
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800244 [sspecTimer, conn, cpuIndex](boost::system::error_code ec) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500245 if (ec)
246 {
247 return;
248 }
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800249 tryReadSSpec(conn, cpuIndex);
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500250 });
Jonathan Doman2285be42021-03-08 14:54:12 -0800251}
252
253/**
254 * Add a D-Bus property to the global list, and attempt to set it by calling
255 * `setDbusProperty`.
256 *
257 * @param[in,out] conn D-Bus connection.
258 * @param[in] cpu 1-based CPU index.
259 * @param[in] interface Interface to set.
260 * @param[in] propName Property to set.
261 * @param[in] propVal Value to set.
262 */
263static void
264 setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
265 size_t cpu, const std::string& interface,
266 const std::string& propName, const std::string& propVal)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700267{
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700268 // cpuId from configuration is one based as
269 // dbus object path used by smbios is 0 based
270 const std::string objectPath = cpuPath + std::to_string(cpu - 1);
Jonathan Doman2285be42021-03-08 14:54:12 -0800271
272 // Can switch to emplace_back if you define a CpuProperty constructor.
273 propertiesToSet.push_back(
274 CpuProperty{objectPath, interface, propName, propVal});
275
276 setDbusProperty(conn, cpu, propertiesToSet.back());
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700277}
278
Jonathan Doman2285be42021-03-08 14:54:12 -0800279/**
280 * Set a D-Bus property which is already contained in the global list, and also
281 * setup a D-Bus match to make sure the target property stays correct.
282 *
283 * @param[in,out] conn D-Bus connection.
284 * @param[in] cpu 1-baesd CPU index.
285 * @param[in] newProp Property to set.
286 */
287static void
288 setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn,
289 size_t cpu, const CpuProperty& newProp)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700290{
Jonathan Doman2285be42021-03-08 14:54:12 -0800291 createCpuUpdatedMatch(conn, cpu);
292 conn->async_method_call(
293 [](const boost::system::error_code ec) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500294 if (ec)
295 {
296 phosphor::logging::log<phosphor::logging::level::ERR>(
297 "Cannot set CPU property!");
298 return;
299 }
Patrick Williamsbadedf12023-10-20 11:19:42 -0500300 },
Jonathan Doman2285be42021-03-08 14:54:12 -0800301 cpuProcessName, newProp.object.c_str(),
302 "org.freedesktop.DBus.Properties", "Set", newProp.interface,
303 newProp.name, std::variant<std::string>{newProp.value});
304}
305
306/**
307 * Set up a D-Bus match (if one does not already exist) to watch for any new
308 * interfaces on the cpu object. When new interfaces are added, re-send all
309 * properties targeting that object/interface.
310 *
311 * @param[in,out] conn D-Bus connection.
312 * @param[in] cpu 1-based CPU index.
313 */
314static void createCpuUpdatedMatch(
315 const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu)
316{
317 static boost::container::flat_map<size_t,
318 std::unique_ptr<sdbusplus::bus::match_t>>
319 cpuUpdatedMatch;
320
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700321 if (cpuUpdatedMatch[cpu])
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700322 {
323 return;
324 }
325
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700326 const std::string objectPath = cpuPath + std::to_string(cpu - 1);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700327
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700328 cpuUpdatedMatch.insert_or_assign(
329 cpu,
Patrick Williams77b9c472022-07-22 19:26:57 -0500330 std::make_unique<sdbusplus::bus::match_t>(
331 static_cast<sdbusplus::bus_t&>(*conn),
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700332 sdbusplus::bus::match::rules::interfacesAdded() +
333 sdbusplus::bus::match::rules::argNpath(0, objectPath.c_str()),
Patrick Williams77b9c472022-07-22 19:26:57 -0500334 [conn, cpu](sdbusplus::message_t& msg) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500335 sdbusplus::message::object_path objectName;
336 boost::container::flat_map<
337 std::string, boost::container::flat_map<
338 std::string, std::variant<std::string, uint64_t>>>
339 msgData;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700340
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500341 msg.read(objectName, msgData);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700342
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500343 // Go through all the property changes, and retry all of them
344 // targeting this object/interface which was just added.
345 for (const CpuProperty& prop : propertiesToSet)
346 {
347 if (prop.object == objectName && msgData.contains(prop.interface))
348 {
349 setDbusProperty(conn, cpu, prop);
350 }
351 }
Patrick Williamsbadedf12023-10-20 11:19:42 -0500352 }));
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700353}
354
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800355#if PECI_ENABLED
356static void getPPIN(boost::asio::io_service& io,
357 const std::shared_ptr<sdbusplus::asio::connection>& conn,
358 const size_t& cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700359{
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700360 if (cpuInfoMap.find(cpu) == cpuInfoMap.end() || cpuInfoMap[cpu] == nullptr)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700361 {
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700362 std::cerr << "No information found for cpu " << cpu << "\n";
363 return;
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700364 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700365
Jonathan Doman2285be42021-03-08 14:54:12 -0800366 std::shared_ptr<CPUInfo> cpuInfo = cpuInfoMap[cpu];
367
368 if (cpuInfo->id != cpu)
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700369 {
Jonathan Doman2285be42021-03-08 14:54:12 -0800370 std::cerr << "Incorrect CPU id " << (unsigned)cpuInfo->id << " expect "
371 << cpu << "\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700372 return;
373 }
374
Jonathan Doman2285be42021-03-08 14:54:12 -0800375 uint8_t cpuAddr = cpuInfo->peciAddr;
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700376
377 uint8_t cc = 0;
378 CPUModel model{};
379 uint8_t stepping = 0;
380
Jonathan Doman0a385372021-03-08 17:04:13 -0800381 // Wait for POST to complete to ensure that BIOS has time to enable the
382 // PPIN. Before BIOS enables it, we would get a 0x90 CC on PECI.
383 if (hostState != HostState::postComplete ||
384 peci_GetCPUID(cpuAddr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700385 {
386 // Start the PECI check loop
387 auto waitTimer = std::make_shared<boost::asio::steady_timer>(io);
388 waitTimer->expires_after(
Jonathan Doman0a385372021-03-08 17:04:13 -0800389 std::chrono::seconds(cpu_info::peciCheckInterval));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700390
391 waitTimer->async_wait(
392 [waitTimer, &io, conn, cpu](const boost::system::error_code& ec) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500393 if (ec)
394 {
395 // operation_aborted is expected if timer is canceled
396 // before completion.
397 if (ec != boost::asio::error::operation_aborted)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700398 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500399 phosphor::logging::log<phosphor::logging::level::ERR>(
400 "info update timer async_wait failed ",
401 phosphor::logging::entry("EC=0x%x", ec.value()));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700402 }
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500403 return;
404 }
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800405 getPPIN(io, conn, cpu);
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500406 });
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700407 return;
408 }
409
410 switch (model)
411 {
Jason M. Billsb86e4f12024-04-01 13:19:19 -0700412 case iceLake:
413 case iceLakeD:
414 case sapphireRapids:
415 case emeraldRapids:
416 case graniteRapids:
417 case graniteRapidsD:
418 case sierraForest:
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700419 {
420 // PPIN can be read through PCS 19
421 static constexpr uint8_t u8Size = 4; // default to a DWORD
422 static constexpr uint8_t u8PPINPkgIndex = 19;
423 static constexpr uint16_t u16PPINPkgParamHigh = 2;
424 static constexpr uint16_t u16PPINPkgParamLow = 1;
425 uint64_t cpuPPIN = 0;
426 uint32_t u32PkgValue = 0;
427
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500428 int ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex,
429 u16PPINPkgParamLow, u8Size,
430 (uint8_t*)&u32PkgValue, &cc);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700431 if (0 != ret)
432 {
433 phosphor::logging::log<phosphor::logging::level::ERR>(
434 "peci read package config failed at address",
435 phosphor::logging::entry("PECIADDR=0x%x",
436 (unsigned)cpuAddr),
437 phosphor::logging::entry("CC=0x%x", cc));
438 u32PkgValue = 0;
439 }
440
441 cpuPPIN = u32PkgValue;
442 ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamHigh,
443 u8Size, (uint8_t*)&u32PkgValue, &cc);
444 if (0 != ret)
445 {
446 phosphor::logging::log<phosphor::logging::level::ERR>(
447 "peci read package config failed at address",
448 phosphor::logging::entry("PECIADDR=0x%x",
449 (unsigned)cpuAddr),
450 phosphor::logging::entry("CC=0x%x", cc));
451 cpuPPIN = 0;
452 u32PkgValue = 0;
453 }
454
455 cpuPPIN |= static_cast<uint64_t>(u32PkgValue) << 32;
456
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700457 // set SerialNumber if cpuPPIN is valid
458 if (0 != cpuPPIN)
459 {
460 std::stringstream stream;
461 stream << std::hex << cpuPPIN;
462 std::string serialNumber(stream.str());
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800463 cpuInfo->publishUUID(*conn, serialNumber);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700464 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700465 break;
466 }
467 default:
468 phosphor::logging::log<phosphor::logging::level::INFO>(
469 "in-compatible cpu for cpu asset info");
470 break;
471 }
472}
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800473#endif
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700474
475/**
476 * Get cpu and pirom address
477 */
478static void
479 getCpuAddress(boost::asio::io_service& io,
480 const std::shared_ptr<sdbusplus::asio::connection>& conn,
481 const std::string& service, const std::string& object,
482 const std::string& interface)
483{
484 conn->async_method_call(
485 [&io, conn](boost::system::error_code ec,
486 const boost::container::flat_map<
487 std::string,
488 std::variant<std::string, uint64_t, uint32_t, uint16_t,
489 std::vector<std::string>>>& properties) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500490 const uint64_t* value = nullptr;
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800491 std::optional<uint8_t> peciAddress;
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500492 uint8_t i2cBus = defaultI2cBus;
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800493 std::optional<uint8_t> i2cDevice;
494 std::optional<size_t> cpu;
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700495
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500496 if (ec)
497 {
498 std::cerr << "DBUS response error " << ec.value() << ": "
499 << ec.message() << "\n";
500 return;
501 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700502
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500503 for (const auto& property : properties)
504 {
505 std::cerr << "property " << property.first << "\n";
506 if (property.first == "Address")
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700507 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500508 value = std::get_if<uint64_t>(&property.second);
509 if (value != nullptr)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700510 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500511 peciAddress = static_cast<uint8_t>(*value);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700512 }
513 }
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500514 if (property.first == "CpuID")
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700515 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500516 value = std::get_if<uint64_t>(&property.second);
517 if (value != nullptr)
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700518 {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500519 cpu = static_cast<size_t>(*value);
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700520 }
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700521 }
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500522 if (property.first == "PiromI2cAddress")
523 {
524 value = std::get_if<uint64_t>(&property.second);
525 if (value != nullptr)
526 {
527 i2cDevice = static_cast<uint8_t>(*value);
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500528 }
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
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800540 if (!cpu || !peciAddress)
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500541 {
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800542 return;
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500543 }
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800544
545 if (!i2cDevice)
546 {
547 i2cDevice = defaultI2cSlaveAddr0 + *cpu - 1;
548 }
549
550 auto key = cpuInfoMap.find(*cpu);
551
552 if (key != cpuInfoMap.end())
553 {
554 cpuInfoMap.erase(key);
555 }
556
557 cpuInfoMap.emplace(*cpu, std::make_shared<CPUInfo>(*cpu, *peciAddress,
558 i2cBus, *i2cDevice));
559
560 tryReadSSpec(conn, *cpu);
561
562#if PECI_ENABLED
563 getPPIN(io, conn, *cpu);
564#endif
Patrick Williamsbadedf12023-10-20 11:19:42 -0500565 },
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700566 service, object, "org.freedesktop.DBus.Properties", "GetAll",
567 interface);
568}
569
570/**
571 * D-Bus client: to get platform specific configs
572 */
573static void getCpuConfiguration(
574 boost::asio::io_service& io,
575 const std::shared_ptr<sdbusplus::asio::connection>& conn,
576 sdbusplus::asio::object_server& objServer)
577{
578 // Get the Cpu configuration
579 // In case it's not available, set a match for it
Patrick Williams77b9c472022-07-22 19:26:57 -0500580 static std::unique_ptr<sdbusplus::bus::match_t> cpuConfigMatch =
581 std::make_unique<sdbusplus::bus::match_t>(
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700582 *conn,
583 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
584 "PropertiesChanged',arg0='xyz.openbmc_project."
585 "Configuration.XeonCPU'",
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700586 [&io, conn, &objServer](sdbusplus::message_t& /* msg */) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500587 std::cerr << "get cpu configuration match\n";
588 static boost::asio::steady_timer filterTimer(io);
589 filterTimer.expires_after(std::chrono::seconds(configCheckInterval));
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700590
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500591 filterTimer.async_wait(
592 [&io, conn, &objServer](const boost::system::error_code& ec) {
593 if (ec == boost::asio::error::operation_aborted)
594 {
595 return; // we're being canceled
596 }
597 else if (ec)
598 {
599 std::cerr << "Error: " << ec.message() << "\n";
600 return;
601 }
602 getCpuConfiguration(io, conn, objServer);
603 });
Patrick Williamsbadedf12023-10-20 11:19:42 -0500604 });
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700605
606 conn->async_method_call(
607 [&io, conn](
608 boost::system::error_code ec,
609 const std::vector<std::pair<
610 std::string,
611 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
612 subtree) {
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500613 if constexpr (debug)
614 std::cerr << "async_method_call callback\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700615
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500616 if (ec)
617 {
618 std::cerr << "error with async_method_call\n";
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700619 return;
Patrick Williamsc39d3df2023-05-10 07:51:14 -0500620 }
621 if (subtree.empty())
622 {
623 // No config data yet, so wait for the match
624 return;
625 }
626
627 for (const auto& object : subtree)
628 {
629 for (const auto& service : object.second)
630 {
631 getCpuAddress(io, conn, service.first, object.first,
632 "xyz.openbmc_project.Configuration.XeonCPU");
633 }
634 }
635 if constexpr (debug)
636 std::cerr << "getCpuConfiguration callback complete\n";
637
638 return;
Patrick Williamsbadedf12023-10-20 11:19:42 -0500639 },
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700640 "xyz.openbmc_project.ObjectMapper",
641 "/xyz/openbmc_project/object_mapper",
642 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
643 "/xyz/openbmc_project/", 0,
644 std::array<const char*, 1>{
645 "xyz.openbmc_project.Configuration.XeonCPU"});
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700646}
647
648} // namespace cpu_info
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700649
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700650int main()
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700651{
652 // setup connection to dbus
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700653 boost::asio::io_service& io = cpu_info::dbus::getIOContext();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700654 std::shared_ptr<sdbusplus::asio::connection> conn =
Jonathan Doman16a2ced2021-11-01 11:13:22 -0700655 cpu_info::dbus::getConnection();
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700656
657 // CPUInfo Object
Jonathan Doman0a385372021-03-08 17:04:13 -0800658 conn->request_name(cpu_info::cpuInfoObject);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700659 sdbusplus::asio::object_server server =
660 sdbusplus::asio::object_server(conn);
Patrick Williams77b9c472022-07-22 19:26:57 -0500661 sdbusplus::bus_t& bus = static_cast<sdbusplus::bus_t&>(*conn);
662 sdbusplus::server::manager_t objManager(bus,
663 "/xyz/openbmc_project/inventory");
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700664
Jonathan Doman703a1852020-11-11 13:04:02 -0800665 cpu_info::hostStateSetup(conn);
666
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800667#if PECI_ENABLED
Jonathan Doman49ea8302022-05-26 14:29:46 -0700668 cpu_info::sst::init();
Jonathan Doman4e1cf092024-03-08 19:57:56 -0800669#endif
Jonathan Doman94c94bf2020-10-05 23:25:45 -0700670
Zhikui Ren6d3ad582020-09-11 21:25:59 -0700671 // shared_ptr conn is global for the service
672 // const reference of conn is passed to async calls
Jonathan Doman0a385372021-03-08 17:04:13 -0800673 cpu_info::getCpuConfiguration(io, conn, server);
Zhikui Ren18a5ab92020-09-01 21:35:20 -0700674
675 io.run();
676
677 return 0;
678}