blob: eabdf8493be154460e197a57ad7561cdc80ec8f3 [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>
Willy Tu975faf72022-09-23 18:39:16 +000033#include <unordered_set>
Jason M. Billsd1e40602019-05-09 11:43:51 -070034
35namespace peci_pcie
36{
37static boost::container::flat_map<
38 int, boost::container::flat_map<
39 int, boost::container::flat_map<
40 int, std::shared_ptr<sdbusplus::asio::dbus_interface>>>>
41 pcieDeviceDBusMap;
42
Jason M. Billsee6d80b2021-06-11 07:37:30 -070043static bool abortScan;
Paul Fertser07343142022-12-01 21:04:57 +000044static bool scanInProgress;
Jason M. Billsee6d80b2021-06-11 07:37:30 -070045
Jason M. Billsd1e40602019-05-09 11:43:51 -070046namespace function
47{
48static constexpr char const* functionTypeName = "FunctionType";
49static constexpr char const* deviceClassName = "DeviceClass";
50static constexpr char const* vendorIdName = "VendorId";
51static constexpr char const* deviceIdName = "DeviceId";
52static constexpr char const* classCodeName = "ClassCode";
53static constexpr char const* revisionIdName = "RevisionId";
54static constexpr char const* subsystemIdName = "SubsystemId";
55static constexpr char const* subsystemVendorIdName = "SubsystemVendorId";
56} // namespace function
Andrei Kartashev6f552032021-05-11 21:25:29 +030057
58static constexpr const std::array pciConfigInfo{
59 std::tuple<const char*, int, int>{function::functionTypeName, -1, -1},
60 std::tuple<const char*, int, int>{function::deviceClassName, -1, -1},
61 std::tuple<const char*, int, int>{function::vendorIdName, 0, 2},
62 std::tuple<const char*, int, int>{function::deviceIdName, 2, 2},
63 std::tuple<const char*, int, int>{function::classCodeName, 9, 3},
64 std::tuple<const char*, int, int>{function::revisionIdName, 8, 1},
65 std::tuple<const char*, int, int>{function::subsystemIdName, 0x2e, 2},
66 std::tuple<const char*, int, int>{function::subsystemVendorIdName, 0x2c,
67 2}};
Jason M. Billsd1e40602019-05-09 11:43:51 -070068} // namespace peci_pcie
69
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030070enum class resCode
71{
72 resOk,
Spencer Kubb5efe72021-09-02 16:11:14 +080073 resSkip,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030074 resErr
75};
76
Jason M. Bills5d049732019-10-25 15:55:15 -070077struct CPUInfo
Jason M. Billsd1e40602019-05-09 11:43:51 -070078{
Jason M. Bills5d049732019-10-25 15:55:15 -070079 size_t addr;
80 bool skipCpuBuses;
81 boost::container::flat_set<size_t> cpuBusNums;
82};
83
84// PECI Client Address Map
Andrei Kartashev8e966032021-07-02 20:04:30 +030085static resCode getCPUBusMap(std::vector<CPUInfo>& cpuInfo)
Jason M. Bills5d049732019-10-25 15:55:15 -070086{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030087 cpuInfo.clear();
Andrei Kartashev8e966032021-07-02 20:04:30 +030088 for (size_t addr = MIN_CLIENT_ADDR; addr <= MAX_CLIENT_ADDR; addr++)
Jason M. Billsd1e40602019-05-09 11:43:51 -070089 {
Andrei Kartashev8e966032021-07-02 20:04:30 +030090 if (peci_Ping(addr) != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -070091 {
Andrei Kartashev8e966032021-07-02 20:04:30 +030092 continue;
Jason M. Bills5d049732019-10-25 15:55:15 -070093 }
Jason M. Bills5d049732019-10-25 15:55:15 -070094
Andrei Kartashev8e966032021-07-02 20:04:30 +030095 auto& cpu = cpuInfo.emplace_back(CPUInfo{addr, false, {}});
Jason M. Bills5d049732019-10-25 15:55:15 -070096 uint8_t cc = 0;
97 CPUModel model{};
98 uint8_t stepping = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +030099 if (peci_GetCPUID(addr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Jason M. Bills5d049732019-10-25 15:55:15 -0700100 {
101 std::cerr << "Cannot get CPUID!\n";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300102 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700103 }
104
105 switch (model)
106 {
107 case skx:
108 {
109 // Get the assigned CPU bus numbers from CPUBUSNO and CPUBUSNO1
110 // (B(0) D8 F2 offsets CCh and D0h)
111 uint32_t cpuBusNum = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300112 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xCC, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700113 (uint8_t*)&cpuBusNum,
114 &cc) != PECI_CC_SUCCESS)
115 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300116 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700117 }
118 uint32_t cpuBusNum1 = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300119 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xD0, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700120 (uint8_t*)&cpuBusNum1,
121 &cc) != PECI_CC_SUCCESS)
122 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300123 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700124 }
125
126 // Add the CPU bus numbers to the set for this CPU
127 while (cpuBusNum)
128 {
129 // Get the LSB
130 size_t busNum = cpuBusNum & 0xFF;
131 cpu.cpuBusNums.insert(busNum);
132 // Shift right by one byte
133 cpuBusNum >>= 8;
134 }
135 while (cpuBusNum1)
136 {
137 // Get the LSB
138 size_t busNum = cpuBusNum1 & 0xFF;
139 cpu.cpuBusNums.insert(busNum);
140 // Shift right by one byte
Zev Weiss9fa54b52020-09-02 21:20:33 +0000141 cpuBusNum1 >>= 8;
Jason M. Bills5d049732019-10-25 15:55:15 -0700142 }
143 cpu.skipCpuBuses = true;
144 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700145 }
146 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300147 return cpuInfo.empty() ? resCode::resErr : resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700148}
149
150static bool isPECIAvailable(void)
151{
Jason M. Bills5d049732019-10-25 15:55:15 -0700152 for (size_t i = MIN_CLIENT_ADDR; i <= MAX_CLIENT_ADDR; i++)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700153 {
Jason M. Bills5d049732019-10-25 15:55:15 -0700154 if (peci_Ping(i) == PECI_CC_SUCCESS)
155 {
156 return true;
157 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700158 }
Jason M. Bills5d049732019-10-25 15:55:15 -0700159 return false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700160}
161
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300162static resCode getDataFromPCIeConfig(const int& clientAddr, const int& bus,
163 const int& dev, const int& func,
164 const int& offset, const int& size,
165 uint32_t& pciData)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700166{
167 // PECI RdPCIConfig() currently only supports 4 byte reads, so adjust
168 // the offset and size to get the right data
169 static constexpr const int pciReadSize = 4;
170 int mod = offset % pciReadSize;
171 int pciOffset = offset - mod;
172 if (mod + size > pciReadSize)
173 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300174 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700175 }
176
177 std::array<uint8_t, pciReadSize> data;
178 uint8_t cc;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300179 int ret = PECI_CC_TIMEOUT;
Paul Fertserb08723d2022-12-16 11:49:08 +0000180 for (int index = 0; (index < 15) && (ret == PECI_CC_TIMEOUT); index++)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300181 {
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700182#ifdef USE_RDENDPOINTCFG
183 ret = peci_RdEndPointConfigPci(clientAddr, // CPU Address
184 0, // PCI Seg (use 0 for now)
185 bus, // PCI Bus
186 dev, // PCI Device
187 func, // PCI Function
188 pciOffset, // PCI Offset
189 pciReadSize, // PCI Read Size
190 data.data(), // PCI Read Data
191 &cc); // PECI Completion Code
192#else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300193 ret = peci_RdPCIConfig(clientAddr, // CPU Address
Jason M. Billsd1e40602019-05-09 11:43:51 -0700194 bus, // PCI Bus
195 dev, // PCI Device
196 func, // PCI Function
197 pciOffset, // PCI Offset
198 data.data(), // PCI Read Data
199 &cc); // PECI Completion Code
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700200#endif
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300201 }
Paul Fertser541637c2022-12-02 13:42:01 +0000202 if (ret != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700203 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300204 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700205 }
Paul Fertser541637c2022-12-02 13:42:01 +0000206 else if (cc != PECI_DEV_CC_SUCCESS)
207 {
208 return resCode::resSkip;
209 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700210
211 // Now build the requested data into a single number
212 pciData = 0;
213 for (int i = mod; i < mod + size; i++)
214 {
Jason M. Billse55832b2021-06-14 16:00:49 -0700215 pciData |= static_cast<uint32_t>(data[i]) << 8 * (i - mod);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700216 }
217
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300218 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700219}
220
Andrei Kartashev6f552032021-05-11 21:25:29 +0300221static resCode getStringFromData(const int& size, const uint32_t& data,
222 std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700223{
Jason M. Billsd1e40602019-05-09 11:43:51 -0700224 // And convert it to a string
225 std::stringstream dataStream;
226 dataStream << "0x" << std::hex << std::setfill('0') << std::setw(size * 2)
227 << data;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300228 res = dataStream.str();
229 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700230}
231
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300232static resCode getVendorName(const int& clientAddr, const int& bus,
233 const int& dev, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700234{
235 static constexpr const int vendorIDOffset = 0x00;
236 static constexpr const int vendorIDSize = 2;
237
238 // Get the header type register from function 0
239 uint32_t vendorID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300240 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, vendorIDOffset,
241 vendorIDSize, vendorID) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700242 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300243 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700244 }
245 // Get the vendor name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300246 res = pciVendors.try_emplace(vendorID, otherVendor).first->second;
247 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700248}
249
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300250static resCode getDeviceClass(const int& clientAddr, const int& bus,
251 const int& dev, const int& func, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700252{
253 static constexpr const int baseClassOffset = 0x0b;
254 static constexpr const int baseClassSize = 1;
255
256 // Get the Device Base Class
257 uint32_t baseClass = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300258 if (getDataFromPCIeConfig(clientAddr, bus, dev, func, baseClassOffset,
259 baseClassSize, baseClass) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700260 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300261 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700262 }
263 // Get the base class name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300264 res = pciDeviceClasses.try_emplace(baseClass, otherClass).first->second;
265 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700266}
267
Spencer Kubb5efe72021-09-02 16:11:14 +0800268static resCode getCapReading(const int& clientAddr, const int& bus,
269 const int& dev, uint32_t& capReading,
270 const int compareCapID, const int offsetAddress,
271 const int offsetLength)
272{
273 resCode error;
274 uint32_t capAddress = 0;
275 uint32_t capabilityID;
276 uint32_t nextCapPointer = peci_pcie::pointToCapStruct;
277
278 do
279 {
280 // Get capability address
281 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, nextCapPointer,
282 1, capAddress);
283 if (error != resCode::resOk)
284 {
285 return error;
286 }
287 // Capability struct address is a pointer which point to next capability
288 // struct, so if capability struct address is 0 means it doesn't have
289 // next capability struct.
290 if (capAddress == 0)
291 {
292 return resCode::resSkip;
293 }
294 // Get capability ID
295 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, capAddress, 1,
296 capabilityID);
297 if (error != resCode::resOk)
298 {
299 return error;
300 }
301 nextCapPointer = capAddress + peci_pcie::capPointerOffset;
302
303 } while (capabilityID != compareCapID);
304 // Get capability reading.
305 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0,
306 capAddress + offsetAddress, offsetLength,
307 capReading);
308 if (error != resCode::resOk)
309 {
310 return error;
311 }
312 return resCode::resOk;
313}
314
315static resCode getGenerationInUse(const int& clientAddr, const int& bus,
316 const int& dev, std::string& generationInUse)
317{
Willy Tu975faf72022-09-23 18:39:16 +0000318 static std::unordered_set<uint32_t> linkSpeedSkipMap;
Spencer Kubb5efe72021-09-02 16:11:14 +0800319 resCode error;
320 std::string res;
321 uint32_t capReading = 0;
322
323 // Capability ID 0x10(16) is PCI Express
324 constexpr int pcieCapID = 16;
325 constexpr int capLength = 2;
326 uint32_t linkStatus;
327
328 error = getCapReading(clientAddr, bus, dev, linkStatus, pcieCapID,
329 peci_pcie::linkStatusOffset, capLength);
330 if (error != resCode::resOk)
331 {
332 return error;
333 }
334
335 uint32_t linkSpeed = linkStatus & peci_pcie::maskOfCLS;
336
337 switch (linkSpeed)
338 {
339 case peci_pcie::pcieGen1:
340 generationInUse = "xyz.openbmc_project.Inventory.Item."
341 "PCIeSlot.Generations.Gen1";
342 error = resCode::resOk;
343 break;
344 case peci_pcie::pcieGen2:
345 generationInUse = "xyz.openbmc_project.Inventory.Item."
346 "PCIeSlot.Generations.Gen2";
347 error = resCode::resOk;
348 break;
349 case peci_pcie::pcieGen3:
350 generationInUse = "xyz.openbmc_project.Inventory.Item."
351 "PCIeSlot.Generations.Gen3";
352 error = resCode::resOk;
353 break;
354 case peci_pcie::pcieGen4:
355 generationInUse = "xyz.openbmc_project.Inventory.Item."
356 "PCIeSlot.Generations.Gen4";
357 error = resCode::resOk;
358 break;
359 case peci_pcie::pcieGen5:
360 generationInUse = "xyz.openbmc_project.Inventory.Item."
361 "PCIeSlot.Generations.Gen5";
362 error = resCode::resOk;
363 break;
364 default:
Willy Tu975faf72022-09-23 18:39:16 +0000365 if (!linkSpeedSkipMap.contains(linkSpeed))
366 {
367 std::cerr << "Link speed : " << linkSpeed
368 << " can not mapping to PCIe type list.\n";
369 linkSpeedSkipMap.emplace(linkSpeed);
370 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800371 error = resCode::resSkip;
372 }
373 return error;
374}
375
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300376static resCode isMultiFunction(const int& clientAddr, const int& bus,
377 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700378{
379 static constexpr const int headerTypeOffset = 0x0e;
380 static constexpr const int headerTypeSize = 1;
381 static constexpr const int multiFuncBit = 1 << 7;
382
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300383 res = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700384 // Get the header type register from function 0
385 uint32_t headerType = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300386 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, headerTypeOffset,
387 headerTypeSize, headerType) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700388 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300389 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700390 }
391 // Check if it's a multifunction device
392 if (headerType & multiFuncBit)
393 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300394 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700395 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300396 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700397}
398
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300399static resCode pcieFunctionExists(const int& clientAddr, const int& bus,
400 const int& dev, const int& func, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700401{
402 constexpr const int pciIDOffset = 0;
403 constexpr const int pciIDSize = 4;
404 uint32_t pciID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300405 res = false;
Paul Fertser541637c2022-12-02 13:42:01 +0000406
407 resCode error = getDataFromPCIeConfig(clientAddr, bus, dev, func,
408 pciIDOffset, pciIDSize, pciID);
409 if (error == resCode::resSkip)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700410 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300411 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700412 }
Paul Fertser541637c2022-12-02 13:42:01 +0000413 else if (error == resCode::resErr)
414 {
415 return resCode::resErr;
416 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700417
418 // if VID and DID are all 0s or 1s, then the device doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300419 if (pciID != 0x00000000 && pciID != 0xFFFFFFFF)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700420 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300421 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700422 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300423 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700424}
425
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300426static resCode pcieDeviceExists(const int& clientAddr, const int& bus,
427 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700428{
429 // Check if this device exists by checking function 0
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300430 return pcieFunctionExists(clientAddr, bus, dev, 0, res);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700431}
432
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300433static resCode setPCIeProperty(const int& clientAddr, const int& bus,
434 const int& dev, const std::string& propertyName,
435 const std::string& propertyValue)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700436{
437 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
438 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
439
440 if (iface->is_initialized())
441 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300442 if (!iface->set_property(propertyName, propertyValue))
443 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700444 }
445 else
446 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300447 if (!iface->register_property(propertyName, propertyValue))
448 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700449 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300450 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700451}
452
453static void setDefaultPCIeFunctionProperties(const int& clientAddr,
454 const int& bus, const int& dev,
455 const int& func)
456{
457 // Set the function-specific properties
Andrei Kartashev6f552032021-05-11 21:25:29 +0300458 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700459 {
460 setPCIeProperty(clientAddr, bus, dev,
461 "Function" + std::to_string(func) + std::string(name),
462 std::string());
463 }
464}
465
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300466static resCode setPCIeFunctionProperties(const int& clientAddr, const int& bus,
467 const int& dev, const int& func)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700468{
Andrei Kartashev6f552032021-05-11 21:25:29 +0300469 uint32_t data = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300470 std::string res;
Andrei Kartashev6f552032021-05-11 21:25:29 +0300471 resCode error;
472
473 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
474 {
475 if (offset < 0)
476 {
477 continue;
478 }
479
480 error = getDataFromPCIeConfig(clientAddr, bus, dev, func, offset, size,
481 data);
482 if (error != resCode::resOk)
483 {
484 return error;
485 }
486 getStringFromData(size, data, res);
487 setPCIeProperty(clientAddr, bus, dev,
488 "Function" + std::to_string(func) + std::string(name),
489 res);
490 }
491
Jason M. Billsd1e40602019-05-09 11:43:51 -0700492 // Set the function type always to physical for now
493 setPCIeProperty(clientAddr, bus, dev,
494 "Function" + std::to_string(func) +
495 std::string(peci_pcie::function::functionTypeName),
496 "Physical");
497
498 // Set the function Device Class
Andrei Kartashev6f552032021-05-11 21:25:29 +0300499 error = getDeviceClass(clientAddr, bus, dev, func, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300500 if (error != resCode::resOk)
501 {
502 return error;
503 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700504 setPCIeProperty(clientAddr, bus, dev,
505 "Function" + std::to_string(func) +
506 std::string(peci_pcie::function::deviceClassName),
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300507 res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300508 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700509}
510
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300511static resCode setPCIeDeviceProperties(const int& clientAddr, const int& bus,
512 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700513{
514 // Set the device manufacturer
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300515 std::string manuf;
516 resCode error = getVendorName(clientAddr, bus, dev, manuf);
517 if (error != resCode::resOk)
518 {
519 return error;
520 }
521 setPCIeProperty(clientAddr, bus, dev, "Manufacturer", manuf);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700522
523 // Set the device type
524 constexpr char const* deviceTypeName = "DeviceType";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300525 bool multiFunc;
526 error = isMultiFunction(clientAddr, bus, dev, multiFunc);
527 if (error != resCode::resOk)
528 {
529 return error;
530 }
531 if (multiFunc)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700532 {
533 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "MultiFunction");
534 }
535 else
536 {
537 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "SingleFunction");
538 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800539
540 // Set PCIe Generation
541 constexpr char const* generationInUseName = "GenerationInUse";
542 std::string generationInUse;
543 error = getGenerationInUse(clientAddr, bus, dev, generationInUse);
544 if (error == resCode::resErr)
545 {
546 return error;
547 }
548 // "resSkip" status means it can't get the capability reading, such like
549 // this device is not PCI Express.
550 if (error == resCode::resSkip)
551 {
552 setPCIeProperty(clientAddr, bus, dev, generationInUseName, "");
553 return resCode::resOk;
554 }
555 setPCIeProperty(clientAddr, bus, dev, generationInUseName, generationInUse);
556
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300557 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700558}
559
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300560static resCode updatePCIeDevice(const int& clientAddr, const int& bus,
561 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700562{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300563 if (setPCIeDeviceProperties(clientAddr, bus, dev) != resCode::resOk)
564 {
565 return resCode::resErr;
566 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700567
568 // Walk through and populate the functions for this device
569 for (int func = 0; func < peci_pcie::maxPCIFunctions; func++)
570 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300571 bool res;
572 resCode error = pcieFunctionExists(clientAddr, bus, dev, func, res);
573 if (error != resCode::resOk)
574 {
575 return error;
576 }
577 if (res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700578 {
579 // Set the properties for this function
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300580 if (setPCIeFunctionProperties(clientAddr, bus, dev, func) !=
581 resCode::resOk)
582 {
583 return resCode::resErr;
584 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700585 }
586 else
587 {
588 // Set default properties for unused functions
589 setDefaultPCIeFunctionProperties(clientAddr, bus, dev, func);
590 }
591 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300592 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700593}
594
595static void removePCIeDevice(sdbusplus::asio::object_server& objServer,
596 const int& clientAddr, const int& bus,
597 const int& dev)
598{
599 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
600 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
601
602 objServer.remove_interface(iface);
603
604 peci_pcie::pcieDeviceDBusMap[clientAddr][bus].erase(dev);
605 if (peci_pcie::pcieDeviceDBusMap[clientAddr][bus].empty())
606 {
607 peci_pcie::pcieDeviceDBusMap[clientAddr].erase(bus);
608 }
609 if (peci_pcie::pcieDeviceDBusMap[clientAddr].empty())
610 {
611 peci_pcie::pcieDeviceDBusMap.erase(clientAddr);
612 }
613}
614
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300615static resCode addPCIeDevice(sdbusplus::asio::object_server& objServer,
616 const int& clientAddr, const int& cpu,
617 const int& bus, const int& dev)
618{
619 std::string pathName = std::string(peci_pcie::peciPCIePath) + "/S" +
620 std::to_string(cpu) + "B" + std::to_string(bus) +
621 "D" + std::to_string(dev);
622 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
623 objServer.add_interface(pathName, peci_pcie::peciPCIeDeviceInterface);
624 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev] = iface;
625
626 // Update the properties for the new device
627 if (updatePCIeDevice(clientAddr, bus, dev) != resCode::resOk)
628 {
629 removePCIeDevice(objServer, clientAddr, bus, dev);
630 return resCode::resErr;
631 }
632
633 iface->initialize();
634 return resCode::resOk;
635}
636
Jason M. Billsd1e40602019-05-09 11:43:51 -0700637static bool pcieDeviceInDBusMap(const int& clientAddr, const int& bus,
638 const int& dev)
639{
640 if (auto clientAddrIt = peci_pcie::pcieDeviceDBusMap.find(clientAddr);
641 clientAddrIt != peci_pcie::pcieDeviceDBusMap.end())
642 {
643 if (auto busIt = clientAddrIt->second.find(bus);
644 busIt != clientAddrIt->second.end())
645 {
646 if (auto devIt = busIt->second.find(dev);
647 devIt != busIt->second.end())
648 {
649 if (devIt->second)
650 {
651 return true;
652 }
653 }
654 }
655 }
656 return false;
657}
658
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300659static resCode probePCIeDevice(boost::asio::io_service& io,
660 sdbusplus::asio::object_server& objServer,
Andrei Kartashev8e966032021-07-02 20:04:30 +0300661 size_t addr, int cpu, int bus, int dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700662{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300663 bool res;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300664 resCode error = pcieDeviceExists(addr, bus, dev, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300665 if (error != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700666 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300667 return error;
Jason M. Bills5d049732019-10-25 15:55:15 -0700668 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300669 if (res)
Jason M. Bills5d049732019-10-25 15:55:15 -0700670 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300671 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700672 {
673 // This device is already in D-Bus, so update it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300674 if (updatePCIeDevice(addr, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300675 {
676 return resCode::resErr;
677 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700678 }
679 else
680 {
681 // This device is not in D-Bus, so add it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300682 if (addPCIeDevice(objServer, addr, cpu, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300683 {
684 return resCode::resErr;
685 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700686 }
687 }
688 else
689 {
690 // If PECI is not available, then stop scanning
691 if (!isPECIAvailable())
692 {
Paul Fertser541637c2022-12-02 13:42:01 +0000693 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700694 }
695
Andrei Kartashev8e966032021-07-02 20:04:30 +0300696 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700697 {
698 // This device is in D-Bus, so remove it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300699 removePCIeDevice(objServer, addr, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700700 }
701 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300702 return resCode::resOk;
703}
704
Andrei Kartashev8e966032021-07-02 20:04:30 +0300705static void scanNextPCIeDevice(boost::asio::io_service& io,
706 sdbusplus::asio::object_server& objServer,
707 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
708 int dev);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300709static void scanPCIeDevice(boost::asio::io_service& io,
710 sdbusplus::asio::object_server& objServer,
711 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
712 int dev)
713{
Andrei Kartashev8e966032021-07-02 20:04:30 +0300714 if (cpu >= cpuInfo.size())
715 {
716 std::cerr << "Request to scan CPU" << cpu
717 << " while CPU array has size " << cpuInfo.size() << "\n";
718 return;
719 }
720 auto& info = cpuInfo[cpu];
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300721 // Check if this is a CPU bus that we should skip
Andrei Kartashev8e966032021-07-02 20:04:30 +0300722 if (info.skipCpuBuses && info.cpuBusNums.count(bus))
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300723 {
724 std::cout << "Skipping CPU " << cpu << " Bus Number " << bus << "\n";
725 // Skip all the devices on this bus
726 dev = peci_pcie::maxPCIDevices;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300727 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300728 else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300729 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300730 if (probePCIeDevice(io, objServer, info.addr, cpu, bus, dev) !=
731 resCode::resOk)
732 {
733 std::cerr << "Failed to probe CPU " << cpu << " Bus " << bus
734 << " Device " << dev << "\n";
Paul Fertser541637c2022-12-02 13:42:01 +0000735 peci_pcie::abortScan = true;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300736 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300737 }
738
Jason M. Bills5d049732019-10-25 15:55:15 -0700739 scanNextPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Andrei Kartashev8e966032021-07-02 20:04:30 +0300740 return;
Jason M. Bills5d049732019-10-25 15:55:15 -0700741}
Jason M. Billsd1e40602019-05-09 11:43:51 -0700742
Jason M. Bills5d049732019-10-25 15:55:15 -0700743static void scanNextPCIeDevice(boost::asio::io_service& io,
744 sdbusplus::asio::object_server& objServer,
745 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
746 int dev)
747{
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700748 if (peci_pcie::abortScan)
749 {
Paul Fertser07343142022-12-01 21:04:57 +0000750 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700751 std::cerr << "PCIe scan aborted\n";
752 return;
753 }
754
Jason M. Billsd1e40602019-05-09 11:43:51 -0700755 // PCIe Device scan completed, so move to the next device
756 if (++dev >= peci_pcie::maxPCIDevices)
757 {
758 // All devices scanned, so move to the next bus
759 dev = 0;
760 if (++bus >= peci_pcie::maxPCIBuses)
761 {
762 // All buses scanned, so move to the next CPU
763 bus = 0;
Jason M. Bills5d049732019-10-25 15:55:15 -0700764 if (++cpu >= cpuInfo.size())
Jason M. Billsd1e40602019-05-09 11:43:51 -0700765 {
766 // All CPUs scanned, so we're done
Paul Fertser07343142022-12-01 21:04:57 +0000767 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700768 std::cerr << "PCIe scan completed\n";
Jason M. Billsd1e40602019-05-09 11:43:51 -0700769 return;
770 }
771 }
772 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300773 boost::asio::post(io, [&io, &objServer, &cpuInfo, cpu, bus, dev]() mutable {
Jason M. Bills5d049732019-10-25 15:55:15 -0700774 scanPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700775 });
776}
777
Paul Fertser07343142022-12-01 21:04:57 +0000778static void startPCIeScan(boost::asio::io_service& io,
779 sdbusplus::asio::object_server& objServer,
780 std::vector<CPUInfo>& cpuInfo)
781{
782 if (!peci_pcie::scanInProgress)
783 {
784 // get the PECI client address list
785 if (getCPUBusMap(cpuInfo) != resCode::resOk)
786 {
Paul Fertser541637c2022-12-02 13:42:01 +0000787 peci_pcie::abortScan = true;
Paul Fertser07343142022-12-01 21:04:57 +0000788 return;
789 }
790 std::cerr << "PCIe scan started\n";
791 // scan PCIe starting from CPU 0, Bus 0, Device 0
792 peci_pcie::scanInProgress = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000793 peci_pcie::abortScan = false;
Paul Fertser07343142022-12-01 21:04:57 +0000794 scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
795 }
796}
797
Jason M. Billsd1e40602019-05-09 11:43:51 -0700798static void peciAvailableCheck(boost::asio::steady_timer& peciWaitTimer,
799 boost::asio::io_service& io,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300800 sdbusplus::asio::object_server& objServer,
801 std::vector<CPUInfo>& cpuInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700802{
Jason M. Bills5d049732019-10-25 15:55:15 -0700803 static bool lastPECIState = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700804 bool peciAvailable = isPECIAvailable();
Paul Fertser541637c2022-12-02 13:42:01 +0000805 if (peciAvailable && (!lastPECIState || peci_pcie::abortScan))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700806 {
807 lastPECIState = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000808 auto pcieTimeout = std::make_shared<boost::asio::steady_timer>(io);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700809 constexpr const int pcieWaitTime = 60;
Paul Fertser541637c2022-12-02 13:42:01 +0000810 pcieTimeout->expires_after(std::chrono::seconds(pcieWaitTime));
811 pcieTimeout->async_wait([&io, &objServer, &cpuInfo, pcieTimeout](
812 const boost::system::error_code& ec) {
813 if (ec)
814 {
815 // operation_aborted is expected if timer is canceled
816 // before completion.
817 if (ec != boost::asio::error::operation_aborted)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700818 {
Paul Fertser541637c2022-12-02 13:42:01 +0000819 std::cerr << "PECI PCIe async_wait failed " << ec;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700820 }
Paul Fertser541637c2022-12-02 13:42:01 +0000821 lastPECIState = false;
822 return;
823 }
824 startPCIeScan(io, objServer, cpuInfo);
825 });
Jason M. Billsd1e40602019-05-09 11:43:51 -0700826 }
827 else if (!peciAvailable && lastPECIState)
828 {
829 lastPECIState = false;
830 }
831
832 peciWaitTimer.expires_after(
833 std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300834 peciWaitTimer.async_wait([&peciWaitTimer, &io, &objServer,
835 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700836 if (ec)
837 {
838 // operation_aborted is expected if timer is canceled
839 // before completion.
840 if (ec != boost::asio::error::operation_aborted)
841 {
842 std::cerr << "PECI Available Check async_wait failed " << ec;
843 }
844 return;
845 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300846 peciAvailableCheck(peciWaitTimer, io, objServer, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700847 });
848}
849
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700850static void waitForOSStandbyDelay(boost::asio::io_service& io,
851 sdbusplus::asio::object_server& objServer,
852 boost::asio::steady_timer& osStandbyTimer,
853 std::vector<CPUInfo>& cpuInfo)
854{
855 osStandbyTimer.expires_after(
856 std::chrono::seconds(peci_pcie::osStandbyDelaySeconds));
857
858 osStandbyTimer.async_wait(
859 [&io, &objServer, &cpuInfo](const boost::system::error_code& ec) {
860 if (ec == boost::asio::error::operation_aborted)
861 {
862 return; // we're being canceled
863 }
864 else if (ec)
865 {
866 std::cerr << "OS Standby async_wait failed: " << ec.value()
867 << ": " << ec.message() << "\n";
868 return;
869 }
Paul Fertser07343142022-12-01 21:04:57 +0000870 startPCIeScan(io, objServer, cpuInfo);
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700871 });
872}
873
874static void monitorOSStandby(boost::asio::io_service& io,
875 std::shared_ptr<sdbusplus::asio::connection> conn,
876 sdbusplus::asio::object_server& objServer,
877 boost::asio::steady_timer& osStandbyTimer,
878 std::vector<CPUInfo>& cpuInfo)
879{
880 std::cerr << "Start OperatingSystemState Monitor\n";
881
Patrick Williamsb2517082022-07-22 19:26:57 -0500882 static sdbusplus::bus::match_t osStateMatch(
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700883 *conn,
884 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
885 "PropertiesChanged',arg0='xyz.openbmc_project.State.OperatingSystem."
886 "Status'",
887 [&io, &objServer, &osStandbyTimer,
Patrick Williamsb2517082022-07-22 19:26:57 -0500888 &cpuInfo](sdbusplus::message_t& msg) {
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700889 // Get the OS State from the message
890 std::string osStateInterface;
891 boost::container::flat_map<std::string, std::variant<std::string>>
892 propertiesChanged;
893 msg.read(osStateInterface, propertiesChanged);
894
895 for (const auto& [name, value] : propertiesChanged)
896 {
897 if (name == "OperatingSystemState")
898 {
899 const std::string* state = std::get_if<std::string>(&value);
900 if (state == nullptr)
901 {
902 std::cerr << "Unable to read OS state value\n";
903 return;
904 }
Andrei Kartashev328685e2021-12-27 17:24:18 +0300905 // Note: Short version of OperatingSystemState value is
906 // deprecated and would be removed in the future
907 if ((*state == "Standby") ||
908 (*state == "xyz.openbmc_project.State.OperatingSystem."
909 "Status.OSStatus.Standby"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700910 {
911 peci_pcie::abortScan = false;
912 waitForOSStandbyDelay(io, objServer, osStandbyTimer,
913 cpuInfo);
914 }
Andrei Kartashev328685e2021-12-27 17:24:18 +0300915 else if ((*state == "Inactive") ||
916 (*state ==
917 "xyz.openbmc_project.State.OperatingSystem."
918 "Status.OSStatus.Inactive"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700919 {
920 peci_pcie::abortScan = true;
921 osStandbyTimer.cancel();
922 }
923 }
924 }
925 });
926
927 // Check if the OS state is already available
928 conn->async_method_call(
929 [&io, &objServer, &osStandbyTimer,
930 &cpuInfo](boost::system::error_code ec,
931 const std::variant<std::string>& property) {
932 if (ec)
933 {
934 std::cerr << "error with OS state async_method_call\n";
935 return;
936 }
937
938 const std::string* state = std::get_if<std::string>(&property);
939 if (state == nullptr)
940 {
941 std::cerr << "Unable to read OS state value\n";
942 return;
943 }
944
945 // If the OS state is in Standby, then BIOS is done and we can
946 // continue. Otherwise, we just wait for the match
Andrei Kartashev328685e2021-12-27 17:24:18 +0300947 // Note: Short version of OperatingSystemState value is deprecated
948 // and would be removed in the future
949
950 if ((*state == "Standby") ||
951 (*state == "xyz.openbmc_project.State.OperatingSystem.Status."
952 "OSStatus.Standby"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700953 {
954 waitForOSStandbyDelay(io, objServer, osStandbyTimer, cpuInfo);
955 }
956 },
957 "xyz.openbmc_project.State.OperatingSystem",
958 "/xyz/openbmc_project/state/os", "org.freedesktop.DBus.Properties",
959 "Get", "xyz.openbmc_project.State.OperatingSystem.Status",
960 "OperatingSystemState");
961}
962
Jason M. Billsd1e40602019-05-09 11:43:51 -0700963int main(int argc, char* argv[])
964{
965 // setup connection to dbus
966 boost::asio::io_service io;
967 std::shared_ptr<sdbusplus::asio::connection> conn =
968 std::make_shared<sdbusplus::asio::connection>(io);
969
970 // PECI PCIe Object
971 conn->request_name(peci_pcie::peciPCIeObject);
972 sdbusplus::asio::object_server server =
973 sdbusplus::asio::object_server(conn);
974
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300975 // CPU map
976 std::vector<CPUInfo> cpuInfo;
977
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700978#ifdef WAIT_FOR_OS_STANDBY
979 boost::asio::steady_timer osStandbyTimer(io);
980 monitorOSStandby(io, conn, server, osStandbyTimer, cpuInfo);
981#else
Jason M. Billsd1e40602019-05-09 11:43:51 -0700982 // Start the PECI check loop
983 boost::asio::steady_timer peciWaitTimer(
984 io, std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300985 peciWaitTimer.async_wait([&peciWaitTimer, &io, &server,
986 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700987 if (ec)
988 {
989 // operation_aborted is expected if timer is canceled
990 // before completion.
991 if (ec != boost::asio::error::operation_aborted)
992 {
993 std::cerr << "PECI Available Check async_wait failed " << ec;
994 }
995 return;
996 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300997 peciAvailableCheck(peciWaitTimer, io, server, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700998 });
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700999#endif
Jason M. Billsd1e40602019-05-09 11:43:51 -07001000
1001 io.run();
1002
1003 return 0;
1004}