xref: /openbmc/smbios-mdr/src/cpuinfo_main.cpp (revision 0a385373)
118a5ab91SZhikui Ren /*
218a5ab91SZhikui Ren // Copyright (c) 2020 Intel Corporation
318a5ab91SZhikui Ren //
418a5ab91SZhikui Ren // Licensed under the Apache License, Version 2.0 (the "License");
518a5ab91SZhikui Ren // you may not use this file except in compliance with the License.
618a5ab91SZhikui Ren // You may obtain a copy of the License at
718a5ab91SZhikui Ren //
818a5ab91SZhikui Ren //      http://www.apache.org/licenses/LICENSE-2.0
918a5ab91SZhikui Ren //
1018a5ab91SZhikui Ren // Unless required by applicable law or agreed to in writing, software
1118a5ab91SZhikui Ren // distributed under the License is distributed on an "AS IS" BASIS,
1218a5ab91SZhikui Ren // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1318a5ab91SZhikui Ren // See the License for the specific language governing permissions and
1418a5ab91SZhikui Ren // limitations under the License.
1518a5ab91SZhikui Ren */
1618a5ab91SZhikui Ren 
1718a5ab91SZhikui Ren #include "cpuinfo.hpp"
18703a1856SJonathan Doman #include "cpuinfo_utils.hpp"
1994c94bfbSJonathan Doman #include "speed_select.hpp"
2018a5ab91SZhikui Ren 
2118a5ab91SZhikui Ren #include <errno.h>
2218a5ab91SZhikui Ren #include <fcntl.h>
2318a5ab91SZhikui Ren #include <stdio.h>
2418a5ab91SZhikui Ren #include <sys/ioctl.h>
2518a5ab91SZhikui Ren 
2618a5ab91SZhikui Ren #include <boost/asio/io_service.hpp>
2718a5ab91SZhikui Ren #include <boost/asio/steady_timer.hpp>
2818a5ab91SZhikui Ren 
296d3ad586SZhikui Ren #include <iostream>
3018a5ab91SZhikui Ren #include <optional>
3118a5ab91SZhikui Ren #include <sstream>
3218a5ab91SZhikui Ren #include <string>
3318a5ab91SZhikui Ren 
3418a5ab91SZhikui Ren extern "C"
3518a5ab91SZhikui Ren {
3618a5ab91SZhikui Ren #include <i2c/smbus.h>
3718a5ab91SZhikui Ren #include <linux/i2c-dev.h>
3818a5ab91SZhikui Ren }
3918a5ab91SZhikui Ren 
4018a5ab91SZhikui Ren #include <peci.h>
4118a5ab91SZhikui Ren 
4218a5ab91SZhikui Ren #include <phosphor-logging/log.hpp>
4318a5ab91SZhikui Ren #include <sdbusplus/asio/object_server.hpp>
4418a5ab91SZhikui Ren 
4518a5ab91SZhikui Ren namespace cpu_info
4618a5ab91SZhikui Ren {
476d3ad586SZhikui Ren static constexpr bool debug = false;
4818a5ab91SZhikui Ren static constexpr const char* cpuInterfaceName =
4918a5ab91SZhikui Ren     "xyz.openbmc_project.Inventory.Decorator.Asset";
5018a5ab91SZhikui Ren static constexpr const char* cpuProcessName =
5118a5ab91SZhikui Ren     "xyz.openbmc_project.Smbios.MDR_V2";
5218a5ab91SZhikui Ren 
536d3ad586SZhikui Ren // constants for reading SSPEC or QDF string from PIROM
546d3ad586SZhikui Ren // Currently, they are the same for platforms with icx
556d3ad586SZhikui Ren static constexpr uint8_t defaultI2cBus = 13;
566d3ad586SZhikui Ren static constexpr uint8_t defaultI2cSlaveAddr0 = 0x50;
576d3ad586SZhikui Ren static constexpr uint8_t sspecRegAddr = 0xd;
586d3ad586SZhikui Ren static constexpr uint8_t sspecSize = 6;
5918a5ab91SZhikui Ren 
606d3ad586SZhikui Ren using CPUInfoMap = boost::container::flat_map<size_t, std::shared_ptr<CPUInfo>>;
6118a5ab91SZhikui Ren 
626d3ad586SZhikui Ren static CPUInfoMap cpuInfoMap = {};
6318a5ab91SZhikui Ren 
646d3ad586SZhikui Ren static boost::container::flat_map<size_t,
656d3ad586SZhikui Ren                                   std::unique_ptr<sdbusplus::bus::match_t>>
666d3ad586SZhikui Ren     cpuUpdatedMatch = {};
6718a5ab91SZhikui Ren 
6818a5ab91SZhikui Ren static std::optional<std::string> readSSpec(uint8_t bus, uint8_t slaveAddr,
6918a5ab91SZhikui Ren                                             uint8_t regAddr, size_t count)
7018a5ab91SZhikui Ren {
7118a5ab91SZhikui Ren     unsigned long funcs = 0;
7218a5ab91SZhikui Ren     std::string devPath = "/dev/i2c-" + std::to_string(bus);
7318a5ab91SZhikui Ren 
7418a5ab91SZhikui Ren     int fd = ::open(devPath.c_str(), O_RDWR);
7518a5ab91SZhikui Ren     if (fd < 0)
7618a5ab91SZhikui Ren     {
7718a5ab91SZhikui Ren         phosphor::logging::log<phosphor::logging::level::ERR>(
7818a5ab91SZhikui Ren             "Error in open!",
7918a5ab91SZhikui Ren             phosphor::logging::entry("PATH=%s", devPath.c_str()),
8018a5ab91SZhikui Ren             phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
8118a5ab91SZhikui Ren         return std::nullopt;
8218a5ab91SZhikui Ren     }
8318a5ab91SZhikui Ren 
8418a5ab91SZhikui Ren     if (::ioctl(fd, I2C_FUNCS, &funcs) < 0)
8518a5ab91SZhikui Ren     {
8618a5ab91SZhikui Ren         phosphor::logging::log<phosphor::logging::level::ERR>(
8718a5ab91SZhikui Ren             "Error in I2C_FUNCS!",
8818a5ab91SZhikui Ren             phosphor::logging::entry("PATH=%s", devPath.c_str()),
8918a5ab91SZhikui Ren             phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
9018a5ab91SZhikui Ren         ::close(fd);
9118a5ab91SZhikui Ren         return std::nullopt;
9218a5ab91SZhikui Ren     }
9318a5ab91SZhikui Ren 
9418a5ab91SZhikui Ren     if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
9518a5ab91SZhikui Ren     {
9618a5ab91SZhikui Ren         phosphor::logging::log<phosphor::logging::level::ERR>(
9718a5ab91SZhikui Ren             "i2c bus does not support read!",
9818a5ab91SZhikui Ren             phosphor::logging::entry("PATH=%s", devPath.c_str()),
9918a5ab91SZhikui Ren             phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
10018a5ab91SZhikui Ren         ::close(fd);
10118a5ab91SZhikui Ren         return std::nullopt;
10218a5ab91SZhikui Ren     }
10318a5ab91SZhikui Ren 
10418a5ab91SZhikui Ren     if (::ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
10518a5ab91SZhikui Ren     {
10618a5ab91SZhikui Ren         phosphor::logging::log<phosphor::logging::level::ERR>(
10718a5ab91SZhikui Ren             "Error in I2C_SLAVE_FORCE!",
10818a5ab91SZhikui Ren             phosphor::logging::entry("PATH=%s", devPath.c_str()),
10918a5ab91SZhikui Ren             phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
11018a5ab91SZhikui Ren         ::close(fd);
11118a5ab91SZhikui Ren         return std::nullopt;
11218a5ab91SZhikui Ren     }
11318a5ab91SZhikui Ren 
11418a5ab91SZhikui Ren     int value = 0;
11518a5ab91SZhikui Ren     std::string sspec;
11618a5ab91SZhikui Ren     sspec.reserve(count);
11718a5ab91SZhikui Ren 
11818a5ab91SZhikui Ren     for (size_t i = 0; i < count; i++)
11918a5ab91SZhikui Ren     {
1206d3ad586SZhikui Ren         value = ::i2c_smbus_read_byte_data(fd, regAddr + i);
12118a5ab91SZhikui Ren         if (value < 0)
12218a5ab91SZhikui Ren         {
12318a5ab91SZhikui Ren             phosphor::logging::log<phosphor::logging::level::ERR>(
12418a5ab91SZhikui Ren                 "Error in i2c read!",
12518a5ab91SZhikui Ren                 phosphor::logging::entry("PATH=%s", devPath.c_str()),
12618a5ab91SZhikui Ren                 phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr));
12718a5ab91SZhikui Ren             ::close(fd);
12818a5ab91SZhikui Ren             return std::nullopt;
12918a5ab91SZhikui Ren         }
13018a5ab91SZhikui Ren         if (!std::isprint(static_cast<unsigned char>(value)))
13118a5ab91SZhikui Ren         {
13218a5ab91SZhikui Ren             phosphor::logging::log<phosphor::logging::level::ERR>(
13318a5ab91SZhikui Ren                 "Non printable value in sspec, ignored.");
13418a5ab91SZhikui Ren             continue;
13518a5ab91SZhikui Ren         }
1366d3ad586SZhikui Ren         // sspec always starts with S,
1376d3ad586SZhikui Ren         // if not assume it is QDF string which starts at offset 2
1386d3ad586SZhikui Ren         if (i == 0 && static_cast<unsigned char>(value) != 'S')
1396d3ad586SZhikui Ren         {
1406d3ad586SZhikui Ren             i = 1;
1416d3ad586SZhikui Ren             continue;
1426d3ad586SZhikui Ren         }
14318a5ab91SZhikui Ren         sspec.push_back(static_cast<unsigned char>(value));
14418a5ab91SZhikui Ren     }
14518a5ab91SZhikui Ren     ::close(fd);
14618a5ab91SZhikui Ren     return sspec;
14718a5ab91SZhikui Ren }
14818a5ab91SZhikui Ren 
14918a5ab91SZhikui Ren static void setAssetProperty(
1506d3ad586SZhikui Ren     const std::shared_ptr<sdbusplus::asio::connection>& conn, const int& cpu,
15118a5ab91SZhikui Ren     const std::vector<std::pair<std::string, std::string>>& propValues)
15218a5ab91SZhikui Ren {
1536d3ad586SZhikui Ren     // cpuId from configuration is one based as
1546d3ad586SZhikui Ren     // dbus object path used by smbios is 0 based
1556d3ad586SZhikui Ren     const std::string objectPath = cpuPath + std::to_string(cpu - 1);
15618a5ab91SZhikui Ren     for (const auto& prop : propValues)
15718a5ab91SZhikui Ren     {
15818a5ab91SZhikui Ren         conn->async_method_call(
15918a5ab91SZhikui Ren             [](const boost::system::error_code ec) {
16018a5ab91SZhikui Ren                 if (ec)
16118a5ab91SZhikui Ren                 {
16218a5ab91SZhikui Ren                     phosphor::logging::log<phosphor::logging::level::ERR>(
16318a5ab91SZhikui Ren                         "Cannot get CPU property!");
16418a5ab91SZhikui Ren                     return;
16518a5ab91SZhikui Ren                 }
16618a5ab91SZhikui Ren             },
16718a5ab91SZhikui Ren             cpuProcessName, objectPath.c_str(),
16818a5ab91SZhikui Ren             "org.freedesktop.DBus.Properties", "Set", cpuInterfaceName,
16918a5ab91SZhikui Ren             prop.first.c_str(), std::variant<std::string>{prop.second});
17018a5ab91SZhikui Ren     }
17118a5ab91SZhikui Ren }
17218a5ab91SZhikui Ren 
17318a5ab91SZhikui Ren static void createCpuUpdatedMatch(
1746d3ad586SZhikui Ren     const std::shared_ptr<sdbusplus::asio::connection>& conn, const int cpu,
17518a5ab91SZhikui Ren     const std::vector<std::pair<std::string, std::string>>& propValues)
17618a5ab91SZhikui Ren {
1776d3ad586SZhikui Ren     if (cpuUpdatedMatch[cpu])
17818a5ab91SZhikui Ren     {
17918a5ab91SZhikui Ren         return;
18018a5ab91SZhikui Ren     }
18118a5ab91SZhikui Ren 
1826d3ad586SZhikui Ren     const std::string objectPath = cpuPath + std::to_string(cpu - 1);
18318a5ab91SZhikui Ren 
1846d3ad586SZhikui Ren     cpuUpdatedMatch.insert_or_assign(
1856d3ad586SZhikui Ren         cpu,
1866d3ad586SZhikui Ren         std::make_unique<sdbusplus::bus::match::match>(
18718a5ab91SZhikui Ren             static_cast<sdbusplus::bus::bus&>(*conn),
18818a5ab91SZhikui Ren             sdbusplus::bus::match::rules::interfacesAdded() +
18918a5ab91SZhikui Ren                 sdbusplus::bus::match::rules::argNpath(0, objectPath.c_str()),
1906d3ad586SZhikui Ren             [conn, cpu, propValues](sdbusplus::message::message& msg) {
191a43eec82SJonathan Doman                 sdbusplus::message::object_path objectName;
19218a5ab91SZhikui Ren                 boost::container::flat_map<
19318a5ab91SZhikui Ren                     std::string,
1946d3ad586SZhikui Ren                     boost::container::flat_map<
1956d3ad586SZhikui Ren                         std::string, std::variant<std::string, uint64_t>>>
19618a5ab91SZhikui Ren                     msgData;
19718a5ab91SZhikui Ren 
19818a5ab91SZhikui Ren                 msg.read(objectName, msgData);
19918a5ab91SZhikui Ren 
20018a5ab91SZhikui Ren                 // Check for xyz.openbmc_project.Inventory.Item.Cpu
20118a5ab91SZhikui Ren                 // interface match
2026d3ad586SZhikui Ren                 const auto& intfFound = msgData.find(cpuInterfaceName);
20318a5ab91SZhikui Ren                 if (msgData.end() != intfFound)
20418a5ab91SZhikui Ren                 {
20518a5ab91SZhikui Ren                     setAssetProperty(conn, cpu, propValues);
20618a5ab91SZhikui Ren                 }
2076d3ad586SZhikui Ren             }));
20818a5ab91SZhikui Ren }
20918a5ab91SZhikui Ren 
2106d3ad586SZhikui Ren static void
2116d3ad586SZhikui Ren     getProcessorInfo(boost::asio::io_service& io,
2126d3ad586SZhikui Ren                      const std::shared_ptr<sdbusplus::asio::connection>& conn,
2136d3ad586SZhikui Ren                      const size_t& cpu)
21418a5ab91SZhikui Ren {
2156d3ad586SZhikui Ren     if (cpuInfoMap.find(cpu) == cpuInfoMap.end() || cpuInfoMap[cpu] == nullptr)
21618a5ab91SZhikui Ren     {
2176d3ad586SZhikui Ren         std::cerr << "No information found for cpu " << cpu << "\n";
2186d3ad586SZhikui Ren         return;
2196d3ad586SZhikui Ren     }
2206d3ad586SZhikui Ren 
2216d3ad586SZhikui Ren     if (cpuInfoMap[cpu]->id != cpu)
2226d3ad586SZhikui Ren     {
2236d3ad586SZhikui Ren         std::cerr << "Incorrect CPU id " << (unsigned)cpuInfoMap[cpu]->id
2246d3ad586SZhikui Ren                   << " expect " << cpu << "\n";
2256d3ad586SZhikui Ren         return;
2266d3ad586SZhikui Ren     }
2276d3ad586SZhikui Ren 
2286d3ad586SZhikui Ren     uint8_t cpuAddr = cpuInfoMap[cpu]->peciAddr;
2296d3ad586SZhikui Ren     uint8_t i2cBus = cpuInfoMap[cpu]->i2cBus;
2306d3ad586SZhikui Ren     uint8_t i2cDevice = cpuInfoMap[cpu]->i2cDevice;
2316d3ad586SZhikui Ren 
23218a5ab91SZhikui Ren     uint8_t cc = 0;
23318a5ab91SZhikui Ren     CPUModel model{};
23418a5ab91SZhikui Ren     uint8_t stepping = 0;
23518a5ab91SZhikui Ren 
236*0a385373SJonathan Doman     // Wait for POST to complete to ensure that BIOS has time to enable the
237*0a385373SJonathan Doman     // PPIN. Before BIOS enables it, we would get a 0x90 CC on PECI.
238*0a385373SJonathan Doman     if (hostState != HostState::postComplete ||
239*0a385373SJonathan Doman         peci_GetCPUID(cpuAddr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
2406d3ad586SZhikui Ren     {
2416d3ad586SZhikui Ren         // Start the PECI check loop
2426d3ad586SZhikui Ren         auto waitTimer = std::make_shared<boost::asio::steady_timer>(io);
2436d3ad586SZhikui Ren         waitTimer->expires_after(
244*0a385373SJonathan Doman             std::chrono::seconds(cpu_info::peciCheckInterval));
24518a5ab91SZhikui Ren 
2466d3ad586SZhikui Ren         waitTimer->async_wait(
2476d3ad586SZhikui Ren             [waitTimer, &io, conn, cpu](const boost::system::error_code& ec) {
2486d3ad586SZhikui Ren                 if (ec)
2496d3ad586SZhikui Ren                 {
2506d3ad586SZhikui Ren                     // operation_aborted is expected if timer is canceled
2516d3ad586SZhikui Ren                     // before completion.
2526d3ad586SZhikui Ren                     if (ec != boost::asio::error::operation_aborted)
25318a5ab91SZhikui Ren                     {
25418a5ab91SZhikui Ren                         phosphor::logging::log<phosphor::logging::level::ERR>(
2556d3ad586SZhikui Ren                             "info update timer async_wait failed ",
2566d3ad586SZhikui Ren                             phosphor::logging::entry("EC=0x%x", ec.value()));
2576d3ad586SZhikui Ren                     }
2586d3ad586SZhikui Ren                     return;
2596d3ad586SZhikui Ren                 }
2606d3ad586SZhikui Ren                 getProcessorInfo(io, conn, cpu);
2616d3ad586SZhikui Ren             });
2626d3ad586SZhikui Ren         return;
26318a5ab91SZhikui Ren     }
26418a5ab91SZhikui Ren 
26518a5ab91SZhikui Ren     switch (model)
26618a5ab91SZhikui Ren     {
26718a5ab91SZhikui Ren         case icx:
26818a5ab91SZhikui Ren         {
2696d3ad586SZhikui Ren             // PPIN can be read through PCS 19
27018a5ab91SZhikui Ren             static constexpr uint8_t u8Size = 4; // default to a DWORD
27118a5ab91SZhikui Ren             static constexpr uint8_t u8PPINPkgIndex = 19;
27218a5ab91SZhikui Ren             static constexpr uint16_t u16PPINPkgParamHigh = 2;
27318a5ab91SZhikui Ren             static constexpr uint16_t u16PPINPkgParamLow = 1;
27418a5ab91SZhikui Ren             uint64_t cpuPPIN = 0;
27518a5ab91SZhikui Ren             uint32_t u32PkgValue = 0;
27618a5ab91SZhikui Ren 
2776d3ad586SZhikui Ren             int ret =
2786d3ad586SZhikui Ren                 peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamLow,
2796d3ad586SZhikui Ren                                  u8Size, (uint8_t*)&u32PkgValue, &cc);
28018a5ab91SZhikui Ren             if (0 != ret)
28118a5ab91SZhikui Ren             {
28218a5ab91SZhikui Ren                 phosphor::logging::log<phosphor::logging::level::ERR>(
28318a5ab91SZhikui Ren                     "peci read package config failed at address",
2846d3ad586SZhikui Ren                     phosphor::logging::entry("PECIADDR=0x%x",
2856d3ad586SZhikui Ren                                              (unsigned)cpuAddr),
28618a5ab91SZhikui Ren                     phosphor::logging::entry("CC=0x%x", cc));
28718a5ab91SZhikui Ren                 u32PkgValue = 0;
28818a5ab91SZhikui Ren             }
28918a5ab91SZhikui Ren 
29018a5ab91SZhikui Ren             cpuPPIN = u32PkgValue;
2916d3ad586SZhikui Ren             ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamHigh,
2926d3ad586SZhikui Ren                                    u8Size, (uint8_t*)&u32PkgValue, &cc);
29318a5ab91SZhikui Ren             if (0 != ret)
29418a5ab91SZhikui Ren             {
29518a5ab91SZhikui Ren                 phosphor::logging::log<phosphor::logging::level::ERR>(
29618a5ab91SZhikui Ren                     "peci read package config failed at address",
2976d3ad586SZhikui Ren                     phosphor::logging::entry("PECIADDR=0x%x",
2986d3ad586SZhikui Ren                                              (unsigned)cpuAddr),
29918a5ab91SZhikui Ren                     phosphor::logging::entry("CC=0x%x", cc));
30018a5ab91SZhikui Ren                 cpuPPIN = 0;
30118a5ab91SZhikui Ren                 u32PkgValue = 0;
30218a5ab91SZhikui Ren             }
30318a5ab91SZhikui Ren 
30418a5ab91SZhikui Ren             cpuPPIN |= static_cast<uint64_t>(u32PkgValue) << 32;
30518a5ab91SZhikui Ren 
30618a5ab91SZhikui Ren             std::vector<std::pair<std::string, std::string>> values;
30718a5ab91SZhikui Ren 
30818a5ab91SZhikui Ren             // set SerialNumber if cpuPPIN is valid
30918a5ab91SZhikui Ren             if (0 != cpuPPIN)
31018a5ab91SZhikui Ren             {
31118a5ab91SZhikui Ren                 std::stringstream stream;
31218a5ab91SZhikui Ren                 stream << std::hex << cpuPPIN;
31318a5ab91SZhikui Ren                 std::string serialNumber(stream.str());
31418a5ab91SZhikui Ren                 // cpuInfo->serialNumber(serialNumber);
31518a5ab91SZhikui Ren                 values.emplace_back(
31618a5ab91SZhikui Ren                     std::make_pair("SerialNumber", serialNumber));
31718a5ab91SZhikui Ren             }
31818a5ab91SZhikui Ren 
3196d3ad586SZhikui Ren             std::optional<std::string> sspec =
3206d3ad586SZhikui Ren                 readSSpec(i2cBus, i2cDevice, sspecRegAddr, sspecSize);
3216d3ad586SZhikui Ren 
32218a5ab91SZhikui Ren             // cpuInfo->model(sspec.value_or(""));
3236d3ad586SZhikui Ren             values.emplace_back(std::make_pair("Model", sspec.value_or("")));
32418a5ab91SZhikui Ren 
32518a5ab91SZhikui Ren             /// \todo in followup patch
32618a5ab91SZhikui Ren             // CPUInfo is created by this service
32718a5ab91SZhikui Ren             // update the below logic, which is needed because smbios
32818a5ab91SZhikui Ren             // service creates the cpu object
3296d3ad586SZhikui Ren             createCpuUpdatedMatch(conn, cpu, values);
3306d3ad586SZhikui Ren             setAssetProperty(conn, cpu, values);
33118a5ab91SZhikui Ren             break;
33218a5ab91SZhikui Ren         }
33318a5ab91SZhikui Ren         default:
33418a5ab91SZhikui Ren             phosphor::logging::log<phosphor::logging::level::INFO>(
33518a5ab91SZhikui Ren                 "in-compatible cpu for cpu asset info");
33618a5ab91SZhikui Ren             break;
33718a5ab91SZhikui Ren     }
33818a5ab91SZhikui Ren }
33918a5ab91SZhikui Ren 
3406d3ad586SZhikui Ren /**
3416d3ad586SZhikui Ren  * Get cpu and pirom address
3426d3ad586SZhikui Ren  */
34318a5ab91SZhikui Ren static void
3446d3ad586SZhikui Ren     getCpuAddress(boost::asio::io_service& io,
3456d3ad586SZhikui Ren                   const std::shared_ptr<sdbusplus::asio::connection>& conn,
3466d3ad586SZhikui Ren                   const std::string& service, const std::string& object,
3476d3ad586SZhikui Ren                   const std::string& interface)
34818a5ab91SZhikui Ren {
3496d3ad586SZhikui Ren     conn->async_method_call(
3506d3ad586SZhikui Ren         [&io, conn](boost::system::error_code ec,
3516d3ad586SZhikui Ren                     const boost::container::flat_map<
3526d3ad586SZhikui Ren                         std::string,
3536d3ad586SZhikui Ren                         std::variant<std::string, uint64_t, uint32_t, uint16_t,
3546d3ad586SZhikui Ren                                      std::vector<std::string>>>& properties) {
3556d3ad586SZhikui Ren             const uint64_t* value = nullptr;
3566d3ad586SZhikui Ren             uint8_t peciAddress = 0;
3576d3ad586SZhikui Ren             uint8_t i2cBus = defaultI2cBus;
3586d3ad586SZhikui Ren             uint8_t i2cDevice;
3596d3ad586SZhikui Ren             bool i2cDeviceFound = false;
3606d3ad586SZhikui Ren             size_t cpu = 0;
3616d3ad586SZhikui Ren 
36218a5ab91SZhikui Ren             if (ec)
36318a5ab91SZhikui Ren             {
3646d3ad586SZhikui Ren                 std::cerr << "DBUS response error " << ec.value() << ": "
3656d3ad586SZhikui Ren                           << ec.message() << "\n";
36618a5ab91SZhikui Ren                 return;
36718a5ab91SZhikui Ren             }
3686d3ad586SZhikui Ren 
3696d3ad586SZhikui Ren             for (const auto& property : properties)
3706d3ad586SZhikui Ren             {
3716d3ad586SZhikui Ren                 std::cerr << "property " << property.first << "\n";
3726d3ad586SZhikui Ren                 if (property.first == "Address")
3736d3ad586SZhikui Ren                 {
3746d3ad586SZhikui Ren                     value = std::get_if<uint64_t>(&property.second);
3756d3ad586SZhikui Ren                     if (value != nullptr)
3766d3ad586SZhikui Ren                     {
3776d3ad586SZhikui Ren                         peciAddress = static_cast<uint8_t>(*value);
37818a5ab91SZhikui Ren                     }
37918a5ab91SZhikui Ren                 }
3806d3ad586SZhikui Ren                 if (property.first == "CpuID")
3816d3ad586SZhikui Ren                 {
3826d3ad586SZhikui Ren                     value = std::get_if<uint64_t>(&property.second);
3836d3ad586SZhikui Ren                     if (value != nullptr)
3846d3ad586SZhikui Ren                     {
3856d3ad586SZhikui Ren                         cpu = static_cast<size_t>(*value);
3866d3ad586SZhikui Ren                     }
3876d3ad586SZhikui Ren                 }
3886d3ad586SZhikui Ren                 if (property.first == "PiromI2cAddress")
3896d3ad586SZhikui Ren                 {
3906d3ad586SZhikui Ren                     value = std::get_if<uint64_t>(&property.second);
3916d3ad586SZhikui Ren                     if (value != nullptr)
3926d3ad586SZhikui Ren                     {
3936d3ad586SZhikui Ren                         i2cDevice = static_cast<uint8_t>(*value);
3946d3ad586SZhikui Ren                         i2cDeviceFound = true;
3956d3ad586SZhikui Ren                     }
3966d3ad586SZhikui Ren                 }
3976d3ad586SZhikui Ren                 if (property.first == "PiromI2cBus")
3986d3ad586SZhikui Ren                 {
3996d3ad586SZhikui Ren                     value = std::get_if<uint64_t>(&property.second);
4006d3ad586SZhikui Ren                     if (value != nullptr)
4016d3ad586SZhikui Ren                     {
4026d3ad586SZhikui Ren                         i2cBus = static_cast<uint8_t>(*value);
4036d3ad586SZhikui Ren                     }
4046d3ad586SZhikui Ren                 }
4056d3ad586SZhikui Ren             }
4066d3ad586SZhikui Ren 
4076d3ad586SZhikui Ren             ///\todo replace this with present + power state
4086d3ad586SZhikui Ren             if (cpu != 0 && peciAddress != 0)
4096d3ad586SZhikui Ren             {
4106d3ad586SZhikui Ren                 if (!i2cDeviceFound)
4116d3ad586SZhikui Ren                 {
4126d3ad586SZhikui Ren                     i2cDevice = defaultI2cSlaveAddr0 + cpu - 1;
4136d3ad586SZhikui Ren                 }
4146d3ad586SZhikui Ren                 cpuInfoMap.insert_or_assign(
4156d3ad586SZhikui Ren                     cpu, std::make_shared<CPUInfo>(cpu, peciAddress, i2cBus,
4166d3ad586SZhikui Ren                                                    i2cDevice));
4176d3ad586SZhikui Ren 
4186d3ad586SZhikui Ren                 getProcessorInfo(io, conn, cpu);
4196d3ad586SZhikui Ren             }
4206d3ad586SZhikui Ren         },
4216d3ad586SZhikui Ren         service, object, "org.freedesktop.DBus.Properties", "GetAll",
4226d3ad586SZhikui Ren         interface);
4236d3ad586SZhikui Ren }
4246d3ad586SZhikui Ren 
4256d3ad586SZhikui Ren /**
4266d3ad586SZhikui Ren  * D-Bus client: to get platform specific configs
4276d3ad586SZhikui Ren  */
4286d3ad586SZhikui Ren static void getCpuConfiguration(
4296d3ad586SZhikui Ren     boost::asio::io_service& io,
4306d3ad586SZhikui Ren     const std::shared_ptr<sdbusplus::asio::connection>& conn,
4316d3ad586SZhikui Ren     sdbusplus::asio::object_server& objServer)
4326d3ad586SZhikui Ren {
4336d3ad586SZhikui Ren     // Get the Cpu configuration
4346d3ad586SZhikui Ren     // In case it's not available, set a match for it
4356d3ad586SZhikui Ren     static std::unique_ptr<sdbusplus::bus::match::match> cpuConfigMatch =
4366d3ad586SZhikui Ren         std::make_unique<sdbusplus::bus::match::match>(
4376d3ad586SZhikui Ren             *conn,
4386d3ad586SZhikui Ren             "type='signal',interface='org.freedesktop.DBus.Properties',member='"
4396d3ad586SZhikui Ren             "PropertiesChanged',arg0='xyz.openbmc_project."
4406d3ad586SZhikui Ren             "Configuration.XeonCPU'",
4416d3ad586SZhikui Ren             [&io, conn, &objServer](sdbusplus::message::message& msg) {
4426d3ad586SZhikui Ren                 std::cerr << "get cpu configuration match\n";
4436d3ad586SZhikui Ren                 static boost::asio::steady_timer filterTimer(io);
4446d3ad586SZhikui Ren                 filterTimer.expires_after(
4456d3ad586SZhikui Ren                     std::chrono::seconds(configCheckInterval));
4466d3ad586SZhikui Ren 
4476d3ad586SZhikui Ren                 filterTimer.async_wait(
4486d3ad586SZhikui Ren                     [&io, conn,
4496d3ad586SZhikui Ren                      &objServer](const boost::system::error_code& ec) {
4506d3ad586SZhikui Ren                         if (ec == boost::asio::error::operation_aborted)
4516d3ad586SZhikui Ren                         {
4526d3ad586SZhikui Ren                             return; // we're being canceled
4536d3ad586SZhikui Ren                         }
4546d3ad586SZhikui Ren                         else if (ec)
4556d3ad586SZhikui Ren                         {
4566d3ad586SZhikui Ren                             std::cerr << "Error: " << ec.message() << "\n";
4576d3ad586SZhikui Ren                             return;
4586d3ad586SZhikui Ren                         }
4596d3ad586SZhikui Ren                         getCpuConfiguration(io, conn, objServer);
4606d3ad586SZhikui Ren                     });
4616d3ad586SZhikui Ren             });
4626d3ad586SZhikui Ren 
4636d3ad586SZhikui Ren     conn->async_method_call(
4646d3ad586SZhikui Ren         [&io, conn](
4656d3ad586SZhikui Ren             boost::system::error_code ec,
4666d3ad586SZhikui Ren             const std::vector<std::pair<
4676d3ad586SZhikui Ren                 std::string,
4686d3ad586SZhikui Ren                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
4696d3ad586SZhikui Ren                 subtree) {
4706d3ad586SZhikui Ren             if constexpr (debug)
4716d3ad586SZhikui Ren                 std::cerr << "async_method_call callback\n";
4726d3ad586SZhikui Ren 
4736d3ad586SZhikui Ren             if (ec)
4746d3ad586SZhikui Ren             {
4756d3ad586SZhikui Ren                 std::cerr << "error with async_method_call\n";
4766d3ad586SZhikui Ren                 return;
4776d3ad586SZhikui Ren             }
4786d3ad586SZhikui Ren             if (subtree.empty())
4796d3ad586SZhikui Ren             {
4806d3ad586SZhikui Ren                 // No config data yet, so wait for the match
4816d3ad586SZhikui Ren                 return;
4826d3ad586SZhikui Ren             }
4836d3ad586SZhikui Ren 
4846d3ad586SZhikui Ren             for (const auto& object : subtree)
4856d3ad586SZhikui Ren             {
4866d3ad586SZhikui Ren                 for (const auto& service : object.second)
4876d3ad586SZhikui Ren                 {
4886d3ad586SZhikui Ren                     getCpuAddress(io, conn, service.first, object.first,
4896d3ad586SZhikui Ren                                   "xyz.openbmc_project.Configuration.XeonCPU");
4906d3ad586SZhikui Ren                 }
4916d3ad586SZhikui Ren             }
4926d3ad586SZhikui Ren             if constexpr (debug)
4936d3ad586SZhikui Ren                 std::cerr << "getCpuConfiguration callback complete\n";
4946d3ad586SZhikui Ren 
4956d3ad586SZhikui Ren             return;
4966d3ad586SZhikui Ren         },
4976d3ad586SZhikui Ren         "xyz.openbmc_project.ObjectMapper",
4986d3ad586SZhikui Ren         "/xyz/openbmc_project/object_mapper",
4996d3ad586SZhikui Ren         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
5006d3ad586SZhikui Ren         "/xyz/openbmc_project/", 0,
5016d3ad586SZhikui Ren         std::array<const char*, 1>{
5026d3ad586SZhikui Ren             "xyz.openbmc_project.Configuration.XeonCPU"});
5036d3ad586SZhikui Ren }
50418a5ab91SZhikui Ren 
50518a5ab91SZhikui Ren } // namespace cpu_info
50618a5ab91SZhikui Ren 
50718a5ab91SZhikui Ren int main(int argc, char* argv[])
50818a5ab91SZhikui Ren {
50918a5ab91SZhikui Ren     // setup connection to dbus
51018a5ab91SZhikui Ren     boost::asio::io_service io;
51118a5ab91SZhikui Ren     std::shared_ptr<sdbusplus::asio::connection> conn =
51218a5ab91SZhikui Ren         std::make_shared<sdbusplus::asio::connection>(io);
51318a5ab91SZhikui Ren 
51418a5ab91SZhikui Ren     // CPUInfo Object
515*0a385373SJonathan Doman     conn->request_name(cpu_info::cpuInfoObject);
51618a5ab91SZhikui Ren     sdbusplus::asio::object_server server =
51718a5ab91SZhikui Ren         sdbusplus::asio::object_server(conn);
51818a5ab91SZhikui Ren     sdbusplus::bus::bus& bus = static_cast<sdbusplus::bus::bus&>(*conn);
51918a5ab91SZhikui Ren     sdbusplus::server::manager::manager objManager(
52018a5ab91SZhikui Ren         bus, "/xyz/openbmc_project/inventory");
52118a5ab91SZhikui Ren 
522703a1856SJonathan Doman     cpu_info::hostStateSetup(conn);
523703a1856SJonathan Doman 
52494c94bfbSJonathan Doman     cpu_info::sst::init(io, conn);
52594c94bfbSJonathan Doman 
5266d3ad586SZhikui Ren     // shared_ptr conn is global for the service
5276d3ad586SZhikui Ren     // const reference of conn is passed to async calls
528*0a385373SJonathan Doman     cpu_info::getCpuConfiguration(io, conn, server);
52918a5ab91SZhikui Ren 
53018a5ab91SZhikui Ren     io.run();
53118a5ab91SZhikui Ren 
53218a5ab91SZhikui Ren     return 0;
53318a5ab91SZhikui Ren }
534