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