blob: 3ebadef6444b49452167340732196a730ee36aa1 [file] [log] [blame]
Jason M. Billsd1e40602019-05-09 11:43:51 -07001/*
2// Copyright (c) 2019 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 "peci_pcie.hpp"
18
19#include "pciDeviceClass.hpp"
20#include "pciVendors.hpp"
21
Jason M. Billsbce86a62020-10-08 16:03:47 -070022#include <boost/asio/io_service.hpp>
23#include <boost/asio/steady_timer.hpp>
Jason M. Billsd1e40602019-05-09 11:43:51 -070024#include <boost/container/flat_map.hpp>
25#include <boost/container/flat_set.hpp>
26#include <sdbusplus/asio/object_server.hpp>
Jason M. Billsee6d80b2021-06-11 07:37:30 -070027#include <sdbusplus/bus/match.hpp>
Jason M. Billsd1e40602019-05-09 11:43:51 -070028
29#include <iomanip>
30#include <iostream>
31#include <set>
32#include <sstream>
33
34namespace peci_pcie
35{
36static boost::container::flat_map<
37 int, boost::container::flat_map<
38 int, boost::container::flat_map<
39 int, std::shared_ptr<sdbusplus::asio::dbus_interface>>>>
40 pcieDeviceDBusMap;
41
Jason M. Billsee6d80b2021-06-11 07:37:30 -070042static bool abortScan;
43
Jason M. Billsd1e40602019-05-09 11:43:51 -070044namespace function
45{
46static constexpr char const* functionTypeName = "FunctionType";
47static constexpr char const* deviceClassName = "DeviceClass";
48static constexpr char const* vendorIdName = "VendorId";
49static constexpr char const* deviceIdName = "DeviceId";
50static constexpr char const* classCodeName = "ClassCode";
51static constexpr char const* revisionIdName = "RevisionId";
52static constexpr char const* subsystemIdName = "SubsystemId";
53static constexpr char const* subsystemVendorIdName = "SubsystemVendorId";
54} // namespace function
Andrei Kartashev6f552032021-05-11 21:25:29 +030055
56static constexpr const std::array pciConfigInfo{
57 std::tuple<const char*, int, int>{function::functionTypeName, -1, -1},
58 std::tuple<const char*, int, int>{function::deviceClassName, -1, -1},
59 std::tuple<const char*, int, int>{function::vendorIdName, 0, 2},
60 std::tuple<const char*, int, int>{function::deviceIdName, 2, 2},
61 std::tuple<const char*, int, int>{function::classCodeName, 9, 3},
62 std::tuple<const char*, int, int>{function::revisionIdName, 8, 1},
63 std::tuple<const char*, int, int>{function::subsystemIdName, 0x2e, 2},
64 std::tuple<const char*, int, int>{function::subsystemVendorIdName, 0x2c,
65 2}};
Jason M. Billsd1e40602019-05-09 11:43:51 -070066} // namespace peci_pcie
67
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030068enum class resCode
69{
70 resOk,
Spencer Kubb5efe72021-09-02 16:11:14 +080071 resSkip,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030072 resErr
73};
74
Jason M. Bills5d049732019-10-25 15:55:15 -070075struct CPUInfo
Jason M. Billsd1e40602019-05-09 11:43:51 -070076{
Jason M. Bills5d049732019-10-25 15:55:15 -070077 size_t addr;
78 bool skipCpuBuses;
79 boost::container::flat_set<size_t> cpuBusNums;
80};
81
82// PECI Client Address Map
Andrei Kartashev8e966032021-07-02 20:04:30 +030083static resCode getCPUBusMap(std::vector<CPUInfo>& cpuInfo)
Jason M. Bills5d049732019-10-25 15:55:15 -070084{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030085 cpuInfo.clear();
Andrei Kartashev8e966032021-07-02 20:04:30 +030086 for (size_t addr = MIN_CLIENT_ADDR; addr <= MAX_CLIENT_ADDR; addr++)
Jason M. Billsd1e40602019-05-09 11:43:51 -070087 {
Andrei Kartashev8e966032021-07-02 20:04:30 +030088 if (peci_Ping(addr) != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -070089 {
Andrei Kartashev8e966032021-07-02 20:04:30 +030090 continue;
Jason M. Bills5d049732019-10-25 15:55:15 -070091 }
Jason M. Bills5d049732019-10-25 15:55:15 -070092
Andrei Kartashev8e966032021-07-02 20:04:30 +030093 auto& cpu = cpuInfo.emplace_back(CPUInfo{addr, false, {}});
Jason M. Bills5d049732019-10-25 15:55:15 -070094 uint8_t cc = 0;
95 CPUModel model{};
96 uint8_t stepping = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +030097 if (peci_GetCPUID(addr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Jason M. Bills5d049732019-10-25 15:55:15 -070098 {
99 std::cerr << "Cannot get CPUID!\n";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300100 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700101 }
102
103 switch (model)
104 {
105 case skx:
106 {
107 // Get the assigned CPU bus numbers from CPUBUSNO and CPUBUSNO1
108 // (B(0) D8 F2 offsets CCh and D0h)
109 uint32_t cpuBusNum = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300110 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xCC, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700111 (uint8_t*)&cpuBusNum,
112 &cc) != PECI_CC_SUCCESS)
113 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300114 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700115 }
116 uint32_t cpuBusNum1 = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300117 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xD0, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700118 (uint8_t*)&cpuBusNum1,
119 &cc) != PECI_CC_SUCCESS)
120 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300121 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700122 }
123
124 // Add the CPU bus numbers to the set for this CPU
125 while (cpuBusNum)
126 {
127 // Get the LSB
128 size_t busNum = cpuBusNum & 0xFF;
129 cpu.cpuBusNums.insert(busNum);
130 // Shift right by one byte
131 cpuBusNum >>= 8;
132 }
133 while (cpuBusNum1)
134 {
135 // Get the LSB
136 size_t busNum = cpuBusNum1 & 0xFF;
137 cpu.cpuBusNums.insert(busNum);
138 // Shift right by one byte
Zev Weiss9fa54b52020-09-02 21:20:33 +0000139 cpuBusNum1 >>= 8;
Jason M. Bills5d049732019-10-25 15:55:15 -0700140 }
141 cpu.skipCpuBuses = true;
142 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700143 }
144 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300145 return cpuInfo.empty() ? resCode::resErr : resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700146}
147
148static bool isPECIAvailable(void)
149{
Jason M. Bills5d049732019-10-25 15:55:15 -0700150 for (size_t i = MIN_CLIENT_ADDR; i <= MAX_CLIENT_ADDR; i++)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700151 {
Jason M. Bills5d049732019-10-25 15:55:15 -0700152 if (peci_Ping(i) == PECI_CC_SUCCESS)
153 {
154 return true;
155 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700156 }
Jason M. Bills5d049732019-10-25 15:55:15 -0700157 return false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700158}
159
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300160static resCode getDataFromPCIeConfig(const int& clientAddr, const int& bus,
161 const int& dev, const int& func,
162 const int& offset, const int& size,
163 uint32_t& pciData)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700164{
165 // PECI RdPCIConfig() currently only supports 4 byte reads, so adjust
166 // the offset and size to get the right data
167 static constexpr const int pciReadSize = 4;
168 int mod = offset % pciReadSize;
169 int pciOffset = offset - mod;
170 if (mod + size > pciReadSize)
171 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300172 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700173 }
174
175 std::array<uint8_t, pciReadSize> data;
176 uint8_t cc;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300177 int ret = PECI_CC_TIMEOUT;
178 for (int index = 0; (index < 5) && (ret == PECI_CC_TIMEOUT); index++)
179 {
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700180#ifdef USE_RDENDPOINTCFG
181 ret = peci_RdEndPointConfigPci(clientAddr, // CPU Address
182 0, // PCI Seg (use 0 for now)
183 bus, // PCI Bus
184 dev, // PCI Device
185 func, // PCI Function
186 pciOffset, // PCI Offset
187 pciReadSize, // PCI Read Size
188 data.data(), // PCI Read Data
189 &cc); // PECI Completion Code
190#else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300191 ret = peci_RdPCIConfig(clientAddr, // CPU Address
Jason M. Billsd1e40602019-05-09 11:43:51 -0700192 bus, // PCI Bus
193 dev, // PCI Device
194 func, // PCI Function
195 pciOffset, // PCI Offset
196 data.data(), // PCI Read Data
197 &cc); // PECI Completion Code
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700198#endif
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300199 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700200 if (ret != PECI_CC_SUCCESS || cc != PECI_DEV_CC_SUCCESS)
201 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300202 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700203 }
204
205 // Now build the requested data into a single number
206 pciData = 0;
207 for (int i = mod; i < mod + size; i++)
208 {
Jason M. Billse55832b2021-06-14 16:00:49 -0700209 pciData |= static_cast<uint32_t>(data[i]) << 8 * (i - mod);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700210 }
211
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300212 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700213}
214
Andrei Kartashev6f552032021-05-11 21:25:29 +0300215static resCode getStringFromData(const int& size, const uint32_t& data,
216 std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700217{
Jason M. Billsd1e40602019-05-09 11:43:51 -0700218 // And convert it to a string
219 std::stringstream dataStream;
220 dataStream << "0x" << std::hex << std::setfill('0') << std::setw(size * 2)
221 << data;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300222 res = dataStream.str();
223 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700224}
225
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300226static resCode getVendorName(const int& clientAddr, const int& bus,
227 const int& dev, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700228{
229 static constexpr const int vendorIDOffset = 0x00;
230 static constexpr const int vendorIDSize = 2;
231
232 // Get the header type register from function 0
233 uint32_t vendorID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300234 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, vendorIDOffset,
235 vendorIDSize, vendorID) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700236 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300237 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700238 }
239 // Get the vendor name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300240 res = pciVendors.try_emplace(vendorID, otherVendor).first->second;
241 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700242}
243
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300244static resCode getDeviceClass(const int& clientAddr, const int& bus,
245 const int& dev, const int& func, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700246{
247 static constexpr const int baseClassOffset = 0x0b;
248 static constexpr const int baseClassSize = 1;
249
250 // Get the Device Base Class
251 uint32_t baseClass = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300252 if (getDataFromPCIeConfig(clientAddr, bus, dev, func, baseClassOffset,
253 baseClassSize, baseClass) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700254 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300255 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700256 }
257 // Get the base class name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300258 res = pciDeviceClasses.try_emplace(baseClass, otherClass).first->second;
259 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700260}
261
Spencer Kubb5efe72021-09-02 16:11:14 +0800262static resCode getCapReading(const int& clientAddr, const int& bus,
263 const int& dev, uint32_t& capReading,
264 const int compareCapID, const int offsetAddress,
265 const int offsetLength)
266{
267 resCode error;
268 uint32_t capAddress = 0;
269 uint32_t capabilityID;
270 uint32_t nextCapPointer = peci_pcie::pointToCapStruct;
271
272 do
273 {
274 // Get capability address
275 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, nextCapPointer,
276 1, capAddress);
277 if (error != resCode::resOk)
278 {
279 return error;
280 }
281 // Capability struct address is a pointer which point to next capability
282 // struct, so if capability struct address is 0 means it doesn't have
283 // next capability struct.
284 if (capAddress == 0)
285 {
286 return resCode::resSkip;
287 }
288 // Get capability ID
289 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, capAddress, 1,
290 capabilityID);
291 if (error != resCode::resOk)
292 {
293 return error;
294 }
295 nextCapPointer = capAddress + peci_pcie::capPointerOffset;
296
297 } while (capabilityID != compareCapID);
298 // Get capability reading.
299 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0,
300 capAddress + offsetAddress, offsetLength,
301 capReading);
302 if (error != resCode::resOk)
303 {
304 return error;
305 }
306 return resCode::resOk;
307}
308
309static resCode getGenerationInUse(const int& clientAddr, const int& bus,
310 const int& dev, std::string& generationInUse)
311{
312 resCode error;
313 std::string res;
314 uint32_t capReading = 0;
315
316 // Capability ID 0x10(16) is PCI Express
317 constexpr int pcieCapID = 16;
318 constexpr int capLength = 2;
319 uint32_t linkStatus;
320
321 error = getCapReading(clientAddr, bus, dev, linkStatus, pcieCapID,
322 peci_pcie::linkStatusOffset, capLength);
323 if (error != resCode::resOk)
324 {
325 return error;
326 }
327
328 uint32_t linkSpeed = linkStatus & peci_pcie::maskOfCLS;
329
330 switch (linkSpeed)
331 {
332 case peci_pcie::pcieGen1:
333 generationInUse = "xyz.openbmc_project.Inventory.Item."
334 "PCIeSlot.Generations.Gen1";
335 error = resCode::resOk;
336 break;
337 case peci_pcie::pcieGen2:
338 generationInUse = "xyz.openbmc_project.Inventory.Item."
339 "PCIeSlot.Generations.Gen2";
340 error = resCode::resOk;
341 break;
342 case peci_pcie::pcieGen3:
343 generationInUse = "xyz.openbmc_project.Inventory.Item."
344 "PCIeSlot.Generations.Gen3";
345 error = resCode::resOk;
346 break;
347 case peci_pcie::pcieGen4:
348 generationInUse = "xyz.openbmc_project.Inventory.Item."
349 "PCIeSlot.Generations.Gen4";
350 error = resCode::resOk;
351 break;
352 case peci_pcie::pcieGen5:
353 generationInUse = "xyz.openbmc_project.Inventory.Item."
354 "PCIeSlot.Generations.Gen5";
355 error = resCode::resOk;
356 break;
357 default:
358 std::cerr << "Link speed : " << linkSpeed
359 << " can not mapping to PCIe type list.\n";
360 error = resCode::resSkip;
361 }
362 return error;
363}
364
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300365static resCode isMultiFunction(const int& clientAddr, const int& bus,
366 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700367{
368 static constexpr const int headerTypeOffset = 0x0e;
369 static constexpr const int headerTypeSize = 1;
370 static constexpr const int multiFuncBit = 1 << 7;
371
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300372 res = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700373 // Get the header type register from function 0
374 uint32_t headerType = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300375 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, headerTypeOffset,
376 headerTypeSize, headerType) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700377 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300378 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700379 }
380 // Check if it's a multifunction device
381 if (headerType & multiFuncBit)
382 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300383 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700384 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300385 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700386}
387
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300388static resCode pcieFunctionExists(const int& clientAddr, const int& bus,
389 const int& dev, const int& func, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700390{
391 constexpr const int pciIDOffset = 0;
392 constexpr const int pciIDSize = 4;
393 uint32_t pciID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300394 res = false;
395 if (getDataFromPCIeConfig(clientAddr, bus, dev, func, pciIDOffset,
396 pciIDSize, pciID) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700397 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300398 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700399 }
400
401 // if VID and DID are all 0s or 1s, then the device doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300402 if (pciID != 0x00000000 && pciID != 0xFFFFFFFF)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700403 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300404 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700405 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300406 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700407}
408
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300409static resCode pcieDeviceExists(const int& clientAddr, const int& bus,
410 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700411{
412 // Check if this device exists by checking function 0
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300413 return pcieFunctionExists(clientAddr, bus, dev, 0, res);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700414}
415
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300416static resCode setPCIeProperty(const int& clientAddr, const int& bus,
417 const int& dev, const std::string& propertyName,
418 const std::string& propertyValue)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700419{
420 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
421 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
422
423 if (iface->is_initialized())
424 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300425 if (!iface->set_property(propertyName, propertyValue))
426 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700427 }
428 else
429 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300430 if (!iface->register_property(propertyName, propertyValue))
431 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700432 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300433 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700434}
435
436static void setDefaultPCIeFunctionProperties(const int& clientAddr,
437 const int& bus, const int& dev,
438 const int& func)
439{
440 // Set the function-specific properties
Andrei Kartashev6f552032021-05-11 21:25:29 +0300441 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700442 {
443 setPCIeProperty(clientAddr, bus, dev,
444 "Function" + std::to_string(func) + std::string(name),
445 std::string());
446 }
447}
448
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300449static resCode setPCIeFunctionProperties(const int& clientAddr, const int& bus,
450 const int& dev, const int& func)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700451{
Andrei Kartashev6f552032021-05-11 21:25:29 +0300452 uint32_t data = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300453 std::string res;
Andrei Kartashev6f552032021-05-11 21:25:29 +0300454 resCode error;
455
456 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
457 {
458 if (offset < 0)
459 {
460 continue;
461 }
462
463 error = getDataFromPCIeConfig(clientAddr, bus, dev, func, offset, size,
464 data);
465 if (error != resCode::resOk)
466 {
467 return error;
468 }
469 getStringFromData(size, data, res);
470 setPCIeProperty(clientAddr, bus, dev,
471 "Function" + std::to_string(func) + std::string(name),
472 res);
473 }
474
Jason M. Billsd1e40602019-05-09 11:43:51 -0700475 // Set the function type always to physical for now
476 setPCIeProperty(clientAddr, bus, dev,
477 "Function" + std::to_string(func) +
478 std::string(peci_pcie::function::functionTypeName),
479 "Physical");
480
481 // Set the function Device Class
Andrei Kartashev6f552032021-05-11 21:25:29 +0300482 error = getDeviceClass(clientAddr, bus, dev, func, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300483 if (error != resCode::resOk)
484 {
485 return error;
486 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700487 setPCIeProperty(clientAddr, bus, dev,
488 "Function" + std::to_string(func) +
489 std::string(peci_pcie::function::deviceClassName),
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300490 res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300491 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700492}
493
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300494static resCode setPCIeDeviceProperties(const int& clientAddr, const int& bus,
495 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700496{
497 // Set the device manufacturer
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300498 std::string manuf;
499 resCode error = getVendorName(clientAddr, bus, dev, manuf);
500 if (error != resCode::resOk)
501 {
502 return error;
503 }
504 setPCIeProperty(clientAddr, bus, dev, "Manufacturer", manuf);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700505
506 // Set the device type
507 constexpr char const* deviceTypeName = "DeviceType";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300508 bool multiFunc;
509 error = isMultiFunction(clientAddr, bus, dev, multiFunc);
510 if (error != resCode::resOk)
511 {
512 return error;
513 }
514 if (multiFunc)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700515 {
516 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "MultiFunction");
517 }
518 else
519 {
520 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "SingleFunction");
521 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800522
523 // Set PCIe Generation
524 constexpr char const* generationInUseName = "GenerationInUse";
525 std::string generationInUse;
526 error = getGenerationInUse(clientAddr, bus, dev, generationInUse);
527 if (error == resCode::resErr)
528 {
529 return error;
530 }
531 // "resSkip" status means it can't get the capability reading, such like
532 // this device is not PCI Express.
533 if (error == resCode::resSkip)
534 {
535 setPCIeProperty(clientAddr, bus, dev, generationInUseName, "");
536 return resCode::resOk;
537 }
538 setPCIeProperty(clientAddr, bus, dev, generationInUseName, generationInUse);
539
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300540 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700541}
542
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300543static resCode updatePCIeDevice(const int& clientAddr, const int& bus,
544 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700545{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300546 if (setPCIeDeviceProperties(clientAddr, bus, dev) != resCode::resOk)
547 {
548 return resCode::resErr;
549 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700550
551 // Walk through and populate the functions for this device
552 for (int func = 0; func < peci_pcie::maxPCIFunctions; func++)
553 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300554 bool res;
555 resCode error = pcieFunctionExists(clientAddr, bus, dev, func, res);
556 if (error != resCode::resOk)
557 {
558 return error;
559 }
560 if (res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700561 {
562 // Set the properties for this function
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300563 if (setPCIeFunctionProperties(clientAddr, bus, dev, func) !=
564 resCode::resOk)
565 {
566 return resCode::resErr;
567 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700568 }
569 else
570 {
571 // Set default properties for unused functions
572 setDefaultPCIeFunctionProperties(clientAddr, bus, dev, func);
573 }
574 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300575 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700576}
577
578static void removePCIeDevice(sdbusplus::asio::object_server& objServer,
579 const int& clientAddr, const int& bus,
580 const int& dev)
581{
582 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
583 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
584
585 objServer.remove_interface(iface);
586
587 peci_pcie::pcieDeviceDBusMap[clientAddr][bus].erase(dev);
588 if (peci_pcie::pcieDeviceDBusMap[clientAddr][bus].empty())
589 {
590 peci_pcie::pcieDeviceDBusMap[clientAddr].erase(bus);
591 }
592 if (peci_pcie::pcieDeviceDBusMap[clientAddr].empty())
593 {
594 peci_pcie::pcieDeviceDBusMap.erase(clientAddr);
595 }
596}
597
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300598static resCode addPCIeDevice(sdbusplus::asio::object_server& objServer,
599 const int& clientAddr, const int& cpu,
600 const int& bus, const int& dev)
601{
602 std::string pathName = std::string(peci_pcie::peciPCIePath) + "/S" +
603 std::to_string(cpu) + "B" + std::to_string(bus) +
604 "D" + std::to_string(dev);
605 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
606 objServer.add_interface(pathName, peci_pcie::peciPCIeDeviceInterface);
607 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev] = iface;
608
609 // Update the properties for the new device
610 if (updatePCIeDevice(clientAddr, bus, dev) != resCode::resOk)
611 {
612 removePCIeDevice(objServer, clientAddr, bus, dev);
613 return resCode::resErr;
614 }
615
616 iface->initialize();
617 return resCode::resOk;
618}
619
Jason M. Billsd1e40602019-05-09 11:43:51 -0700620static bool pcieDeviceInDBusMap(const int& clientAddr, const int& bus,
621 const int& dev)
622{
623 if (auto clientAddrIt = peci_pcie::pcieDeviceDBusMap.find(clientAddr);
624 clientAddrIt != peci_pcie::pcieDeviceDBusMap.end())
625 {
626 if (auto busIt = clientAddrIt->second.find(bus);
627 busIt != clientAddrIt->second.end())
628 {
629 if (auto devIt = busIt->second.find(dev);
630 devIt != busIt->second.end())
631 {
632 if (devIt->second)
633 {
634 return true;
635 }
636 }
637 }
638 }
639 return false;
640}
641
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300642static resCode probePCIeDevice(boost::asio::io_service& io,
643 sdbusplus::asio::object_server& objServer,
Andrei Kartashev8e966032021-07-02 20:04:30 +0300644 size_t addr, int cpu, int bus, int dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700645{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300646 bool res;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300647 resCode error = pcieDeviceExists(addr, bus, dev, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300648 if (error != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700649 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300650 return error;
Jason M. Bills5d049732019-10-25 15:55:15 -0700651 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300652 if (res)
Jason M. Bills5d049732019-10-25 15:55:15 -0700653 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300654 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700655 {
656 // This device is already in D-Bus, so update it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300657 if (updatePCIeDevice(addr, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300658 {
659 return resCode::resErr;
660 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700661 }
662 else
663 {
664 // This device is not in D-Bus, so add it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300665 if (addPCIeDevice(objServer, addr, cpu, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300666 {
667 return resCode::resErr;
668 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700669 }
670 }
671 else
672 {
673 // If PECI is not available, then stop scanning
674 if (!isPECIAvailable())
675 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300676 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700677 }
678
Andrei Kartashev8e966032021-07-02 20:04:30 +0300679 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700680 {
681 // This device is in D-Bus, so remove it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300682 removePCIeDevice(objServer, addr, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700683 }
684 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300685 return resCode::resOk;
686}
687
Andrei Kartashev8e966032021-07-02 20:04:30 +0300688static void scanNextPCIeDevice(boost::asio::io_service& io,
689 sdbusplus::asio::object_server& objServer,
690 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
691 int dev);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300692static void scanPCIeDevice(boost::asio::io_service& io,
693 sdbusplus::asio::object_server& objServer,
694 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
695 int dev)
696{
Andrei Kartashev8e966032021-07-02 20:04:30 +0300697 if (cpu >= cpuInfo.size())
698 {
699 std::cerr << "Request to scan CPU" << cpu
700 << " while CPU array has size " << cpuInfo.size() << "\n";
701 return;
702 }
703 auto& info = cpuInfo[cpu];
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300704 // Check if this is a CPU bus that we should skip
Andrei Kartashev8e966032021-07-02 20:04:30 +0300705 if (info.skipCpuBuses && info.cpuBusNums.count(bus))
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300706 {
707 std::cout << "Skipping CPU " << cpu << " Bus Number " << bus << "\n";
708 // Skip all the devices on this bus
709 dev = peci_pcie::maxPCIDevices;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300710 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300711 else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300712 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300713 if (probePCIeDevice(io, objServer, info.addr, cpu, bus, dev) !=
714 resCode::resOk)
715 {
716 std::cerr << "Failed to probe CPU " << cpu << " Bus " << bus
717 << " Device " << dev << "\n";
718 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300719 }
720
Jason M. Bills5d049732019-10-25 15:55:15 -0700721 scanNextPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Andrei Kartashev8e966032021-07-02 20:04:30 +0300722 return;
Jason M. Bills5d049732019-10-25 15:55:15 -0700723}
Jason M. Billsd1e40602019-05-09 11:43:51 -0700724
Jason M. Bills5d049732019-10-25 15:55:15 -0700725static void scanNextPCIeDevice(boost::asio::io_service& io,
726 sdbusplus::asio::object_server& objServer,
727 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
728 int dev)
729{
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700730 if (peci_pcie::abortScan)
731 {
732 std::cerr << "PCIe scan aborted\n";
733 return;
734 }
735
Jason M. Billsd1e40602019-05-09 11:43:51 -0700736 // PCIe Device scan completed, so move to the next device
737 if (++dev >= peci_pcie::maxPCIDevices)
738 {
739 // All devices scanned, so move to the next bus
740 dev = 0;
741 if (++bus >= peci_pcie::maxPCIBuses)
742 {
743 // All buses scanned, so move to the next CPU
744 bus = 0;
Jason M. Bills5d049732019-10-25 15:55:15 -0700745 if (++cpu >= cpuInfo.size())
Jason M. Billsd1e40602019-05-09 11:43:51 -0700746 {
747 // All CPUs scanned, so we're done
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700748 std::cerr << "PCIe scan completed\n";
Jason M. Billsd1e40602019-05-09 11:43:51 -0700749 return;
750 }
751 }
752 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300753 boost::asio::post(io, [&io, &objServer, &cpuInfo, cpu, bus, dev]() mutable {
Jason M. Bills5d049732019-10-25 15:55:15 -0700754 scanPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700755 });
756}
757
758static void peciAvailableCheck(boost::asio::steady_timer& peciWaitTimer,
759 boost::asio::io_service& io,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300760 sdbusplus::asio::object_server& objServer,
761 std::vector<CPUInfo>& cpuInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700762{
Jason M. Bills5d049732019-10-25 15:55:15 -0700763 static bool lastPECIState = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700764 bool peciAvailable = isPECIAvailable();
765 if (peciAvailable && !lastPECIState)
766 {
767 lastPECIState = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700768 static boost::asio::steady_timer pcieTimeout(io);
769 constexpr const int pcieWaitTime = 60;
770 pcieTimeout.expires_after(std::chrono::seconds(pcieWaitTime));
771 pcieTimeout.async_wait(
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300772 [&io, &objServer, &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700773 if (ec)
774 {
775 // operation_aborted is expected if timer is canceled
776 // before completion.
777 if (ec != boost::asio::error::operation_aborted)
778 {
779 std::cerr << "PECI PCIe async_wait failed " << ec;
780 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300781 lastPECIState = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700782 return;
783 }
784 // get the PECI client address list
Andrei Kartashev8e966032021-07-02 20:04:30 +0300785 if (getCPUBusMap(cpuInfo) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300786 {
787 lastPECIState = false;
788 return;
789 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700790 // scan PCIe starting from CPU 0, Bus 0, Device 0
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700791 std::cerr << "PCIe scan started\n";
Jason M. Bills5d049732019-10-25 15:55:15 -0700792 scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700793 });
794 }
795 else if (!peciAvailable && lastPECIState)
796 {
797 lastPECIState = false;
798 }
799
800 peciWaitTimer.expires_after(
801 std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300802 peciWaitTimer.async_wait([&peciWaitTimer, &io, &objServer,
803 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700804 if (ec)
805 {
806 // operation_aborted is expected if timer is canceled
807 // before completion.
808 if (ec != boost::asio::error::operation_aborted)
809 {
810 std::cerr << "PECI Available Check async_wait failed " << ec;
811 }
812 return;
813 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300814 peciAvailableCheck(peciWaitTimer, io, objServer, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700815 });
816}
817
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700818static void waitForOSStandbyDelay(boost::asio::io_service& io,
819 sdbusplus::asio::object_server& objServer,
820 boost::asio::steady_timer& osStandbyTimer,
821 std::vector<CPUInfo>& cpuInfo)
822{
823 osStandbyTimer.expires_after(
824 std::chrono::seconds(peci_pcie::osStandbyDelaySeconds));
825
826 osStandbyTimer.async_wait(
827 [&io, &objServer, &cpuInfo](const boost::system::error_code& ec) {
828 if (ec == boost::asio::error::operation_aborted)
829 {
830 return; // we're being canceled
831 }
832 else if (ec)
833 {
834 std::cerr << "OS Standby async_wait failed: " << ec.value()
835 << ": " << ec.message() << "\n";
836 return;
837 }
838 // get the PECI client address list
Andrei Kartashev8e966032021-07-02 20:04:30 +0300839 if (getCPUBusMap(cpuInfo) != resCode::resOk)
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700840 {
841 return;
842 }
843 // scan PCIe starting from CPU 0, Bus 0, Device 0
844 std::cerr << "PCIe scan started\n";
845 scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
846 });
847}
848
849static void monitorOSStandby(boost::asio::io_service& io,
850 std::shared_ptr<sdbusplus::asio::connection> conn,
851 sdbusplus::asio::object_server& objServer,
852 boost::asio::steady_timer& osStandbyTimer,
853 std::vector<CPUInfo>& cpuInfo)
854{
855 std::cerr << "Start OperatingSystemState Monitor\n";
856
857 static sdbusplus::bus::match::match osStateMatch(
858 *conn,
859 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
860 "PropertiesChanged',arg0='xyz.openbmc_project.State.OperatingSystem."
861 "Status'",
862 [&io, &objServer, &osStandbyTimer,
863 &cpuInfo](sdbusplus::message::message& msg) {
864 // Get the OS State from the message
865 std::string osStateInterface;
866 boost::container::flat_map<std::string, std::variant<std::string>>
867 propertiesChanged;
868 msg.read(osStateInterface, propertiesChanged);
869
870 for (const auto& [name, value] : propertiesChanged)
871 {
872 if (name == "OperatingSystemState")
873 {
874 const std::string* state = std::get_if<std::string>(&value);
875 if (state == nullptr)
876 {
877 std::cerr << "Unable to read OS state value\n";
878 return;
879 }
Andrei Kartashev328685e2021-12-27 17:24:18 +0300880 // Note: Short version of OperatingSystemState value is
881 // deprecated and would be removed in the future
882 if ((*state == "Standby") ||
883 (*state == "xyz.openbmc_project.State.OperatingSystem."
884 "Status.OSStatus.Standby"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700885 {
886 peci_pcie::abortScan = false;
887 waitForOSStandbyDelay(io, objServer, osStandbyTimer,
888 cpuInfo);
889 }
Andrei Kartashev328685e2021-12-27 17:24:18 +0300890 else if ((*state == "Inactive") ||
891 (*state ==
892 "xyz.openbmc_project.State.OperatingSystem."
893 "Status.OSStatus.Inactive"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700894 {
895 peci_pcie::abortScan = true;
896 osStandbyTimer.cancel();
897 }
898 }
899 }
900 });
901
902 // Check if the OS state is already available
903 conn->async_method_call(
904 [&io, &objServer, &osStandbyTimer,
905 &cpuInfo](boost::system::error_code ec,
906 const std::variant<std::string>& property) {
907 if (ec)
908 {
909 std::cerr << "error with OS state async_method_call\n";
910 return;
911 }
912
913 const std::string* state = std::get_if<std::string>(&property);
914 if (state == nullptr)
915 {
916 std::cerr << "Unable to read OS state value\n";
917 return;
918 }
919
920 // If the OS state is in Standby, then BIOS is done and we can
921 // continue. Otherwise, we just wait for the match
Andrei Kartashev328685e2021-12-27 17:24:18 +0300922 // Note: Short version of OperatingSystemState value is deprecated
923 // and would be removed in the future
924
925 if ((*state == "Standby") ||
926 (*state == "xyz.openbmc_project.State.OperatingSystem.Status."
927 "OSStatus.Standby"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700928 {
929 waitForOSStandbyDelay(io, objServer, osStandbyTimer, cpuInfo);
930 }
931 },
932 "xyz.openbmc_project.State.OperatingSystem",
933 "/xyz/openbmc_project/state/os", "org.freedesktop.DBus.Properties",
934 "Get", "xyz.openbmc_project.State.OperatingSystem.Status",
935 "OperatingSystemState");
936}
937
Jason M. Billsd1e40602019-05-09 11:43:51 -0700938int main(int argc, char* argv[])
939{
940 // setup connection to dbus
941 boost::asio::io_service io;
942 std::shared_ptr<sdbusplus::asio::connection> conn =
943 std::make_shared<sdbusplus::asio::connection>(io);
944
945 // PECI PCIe Object
946 conn->request_name(peci_pcie::peciPCIeObject);
947 sdbusplus::asio::object_server server =
948 sdbusplus::asio::object_server(conn);
949
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300950 // CPU map
951 std::vector<CPUInfo> cpuInfo;
952
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700953#ifdef WAIT_FOR_OS_STANDBY
954 boost::asio::steady_timer osStandbyTimer(io);
955 monitorOSStandby(io, conn, server, osStandbyTimer, cpuInfo);
956#else
Jason M. Billsd1e40602019-05-09 11:43:51 -0700957 // Start the PECI check loop
958 boost::asio::steady_timer peciWaitTimer(
959 io, std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300960 peciWaitTimer.async_wait([&peciWaitTimer, &io, &server,
961 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700962 if (ec)
963 {
964 // operation_aborted is expected if timer is canceled
965 // before completion.
966 if (ec != boost::asio::error::operation_aborted)
967 {
968 std::cerr << "PECI Available Check async_wait failed " << ec;
969 }
970 return;
971 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300972 peciAvailableCheck(peciWaitTimer, io, server, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700973 });
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700974#endif
Jason M. Billsd1e40602019-05-09 11:43:51 -0700975
976 io.run();
977
978 return 0;
979}