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> 281e1ca736SJason M. Bills #include <boost/container/flat_map.hpp> 2918a5ab91SZhikui Ren 306d3ad586SZhikui Ren #include <iostream> 312285be4fSJonathan Doman #include <list> 3218a5ab91SZhikui Ren #include <optional> 3318a5ab91SZhikui Ren #include <sstream> 3418a5ab91SZhikui Ren #include <string> 3518a5ab91SZhikui Ren 3618a5ab91SZhikui Ren extern "C" 3718a5ab91SZhikui Ren { 3818a5ab91SZhikui Ren #include <i2c/smbus.h> 3918a5ab91SZhikui Ren #include <linux/i2c-dev.h> 4018a5ab91SZhikui Ren } 4118a5ab91SZhikui Ren 4218a5ab91SZhikui Ren #include <peci.h> 4318a5ab91SZhikui Ren 4418a5ab91SZhikui Ren #include <phosphor-logging/log.hpp> 4518a5ab91SZhikui Ren #include <sdbusplus/asio/object_server.hpp> 4618a5ab91SZhikui Ren 4718a5ab91SZhikui Ren namespace cpu_info 4818a5ab91SZhikui Ren { 496d3ad586SZhikui Ren static constexpr bool debug = false; 502285be4fSJonathan Doman static constexpr const char* assetInterfaceName = 5118a5ab91SZhikui Ren "xyz.openbmc_project.Inventory.Decorator.Asset"; 5218a5ab91SZhikui Ren static constexpr const char* cpuProcessName = 5318a5ab91SZhikui Ren "xyz.openbmc_project.Smbios.MDR_V2"; 5418a5ab91SZhikui Ren 556d3ad586SZhikui Ren // constants for reading SSPEC or QDF string from PIROM 566d3ad586SZhikui Ren // Currently, they are the same for platforms with icx 576d3ad586SZhikui Ren static constexpr uint8_t defaultI2cBus = 13; 586d3ad586SZhikui Ren static constexpr uint8_t defaultI2cSlaveAddr0 = 0x50; 596d3ad586SZhikui Ren static constexpr uint8_t sspecRegAddr = 0xd; 606d3ad586SZhikui Ren static constexpr uint8_t sspecSize = 6; 6118a5ab91SZhikui Ren 626d3ad586SZhikui Ren using CPUInfoMap = boost::container::flat_map<size_t, std::shared_ptr<CPUInfo>>; 6318a5ab91SZhikui Ren 646d3ad586SZhikui Ren static CPUInfoMap cpuInfoMap = {}; 6518a5ab91SZhikui Ren 662285be4fSJonathan Doman /** 672285be4fSJonathan Doman * Simple aggregate to define an external D-Bus property which needs to be set 682285be4fSJonathan Doman * by this application. 692285be4fSJonathan Doman */ 702285be4fSJonathan Doman struct CpuProperty 712285be4fSJonathan Doman { 722285be4fSJonathan Doman std::string object; 732285be4fSJonathan Doman std::string interface; 742285be4fSJonathan Doman std::string name; 752285be4fSJonathan Doman std::string value; 762285be4fSJonathan Doman }; 772285be4fSJonathan Doman 782285be4fSJonathan Doman /** 792285be4fSJonathan Doman * List of properties we want to set on other D-Bus objects. This list is kept 802285be4fSJonathan Doman * around so that if any target objects are removed+readded, then we can set the 812285be4fSJonathan Doman * values again. 822285be4fSJonathan Doman */ 832285be4fSJonathan Doman static std::list<CpuProperty> propertiesToSet; 842285be4fSJonathan Doman 852285be4fSJonathan Doman static std::ostream& logStream(int cpu) 862285be4fSJonathan Doman { 872285be4fSJonathan Doman return std::cerr << "[CPU " << cpu << "] "; 882285be4fSJonathan Doman } 892285be4fSJonathan Doman 902285be4fSJonathan Doman static void 912285be4fSJonathan Doman setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn, 922285be4fSJonathan Doman size_t cpu, const std::string& interface, 932285be4fSJonathan Doman const std::string& propName, const std::string& propVal); 942285be4fSJonathan Doman static void 952285be4fSJonathan Doman setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn, 962285be4fSJonathan Doman size_t cpu, const CpuProperty& newProp); 972285be4fSJonathan Doman static void createCpuUpdatedMatch( 982285be4fSJonathan Doman const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu); 9918a5ab91SZhikui Ren 10018a5ab91SZhikui Ren static std::optional<std::string> readSSpec(uint8_t bus, uint8_t slaveAddr, 10118a5ab91SZhikui Ren uint8_t regAddr, size_t count) 10218a5ab91SZhikui Ren { 10318a5ab91SZhikui Ren unsigned long funcs = 0; 10418a5ab91SZhikui Ren std::string devPath = "/dev/i2c-" + std::to_string(bus); 10518a5ab91SZhikui Ren 10618a5ab91SZhikui Ren int fd = ::open(devPath.c_str(), O_RDWR); 10718a5ab91SZhikui Ren if (fd < 0) 10818a5ab91SZhikui Ren { 10918a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 11018a5ab91SZhikui Ren "Error in open!", 11118a5ab91SZhikui Ren phosphor::logging::entry("PATH=%s", devPath.c_str()), 11218a5ab91SZhikui Ren phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr)); 11318a5ab91SZhikui Ren return std::nullopt; 11418a5ab91SZhikui Ren } 11518a5ab91SZhikui Ren 11618a5ab91SZhikui Ren if (::ioctl(fd, I2C_FUNCS, &funcs) < 0) 11718a5ab91SZhikui Ren { 11818a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 11918a5ab91SZhikui Ren "Error in I2C_FUNCS!", 12018a5ab91SZhikui Ren phosphor::logging::entry("PATH=%s", devPath.c_str()), 12118a5ab91SZhikui Ren phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr)); 12218a5ab91SZhikui Ren ::close(fd); 12318a5ab91SZhikui Ren return std::nullopt; 12418a5ab91SZhikui Ren } 12518a5ab91SZhikui Ren 12618a5ab91SZhikui Ren if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) 12718a5ab91SZhikui Ren { 12818a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 12918a5ab91SZhikui Ren "i2c bus does not support read!", 13018a5ab91SZhikui Ren phosphor::logging::entry("PATH=%s", devPath.c_str()), 13118a5ab91SZhikui Ren phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr)); 13218a5ab91SZhikui Ren ::close(fd); 13318a5ab91SZhikui Ren return std::nullopt; 13418a5ab91SZhikui Ren } 13518a5ab91SZhikui Ren 13618a5ab91SZhikui Ren if (::ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0) 13718a5ab91SZhikui Ren { 13818a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 13918a5ab91SZhikui Ren "Error in I2C_SLAVE_FORCE!", 14018a5ab91SZhikui Ren phosphor::logging::entry("PATH=%s", devPath.c_str()), 14118a5ab91SZhikui Ren phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr)); 14218a5ab91SZhikui Ren ::close(fd); 14318a5ab91SZhikui Ren return std::nullopt; 14418a5ab91SZhikui Ren } 14518a5ab91SZhikui Ren 14618a5ab91SZhikui Ren int value = 0; 14718a5ab91SZhikui Ren std::string sspec; 14818a5ab91SZhikui Ren sspec.reserve(count); 14918a5ab91SZhikui Ren 15018a5ab91SZhikui Ren for (size_t i = 0; i < count; i++) 15118a5ab91SZhikui Ren { 1526d3ad586SZhikui Ren value = ::i2c_smbus_read_byte_data(fd, regAddr + i); 15318a5ab91SZhikui Ren if (value < 0) 15418a5ab91SZhikui Ren { 15518a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 15618a5ab91SZhikui Ren "Error in i2c read!", 15718a5ab91SZhikui Ren phosphor::logging::entry("PATH=%s", devPath.c_str()), 15818a5ab91SZhikui Ren phosphor::logging::entry("SLAVEADDR=0x%x", slaveAddr)); 15918a5ab91SZhikui Ren ::close(fd); 16018a5ab91SZhikui Ren return std::nullopt; 16118a5ab91SZhikui Ren } 16218a5ab91SZhikui Ren if (!std::isprint(static_cast<unsigned char>(value))) 16318a5ab91SZhikui Ren { 16418a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 16518a5ab91SZhikui Ren "Non printable value in sspec, ignored."); 16618a5ab91SZhikui Ren continue; 16718a5ab91SZhikui Ren } 1686d3ad586SZhikui Ren // sspec always starts with S, 1696d3ad586SZhikui Ren // if not assume it is QDF string which starts at offset 2 1706d3ad586SZhikui Ren if (i == 0 && static_cast<unsigned char>(value) != 'S') 1716d3ad586SZhikui Ren { 1726d3ad586SZhikui Ren i = 1; 1736d3ad586SZhikui Ren continue; 1746d3ad586SZhikui Ren } 17518a5ab91SZhikui Ren sspec.push_back(static_cast<unsigned char>(value)); 17618a5ab91SZhikui Ren } 17718a5ab91SZhikui Ren ::close(fd); 1782285be4fSJonathan Doman 1792285be4fSJonathan Doman if (sspec.size() < 4) 1802285be4fSJonathan Doman { 1812285be4fSJonathan Doman return std::nullopt; 1822285be4fSJonathan Doman } 1832285be4fSJonathan Doman 18418a5ab91SZhikui Ren return sspec; 18518a5ab91SZhikui Ren } 18618a5ab91SZhikui Ren 1872285be4fSJonathan Doman /** 1882285be4fSJonathan Doman * Higher level SSpec logic. 1892285be4fSJonathan Doman * This handles retrying the PIROM reads until two subsequent reads are 1902285be4fSJonathan Doman * successful and return matching data. When we have confidence that the data 1912285be4fSJonathan Doman * read is correct, then set the property on D-Bus. 1922285be4fSJonathan Doman * 1932285be4fSJonathan Doman * @param[in,out] conn D-Bus connection. 1942285be4fSJonathan Doman * @param[in] cpuInfo CPU to read from. 1952285be4fSJonathan Doman */ 1962285be4fSJonathan Doman static void 1972285be4fSJonathan Doman tryReadSSpec(const std::shared_ptr<sdbusplus::asio::connection>& conn, 1982285be4fSJonathan Doman const std::shared_ptr<CPUInfo>& cpuInfo) 1992285be4fSJonathan Doman { 2002285be4fSJonathan Doman static int failedReads = 0; 2012285be4fSJonathan Doman 2022285be4fSJonathan Doman std::optional<std::string> newSSpec = 2032285be4fSJonathan Doman readSSpec(cpuInfo->i2cBus, cpuInfo->i2cDevice, sspecRegAddr, sspecSize); 2042285be4fSJonathan Doman logStream(cpuInfo->id) << "SSpec read status: " 2052285be4fSJonathan Doman << static_cast<bool>(newSSpec) << "\n"; 2062285be4fSJonathan Doman if (newSSpec && newSSpec == cpuInfo->sSpec) 2072285be4fSJonathan Doman { 2082285be4fSJonathan Doman setCpuProperty(conn, cpuInfo->id, assetInterfaceName, "Model", 2092285be4fSJonathan Doman *newSSpec); 2102285be4fSJonathan Doman return; 2112285be4fSJonathan Doman } 2122285be4fSJonathan Doman 2132285be4fSJonathan Doman // If this read failed, back off for a little longer so that hopefully the 2142285be4fSJonathan Doman // transient condition affecting PIROM reads will pass, but give up after 2152285be4fSJonathan Doman // several consecutive failures. But if this read looked OK, try again 2162285be4fSJonathan Doman // sooner to confirm it. 2172285be4fSJonathan Doman int retrySeconds; 2182285be4fSJonathan Doman if (newSSpec) 2192285be4fSJonathan Doman { 2202285be4fSJonathan Doman retrySeconds = 1; 2212285be4fSJonathan Doman failedReads = 0; 2222285be4fSJonathan Doman cpuInfo->sSpec = *newSSpec; 2232285be4fSJonathan Doman } 2242285be4fSJonathan Doman else 2252285be4fSJonathan Doman { 2262285be4fSJonathan Doman retrySeconds = 5; 2272285be4fSJonathan Doman if (++failedReads > 10) 2282285be4fSJonathan Doman { 2292285be4fSJonathan Doman logStream(cpuInfo->id) << "PIROM Read failed too many times\n"; 2302285be4fSJonathan Doman return; 2312285be4fSJonathan Doman } 2322285be4fSJonathan Doman } 2332285be4fSJonathan Doman 2342285be4fSJonathan Doman auto sspecTimer = std::make_shared<boost::asio::steady_timer>( 2352285be4fSJonathan Doman conn->get_io_context(), std::chrono::seconds(retrySeconds)); 2362285be4fSJonathan Doman sspecTimer->async_wait( 2372285be4fSJonathan Doman [sspecTimer, conn, cpuInfo](boost::system::error_code ec) { 2382285be4fSJonathan Doman if (ec) 2392285be4fSJonathan Doman { 2402285be4fSJonathan Doman return; 2412285be4fSJonathan Doman } 2422285be4fSJonathan Doman tryReadSSpec(conn, cpuInfo); 2432285be4fSJonathan Doman }); 2442285be4fSJonathan Doman } 2452285be4fSJonathan Doman 2462285be4fSJonathan Doman /** 2472285be4fSJonathan Doman * Add a D-Bus property to the global list, and attempt to set it by calling 2482285be4fSJonathan Doman * `setDbusProperty`. 2492285be4fSJonathan Doman * 2502285be4fSJonathan Doman * @param[in,out] conn D-Bus connection. 2512285be4fSJonathan Doman * @param[in] cpu 1-based CPU index. 2522285be4fSJonathan Doman * @param[in] interface Interface to set. 2532285be4fSJonathan Doman * @param[in] propName Property to set. 2542285be4fSJonathan Doman * @param[in] propVal Value to set. 2552285be4fSJonathan Doman */ 2562285be4fSJonathan Doman static void 2572285be4fSJonathan Doman setCpuProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn, 2582285be4fSJonathan Doman size_t cpu, const std::string& interface, 2592285be4fSJonathan Doman const std::string& propName, const std::string& propVal) 26018a5ab91SZhikui Ren { 2616d3ad586SZhikui Ren // cpuId from configuration is one based as 2626d3ad586SZhikui Ren // dbus object path used by smbios is 0 based 2636d3ad586SZhikui Ren const std::string objectPath = cpuPath + std::to_string(cpu - 1); 2642285be4fSJonathan Doman 2652285be4fSJonathan Doman // Can switch to emplace_back if you define a CpuProperty constructor. 2662285be4fSJonathan Doman propertiesToSet.push_back( 2672285be4fSJonathan Doman CpuProperty{objectPath, interface, propName, propVal}); 2682285be4fSJonathan Doman 2692285be4fSJonathan Doman setDbusProperty(conn, cpu, propertiesToSet.back()); 2702285be4fSJonathan Doman } 2712285be4fSJonathan Doman 2722285be4fSJonathan Doman /** 2732285be4fSJonathan Doman * Set a D-Bus property which is already contained in the global list, and also 2742285be4fSJonathan Doman * setup a D-Bus match to make sure the target property stays correct. 2752285be4fSJonathan Doman * 2762285be4fSJonathan Doman * @param[in,out] conn D-Bus connection. 2772285be4fSJonathan Doman * @param[in] cpu 1-baesd CPU index. 2782285be4fSJonathan Doman * @param[in] newProp Property to set. 2792285be4fSJonathan Doman */ 2802285be4fSJonathan Doman static void 2812285be4fSJonathan Doman setDbusProperty(const std::shared_ptr<sdbusplus::asio::connection>& conn, 2822285be4fSJonathan Doman size_t cpu, const CpuProperty& newProp) 28318a5ab91SZhikui Ren { 2842285be4fSJonathan Doman createCpuUpdatedMatch(conn, cpu); 28518a5ab91SZhikui Ren conn->async_method_call( 28618a5ab91SZhikui Ren [](const boost::system::error_code ec) { 28718a5ab91SZhikui Ren if (ec) 28818a5ab91SZhikui Ren { 28918a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 2902285be4fSJonathan Doman "Cannot set CPU property!"); 29118a5ab91SZhikui Ren return; 29218a5ab91SZhikui Ren } 29318a5ab91SZhikui Ren }, 2942285be4fSJonathan Doman cpuProcessName, newProp.object.c_str(), 2952285be4fSJonathan Doman "org.freedesktop.DBus.Properties", "Set", newProp.interface, 2962285be4fSJonathan Doman newProp.name, std::variant<std::string>{newProp.value}); 29718a5ab91SZhikui Ren } 29818a5ab91SZhikui Ren 2992285be4fSJonathan Doman /** 3002285be4fSJonathan Doman * Set up a D-Bus match (if one does not already exist) to watch for any new 3012285be4fSJonathan Doman * interfaces on the cpu object. When new interfaces are added, re-send all 3022285be4fSJonathan Doman * properties targeting that object/interface. 3032285be4fSJonathan Doman * 3042285be4fSJonathan Doman * @param[in,out] conn D-Bus connection. 3052285be4fSJonathan Doman * @param[in] cpu 1-based CPU index. 3062285be4fSJonathan Doman */ 30718a5ab91SZhikui Ren static void createCpuUpdatedMatch( 3082285be4fSJonathan Doman const std::shared_ptr<sdbusplus::asio::connection>& conn, size_t cpu) 30918a5ab91SZhikui Ren { 3102285be4fSJonathan Doman static boost::container::flat_map<size_t, 3112285be4fSJonathan Doman std::unique_ptr<sdbusplus::bus::match_t>> 3122285be4fSJonathan Doman cpuUpdatedMatch; 3132285be4fSJonathan Doman 3146d3ad586SZhikui Ren if (cpuUpdatedMatch[cpu]) 31518a5ab91SZhikui Ren { 31618a5ab91SZhikui Ren return; 31718a5ab91SZhikui Ren } 31818a5ab91SZhikui Ren 3196d3ad586SZhikui Ren const std::string objectPath = cpuPath + std::to_string(cpu - 1); 32018a5ab91SZhikui Ren 3216d3ad586SZhikui Ren cpuUpdatedMatch.insert_or_assign( 3226d3ad586SZhikui Ren cpu, 32377b9c478SPatrick Williams std::make_unique<sdbusplus::bus::match_t>( 32477b9c478SPatrick Williams static_cast<sdbusplus::bus_t&>(*conn), 32518a5ab91SZhikui Ren sdbusplus::bus::match::rules::interfacesAdded() + 32618a5ab91SZhikui Ren sdbusplus::bus::match::rules::argNpath(0, objectPath.c_str()), 32777b9c478SPatrick Williams [conn, cpu](sdbusplus::message_t& msg) { 328a43eec82SJonathan Doman sdbusplus::message::object_path objectName; 32918a5ab91SZhikui Ren boost::container::flat_map< 330*c39d3dfcSPatrick Williams std::string, boost::container::flat_map< 3316d3ad586SZhikui Ren std::string, std::variant<std::string, uint64_t>>> 33218a5ab91SZhikui Ren msgData; 33318a5ab91SZhikui Ren 33418a5ab91SZhikui Ren msg.read(objectName, msgData); 33518a5ab91SZhikui Ren 3362285be4fSJonathan Doman // Go through all the property changes, and retry all of them 3372285be4fSJonathan Doman // targeting this object/interface which was just added. 3382285be4fSJonathan Doman for (const CpuProperty& prop : propertiesToSet) 33918a5ab91SZhikui Ren { 340*c39d3dfcSPatrick Williams if (prop.object == objectName && msgData.contains(prop.interface)) 3412285be4fSJonathan Doman { 3422285be4fSJonathan Doman setDbusProperty(conn, cpu, prop); 3432285be4fSJonathan Doman } 34418a5ab91SZhikui Ren } 3456d3ad586SZhikui Ren })); 34618a5ab91SZhikui Ren } 34718a5ab91SZhikui Ren 3486d3ad586SZhikui Ren static void 3496d3ad586SZhikui Ren getProcessorInfo(boost::asio::io_service& io, 3506d3ad586SZhikui Ren const std::shared_ptr<sdbusplus::asio::connection>& conn, 3516d3ad586SZhikui Ren const size_t& cpu) 35218a5ab91SZhikui Ren { 3536d3ad586SZhikui Ren if (cpuInfoMap.find(cpu) == cpuInfoMap.end() || cpuInfoMap[cpu] == nullptr) 35418a5ab91SZhikui Ren { 3556d3ad586SZhikui Ren std::cerr << "No information found for cpu " << cpu << "\n"; 3566d3ad586SZhikui Ren return; 3576d3ad586SZhikui Ren } 3586d3ad586SZhikui Ren 3592285be4fSJonathan Doman std::shared_ptr<CPUInfo> cpuInfo = cpuInfoMap[cpu]; 3602285be4fSJonathan Doman 3612285be4fSJonathan Doman if (cpuInfo->id != cpu) 3626d3ad586SZhikui Ren { 3632285be4fSJonathan Doman std::cerr << "Incorrect CPU id " << (unsigned)cpuInfo->id << " expect " 3642285be4fSJonathan Doman << cpu << "\n"; 3656d3ad586SZhikui Ren return; 3666d3ad586SZhikui Ren } 3676d3ad586SZhikui Ren 3682285be4fSJonathan Doman uint8_t cpuAddr = cpuInfo->peciAddr; 3696d3ad586SZhikui Ren 37018a5ab91SZhikui Ren uint8_t cc = 0; 37118a5ab91SZhikui Ren CPUModel model{}; 37218a5ab91SZhikui Ren uint8_t stepping = 0; 37318a5ab91SZhikui Ren 3740a385373SJonathan Doman // Wait for POST to complete to ensure that BIOS has time to enable the 3750a385373SJonathan Doman // PPIN. Before BIOS enables it, we would get a 0x90 CC on PECI. 3760a385373SJonathan Doman if (hostState != HostState::postComplete || 3770a385373SJonathan Doman peci_GetCPUID(cpuAddr, &model, &stepping, &cc) != PECI_CC_SUCCESS) 3786d3ad586SZhikui Ren { 3796d3ad586SZhikui Ren // Start the PECI check loop 3806d3ad586SZhikui Ren auto waitTimer = std::make_shared<boost::asio::steady_timer>(io); 3816d3ad586SZhikui Ren waitTimer->expires_after( 3820a385373SJonathan Doman std::chrono::seconds(cpu_info::peciCheckInterval)); 38318a5ab91SZhikui Ren 3846d3ad586SZhikui Ren waitTimer->async_wait( 3856d3ad586SZhikui Ren [waitTimer, &io, conn, cpu](const boost::system::error_code& ec) { 3866d3ad586SZhikui Ren if (ec) 3876d3ad586SZhikui Ren { 3886d3ad586SZhikui Ren // operation_aborted is expected if timer is canceled 3896d3ad586SZhikui Ren // before completion. 3906d3ad586SZhikui Ren if (ec != boost::asio::error::operation_aborted) 39118a5ab91SZhikui Ren { 39218a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 3936d3ad586SZhikui Ren "info update timer async_wait failed ", 3946d3ad586SZhikui Ren phosphor::logging::entry("EC=0x%x", ec.value())); 3956d3ad586SZhikui Ren } 3966d3ad586SZhikui Ren return; 3976d3ad586SZhikui Ren } 3986d3ad586SZhikui Ren getProcessorInfo(io, conn, cpu); 3996d3ad586SZhikui Ren }); 4006d3ad586SZhikui Ren return; 40118a5ab91SZhikui Ren } 40218a5ab91SZhikui Ren 40318a5ab91SZhikui Ren switch (model) 40418a5ab91SZhikui Ren { 40518a5ab91SZhikui Ren case icx: 406631388e6SJonathan Doman case icxd: 407631388e6SJonathan Doman case spr: 408949f634dSJonathan Doman case emr: 409ca2b38a6SJonathan Doman case gnr: 410ca2b38a6SJonathan Doman case srf: 41118a5ab91SZhikui Ren { 4126d3ad586SZhikui Ren // PPIN can be read through PCS 19 41318a5ab91SZhikui Ren static constexpr uint8_t u8Size = 4; // default to a DWORD 41418a5ab91SZhikui Ren static constexpr uint8_t u8PPINPkgIndex = 19; 41518a5ab91SZhikui Ren static constexpr uint16_t u16PPINPkgParamHigh = 2; 41618a5ab91SZhikui Ren static constexpr uint16_t u16PPINPkgParamLow = 1; 41718a5ab91SZhikui Ren uint64_t cpuPPIN = 0; 41818a5ab91SZhikui Ren uint32_t u32PkgValue = 0; 41918a5ab91SZhikui Ren 420*c39d3dfcSPatrick Williams int ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, 421*c39d3dfcSPatrick Williams u16PPINPkgParamLow, u8Size, 422*c39d3dfcSPatrick Williams (uint8_t*)&u32PkgValue, &cc); 42318a5ab91SZhikui Ren if (0 != ret) 42418a5ab91SZhikui Ren { 42518a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 42618a5ab91SZhikui Ren "peci read package config failed at address", 4276d3ad586SZhikui Ren phosphor::logging::entry("PECIADDR=0x%x", 4286d3ad586SZhikui Ren (unsigned)cpuAddr), 42918a5ab91SZhikui Ren phosphor::logging::entry("CC=0x%x", cc)); 43018a5ab91SZhikui Ren u32PkgValue = 0; 43118a5ab91SZhikui Ren } 43218a5ab91SZhikui Ren 43318a5ab91SZhikui Ren cpuPPIN = u32PkgValue; 4346d3ad586SZhikui Ren ret = peci_RdPkgConfig(cpuAddr, u8PPINPkgIndex, u16PPINPkgParamHigh, 4356d3ad586SZhikui Ren u8Size, (uint8_t*)&u32PkgValue, &cc); 43618a5ab91SZhikui Ren if (0 != ret) 43718a5ab91SZhikui Ren { 43818a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 43918a5ab91SZhikui Ren "peci read package config failed at address", 4406d3ad586SZhikui Ren phosphor::logging::entry("PECIADDR=0x%x", 4416d3ad586SZhikui Ren (unsigned)cpuAddr), 44218a5ab91SZhikui Ren phosphor::logging::entry("CC=0x%x", cc)); 44318a5ab91SZhikui Ren cpuPPIN = 0; 44418a5ab91SZhikui Ren u32PkgValue = 0; 44518a5ab91SZhikui Ren } 44618a5ab91SZhikui Ren 44718a5ab91SZhikui Ren cpuPPIN |= static_cast<uint64_t>(u32PkgValue) << 32; 44818a5ab91SZhikui Ren 44918a5ab91SZhikui Ren // set SerialNumber if cpuPPIN is valid 45018a5ab91SZhikui Ren if (0 != cpuPPIN) 45118a5ab91SZhikui Ren { 45218a5ab91SZhikui Ren std::stringstream stream; 45318a5ab91SZhikui Ren stream << std::hex << cpuPPIN; 45418a5ab91SZhikui Ren std::string serialNumber(stream.str()); 4555b285892SJonathan Doman cpuInfo->uniqueIdentifier(serialNumber); 4565b285892SJonathan Doman // Signal that the iface is added now so that ObjectMapper and 4575b285892SJonathan Doman // others can find it. 4585b285892SJonathan Doman cpuInfo->emit_added(); 45918a5ab91SZhikui Ren } 46018a5ab91SZhikui Ren 4612285be4fSJonathan Doman tryReadSSpec(conn, cpuInfo); 46218a5ab91SZhikui Ren break; 46318a5ab91SZhikui Ren } 46418a5ab91SZhikui Ren default: 46518a5ab91SZhikui Ren phosphor::logging::log<phosphor::logging::level::INFO>( 46618a5ab91SZhikui Ren "in-compatible cpu for cpu asset info"); 46718a5ab91SZhikui Ren break; 46818a5ab91SZhikui Ren } 46918a5ab91SZhikui Ren } 47018a5ab91SZhikui Ren 4716d3ad586SZhikui Ren /** 4726d3ad586SZhikui Ren * Get cpu and pirom address 4736d3ad586SZhikui Ren */ 47418a5ab91SZhikui Ren static void 4756d3ad586SZhikui Ren getCpuAddress(boost::asio::io_service& io, 4766d3ad586SZhikui Ren const std::shared_ptr<sdbusplus::asio::connection>& conn, 4776d3ad586SZhikui Ren const std::string& service, const std::string& object, 4786d3ad586SZhikui Ren const std::string& interface) 47918a5ab91SZhikui Ren { 4806d3ad586SZhikui Ren conn->async_method_call( 4816d3ad586SZhikui Ren [&io, conn](boost::system::error_code ec, 4826d3ad586SZhikui Ren const boost::container::flat_map< 4836d3ad586SZhikui Ren std::string, 4846d3ad586SZhikui Ren std::variant<std::string, uint64_t, uint32_t, uint16_t, 4856d3ad586SZhikui Ren std::vector<std::string>>>& properties) { 4866d3ad586SZhikui Ren const uint64_t* value = nullptr; 4876d3ad586SZhikui Ren uint8_t peciAddress = 0; 4886d3ad586SZhikui Ren uint8_t i2cBus = defaultI2cBus; 4896d3ad586SZhikui Ren uint8_t i2cDevice; 4906d3ad586SZhikui Ren bool i2cDeviceFound = false; 4916d3ad586SZhikui Ren size_t cpu = 0; 4926d3ad586SZhikui Ren 49318a5ab91SZhikui Ren if (ec) 49418a5ab91SZhikui Ren { 4956d3ad586SZhikui Ren std::cerr << "DBUS response error " << ec.value() << ": " 4966d3ad586SZhikui Ren << ec.message() << "\n"; 49718a5ab91SZhikui Ren return; 49818a5ab91SZhikui Ren } 4996d3ad586SZhikui Ren 5006d3ad586SZhikui Ren for (const auto& property : properties) 5016d3ad586SZhikui Ren { 5026d3ad586SZhikui Ren std::cerr << "property " << property.first << "\n"; 5036d3ad586SZhikui Ren if (property.first == "Address") 5046d3ad586SZhikui Ren { 5056d3ad586SZhikui Ren value = std::get_if<uint64_t>(&property.second); 5066d3ad586SZhikui Ren if (value != nullptr) 5076d3ad586SZhikui Ren { 5086d3ad586SZhikui Ren peciAddress = static_cast<uint8_t>(*value); 50918a5ab91SZhikui Ren } 51018a5ab91SZhikui Ren } 5116d3ad586SZhikui Ren if (property.first == "CpuID") 5126d3ad586SZhikui Ren { 5136d3ad586SZhikui Ren value = std::get_if<uint64_t>(&property.second); 5146d3ad586SZhikui Ren if (value != nullptr) 5156d3ad586SZhikui Ren { 5166d3ad586SZhikui Ren cpu = static_cast<size_t>(*value); 5176d3ad586SZhikui Ren } 5186d3ad586SZhikui Ren } 5196d3ad586SZhikui Ren if (property.first == "PiromI2cAddress") 5206d3ad586SZhikui Ren { 5216d3ad586SZhikui Ren value = std::get_if<uint64_t>(&property.second); 5226d3ad586SZhikui Ren if (value != nullptr) 5236d3ad586SZhikui Ren { 5246d3ad586SZhikui Ren i2cDevice = static_cast<uint8_t>(*value); 5256d3ad586SZhikui Ren i2cDeviceFound = true; 5266d3ad586SZhikui Ren } 5276d3ad586SZhikui Ren } 5286d3ad586SZhikui Ren if (property.first == "PiromI2cBus") 5296d3ad586SZhikui Ren { 5306d3ad586SZhikui Ren value = std::get_if<uint64_t>(&property.second); 5316d3ad586SZhikui Ren if (value != nullptr) 5326d3ad586SZhikui Ren { 5336d3ad586SZhikui Ren i2cBus = static_cast<uint8_t>(*value); 5346d3ad586SZhikui Ren } 5356d3ad586SZhikui Ren } 5366d3ad586SZhikui Ren } 5376d3ad586SZhikui Ren 5386d3ad586SZhikui Ren ///\todo replace this with present + power state 5396d3ad586SZhikui Ren if (cpu != 0 && peciAddress != 0) 5406d3ad586SZhikui Ren { 5416d3ad586SZhikui Ren if (!i2cDeviceFound) 5426d3ad586SZhikui Ren { 5436d3ad586SZhikui Ren i2cDevice = defaultI2cSlaveAddr0 + cpu - 1; 5446d3ad586SZhikui Ren } 5456d3ad586SZhikui Ren cpuInfoMap.insert_or_assign( 546*c39d3dfcSPatrick Williams cpu, std::make_shared<CPUInfo>(*conn, cpu, peciAddress, i2cBus, 547*c39d3dfcSPatrick Williams i2cDevice)); 5486d3ad586SZhikui Ren 5496d3ad586SZhikui Ren getProcessorInfo(io, conn, cpu); 5506d3ad586SZhikui Ren } 5516d3ad586SZhikui Ren }, 5526d3ad586SZhikui Ren service, object, "org.freedesktop.DBus.Properties", "GetAll", 5536d3ad586SZhikui Ren interface); 5546d3ad586SZhikui Ren } 5556d3ad586SZhikui Ren 5566d3ad586SZhikui Ren /** 5576d3ad586SZhikui Ren * D-Bus client: to get platform specific configs 5586d3ad586SZhikui Ren */ 5596d3ad586SZhikui Ren static void getCpuConfiguration( 5606d3ad586SZhikui Ren boost::asio::io_service& io, 5616d3ad586SZhikui Ren const std::shared_ptr<sdbusplus::asio::connection>& conn, 5626d3ad586SZhikui Ren sdbusplus::asio::object_server& objServer) 5636d3ad586SZhikui Ren { 5646d3ad586SZhikui Ren // Get the Cpu configuration 5656d3ad586SZhikui Ren // In case it's not available, set a match for it 56677b9c478SPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> cpuConfigMatch = 56777b9c478SPatrick Williams std::make_unique<sdbusplus::bus::match_t>( 5686d3ad586SZhikui Ren *conn, 5696d3ad586SZhikui Ren "type='signal',interface='org.freedesktop.DBus.Properties',member='" 5706d3ad586SZhikui Ren "PropertiesChanged',arg0='xyz.openbmc_project." 5716d3ad586SZhikui Ren "Configuration.XeonCPU'", 57277b9c478SPatrick Williams [&io, conn, &objServer](sdbusplus::message_t& msg) { 5736d3ad586SZhikui Ren std::cerr << "get cpu configuration match\n"; 5746d3ad586SZhikui Ren static boost::asio::steady_timer filterTimer(io); 575*c39d3dfcSPatrick Williams filterTimer.expires_after(std::chrono::seconds(configCheckInterval)); 5766d3ad586SZhikui Ren 5776d3ad586SZhikui Ren filterTimer.async_wait( 578*c39d3dfcSPatrick Williams [&io, conn, &objServer](const boost::system::error_code& ec) { 5796d3ad586SZhikui Ren if (ec == boost::asio::error::operation_aborted) 5806d3ad586SZhikui Ren { 5816d3ad586SZhikui Ren return; // we're being canceled 5826d3ad586SZhikui Ren } 5836d3ad586SZhikui Ren else if (ec) 5846d3ad586SZhikui Ren { 5856d3ad586SZhikui Ren std::cerr << "Error: " << ec.message() << "\n"; 5866d3ad586SZhikui Ren return; 5876d3ad586SZhikui Ren } 5886d3ad586SZhikui Ren getCpuConfiguration(io, conn, objServer); 5896d3ad586SZhikui Ren }); 5906d3ad586SZhikui Ren }); 5916d3ad586SZhikui Ren 5926d3ad586SZhikui Ren conn->async_method_call( 5936d3ad586SZhikui Ren [&io, conn]( 5946d3ad586SZhikui Ren boost::system::error_code ec, 5956d3ad586SZhikui Ren const std::vector<std::pair< 5966d3ad586SZhikui Ren std::string, 5976d3ad586SZhikui Ren std::vector<std::pair<std::string, std::vector<std::string>>>>>& 5986d3ad586SZhikui Ren subtree) { 5996d3ad586SZhikui Ren if constexpr (debug) 6006d3ad586SZhikui Ren std::cerr << "async_method_call callback\n"; 6016d3ad586SZhikui Ren 6026d3ad586SZhikui Ren if (ec) 6036d3ad586SZhikui Ren { 6046d3ad586SZhikui Ren std::cerr << "error with async_method_call\n"; 6056d3ad586SZhikui Ren return; 6066d3ad586SZhikui Ren } 6076d3ad586SZhikui Ren if (subtree.empty()) 6086d3ad586SZhikui Ren { 6096d3ad586SZhikui Ren // No config data yet, so wait for the match 6106d3ad586SZhikui Ren return; 6116d3ad586SZhikui Ren } 6126d3ad586SZhikui Ren 6136d3ad586SZhikui Ren for (const auto& object : subtree) 6146d3ad586SZhikui Ren { 6156d3ad586SZhikui Ren for (const auto& service : object.second) 6166d3ad586SZhikui Ren { 6176d3ad586SZhikui Ren getCpuAddress(io, conn, service.first, object.first, 6186d3ad586SZhikui Ren "xyz.openbmc_project.Configuration.XeonCPU"); 6196d3ad586SZhikui Ren } 6206d3ad586SZhikui Ren } 6216d3ad586SZhikui Ren if constexpr (debug) 6226d3ad586SZhikui Ren std::cerr << "getCpuConfiguration callback complete\n"; 6236d3ad586SZhikui Ren 6246d3ad586SZhikui Ren return; 6256d3ad586SZhikui Ren }, 6266d3ad586SZhikui Ren "xyz.openbmc_project.ObjectMapper", 6276d3ad586SZhikui Ren "/xyz/openbmc_project/object_mapper", 6286d3ad586SZhikui Ren "xyz.openbmc_project.ObjectMapper", "GetSubTree", 6296d3ad586SZhikui Ren "/xyz/openbmc_project/", 0, 6306d3ad586SZhikui Ren std::array<const char*, 1>{ 6316d3ad586SZhikui Ren "xyz.openbmc_project.Configuration.XeonCPU"}); 6326d3ad586SZhikui Ren } 63318a5ab91SZhikui Ren 63418a5ab91SZhikui Ren } // namespace cpu_info 63518a5ab91SZhikui Ren 63618a5ab91SZhikui Ren int main(int argc, char* argv[]) 63718a5ab91SZhikui Ren { 63818a5ab91SZhikui Ren // setup connection to dbus 63916a2ced3SJonathan Doman boost::asio::io_service& io = cpu_info::dbus::getIOContext(); 64018a5ab91SZhikui Ren std::shared_ptr<sdbusplus::asio::connection> conn = 64116a2ced3SJonathan Doman cpu_info::dbus::getConnection(); 64218a5ab91SZhikui Ren 64318a5ab91SZhikui Ren // CPUInfo Object 6440a385373SJonathan Doman conn->request_name(cpu_info::cpuInfoObject); 64518a5ab91SZhikui Ren sdbusplus::asio::object_server server = 64618a5ab91SZhikui Ren sdbusplus::asio::object_server(conn); 64777b9c478SPatrick Williams sdbusplus::bus_t& bus = static_cast<sdbusplus::bus_t&>(*conn); 64877b9c478SPatrick Williams sdbusplus::server::manager_t objManager(bus, 64977b9c478SPatrick Williams "/xyz/openbmc_project/inventory"); 65018a5ab91SZhikui Ren 651703a1856SJonathan Doman cpu_info::hostStateSetup(conn); 652703a1856SJonathan Doman 65349ea830eSJonathan Doman cpu_info::sst::init(); 65494c94bfbSJonathan Doman 6556d3ad586SZhikui Ren // shared_ptr conn is global for the service 6566d3ad586SZhikui Ren // const reference of conn is passed to async calls 6570a385373SJonathan Doman cpu_info::getCpuConfiguration(io, conn, server); 65818a5ab91SZhikui Ren 65918a5ab91SZhikui Ren io.run(); 66018a5ab91SZhikui Ren 66118a5ab91SZhikui Ren return 0; 66218a5ab91SZhikui Ren } 663