blob: 4bfe6b15404fb7ea8143a2dc09f8314be341070c [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
Paul Fertser3b2afcb2022-12-16 12:17:15 +000046constexpr const bool debug = false;
47
Jason M. Billsd1e40602019-05-09 11:43:51 -070048namespace function
49{
50static constexpr char const* functionTypeName = "FunctionType";
51static constexpr char const* deviceClassName = "DeviceClass";
52static constexpr char const* vendorIdName = "VendorId";
53static constexpr char const* deviceIdName = "DeviceId";
54static constexpr char const* classCodeName = "ClassCode";
55static constexpr char const* revisionIdName = "RevisionId";
56static constexpr char const* subsystemIdName = "SubsystemId";
57static constexpr char const* subsystemVendorIdName = "SubsystemVendorId";
58} // namespace function
Andrei Kartashev6f552032021-05-11 21:25:29 +030059
60static constexpr const std::array pciConfigInfo{
61 std::tuple<const char*, int, int>{function::functionTypeName, -1, -1},
62 std::tuple<const char*, int, int>{function::deviceClassName, -1, -1},
63 std::tuple<const char*, int, int>{function::vendorIdName, 0, 2},
64 std::tuple<const char*, int, int>{function::deviceIdName, 2, 2},
65 std::tuple<const char*, int, int>{function::classCodeName, 9, 3},
66 std::tuple<const char*, int, int>{function::revisionIdName, 8, 1},
67 std::tuple<const char*, int, int>{function::subsystemIdName, 0x2e, 2},
68 std::tuple<const char*, int, int>{function::subsystemVendorIdName, 0x2c,
69 2}};
Jason M. Billsd1e40602019-05-09 11:43:51 -070070} // namespace peci_pcie
71
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030072enum class resCode
73{
74 resOk,
Spencer Kubb5efe72021-09-02 16:11:14 +080075 resSkip,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030076 resErr
77};
78
Jason M. Bills5d049732019-10-25 15:55:15 -070079struct CPUInfo
Jason M. Billsd1e40602019-05-09 11:43:51 -070080{
Jason M. Bills5d049732019-10-25 15:55:15 -070081 size_t addr;
82 bool skipCpuBuses;
83 boost::container::flat_set<size_t> cpuBusNums;
84};
85
86// PECI Client Address Map
Andrei Kartashev8e966032021-07-02 20:04:30 +030087static resCode getCPUBusMap(std::vector<CPUInfo>& cpuInfo)
Jason M. Bills5d049732019-10-25 15:55:15 -070088{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030089 cpuInfo.clear();
Andrei Kartashev8e966032021-07-02 20:04:30 +030090 for (size_t addr = MIN_CLIENT_ADDR; addr <= MAX_CLIENT_ADDR; addr++)
Jason M. Billsd1e40602019-05-09 11:43:51 -070091 {
Andrei Kartashev8e966032021-07-02 20:04:30 +030092 if (peci_Ping(addr) != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -070093 {
Andrei Kartashev8e966032021-07-02 20:04:30 +030094 continue;
Jason M. Bills5d049732019-10-25 15:55:15 -070095 }
Jason M. Bills5d049732019-10-25 15:55:15 -070096
Andrei Kartashev8e966032021-07-02 20:04:30 +030097 auto& cpu = cpuInfo.emplace_back(CPUInfo{addr, false, {}});
Jason M. Bills5d049732019-10-25 15:55:15 -070098 uint8_t cc = 0;
99 CPUModel model{};
100 uint8_t stepping = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300101 if (peci_GetCPUID(addr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Jason M. Bills5d049732019-10-25 15:55:15 -0700102 {
103 std::cerr << "Cannot get CPUID!\n";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300104 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700105 }
106
107 switch (model)
108 {
109 case skx:
110 {
111 // Get the assigned CPU bus numbers from CPUBUSNO and CPUBUSNO1
112 // (B(0) D8 F2 offsets CCh and D0h)
113 uint32_t cpuBusNum = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300114 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xCC, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700115 (uint8_t*)&cpuBusNum,
116 &cc) != PECI_CC_SUCCESS)
117 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300118 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700119 }
120 uint32_t cpuBusNum1 = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300121 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xD0, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700122 (uint8_t*)&cpuBusNum1,
123 &cc) != PECI_CC_SUCCESS)
124 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300125 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700126 }
127
128 // Add the CPU bus numbers to the set for this CPU
129 while (cpuBusNum)
130 {
131 // Get the LSB
132 size_t busNum = cpuBusNum & 0xFF;
133 cpu.cpuBusNums.insert(busNum);
134 // Shift right by one byte
135 cpuBusNum >>= 8;
136 }
137 while (cpuBusNum1)
138 {
139 // Get the LSB
140 size_t busNum = cpuBusNum1 & 0xFF;
141 cpu.cpuBusNums.insert(busNum);
142 // Shift right by one byte
Zev Weiss9fa54b52020-09-02 21:20:33 +0000143 cpuBusNum1 >>= 8;
Jason M. Bills5d049732019-10-25 15:55:15 -0700144 }
145 cpu.skipCpuBuses = true;
146 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700147 }
148 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300149 return cpuInfo.empty() ? resCode::resErr : resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700150}
151
152static bool isPECIAvailable(void)
153{
Jason M. Bills5d049732019-10-25 15:55:15 -0700154 for (size_t i = MIN_CLIENT_ADDR; i <= MAX_CLIENT_ADDR; i++)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700155 {
Jason M. Bills5d049732019-10-25 15:55:15 -0700156 if (peci_Ping(i) == PECI_CC_SUCCESS)
157 {
158 return true;
159 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700160 }
Jason M. Bills5d049732019-10-25 15:55:15 -0700161 return false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700162}
163
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300164static resCode getDataFromPCIeConfig(const int& clientAddr, const int& bus,
165 const int& dev, const int& func,
166 const int& offset, const int& size,
167 uint32_t& pciData)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700168{
169 // PECI RdPCIConfig() currently only supports 4 byte reads, so adjust
170 // the offset and size to get the right data
171 static constexpr const int pciReadSize = 4;
172 int mod = offset % pciReadSize;
173 int pciOffset = offset - mod;
174 if (mod + size > pciReadSize)
175 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300176 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700177 }
178
179 std::array<uint8_t, pciReadSize> data;
180 uint8_t cc;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300181 int ret = PECI_CC_TIMEOUT;
Paul Fertserb08723d2022-12-16 11:49:08 +0000182 for (int index = 0; (index < 15) && (ret == PECI_CC_TIMEOUT); index++)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300183 {
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700184#ifdef USE_RDENDPOINTCFG
185 ret = peci_RdEndPointConfigPci(clientAddr, // CPU Address
186 0, // PCI Seg (use 0 for now)
187 bus, // PCI Bus
188 dev, // PCI Device
189 func, // PCI Function
190 pciOffset, // PCI Offset
191 pciReadSize, // PCI Read Size
192 data.data(), // PCI Read Data
193 &cc); // PECI Completion Code
194#else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300195 ret = peci_RdPCIConfig(clientAddr, // CPU Address
Jason M. Billsd1e40602019-05-09 11:43:51 -0700196 bus, // PCI Bus
197 dev, // PCI Device
198 func, // PCI Function
199 pciOffset, // PCI Offset
200 data.data(), // PCI Read Data
201 &cc); // PECI Completion Code
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700202#endif
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000203 if constexpr (peci_pcie::debug)
204 {
205 std::cerr << "Request: bus " << bus << " dev " << dev << " func "
206 << func << " pciOffset " << pciOffset << " ret: " << ret
207 << " cc: " << static_cast<int>(cc) << "\n";
208 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300209 }
Paul Fertser541637c2022-12-02 13:42:01 +0000210 if (ret != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700211 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300212 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700213 }
Paul Fertser541637c2022-12-02 13:42:01 +0000214 else if (cc != PECI_DEV_CC_SUCCESS)
215 {
216 return resCode::resSkip;
217 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700218
219 // Now build the requested data into a single number
220 pciData = 0;
221 for (int i = mod; i < mod + size; i++)
222 {
Jason M. Billse55832b2021-06-14 16:00:49 -0700223 pciData |= static_cast<uint32_t>(data[i]) << 8 * (i - mod);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700224 }
225
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300226 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700227}
228
Andrei Kartashev6f552032021-05-11 21:25:29 +0300229static resCode getStringFromData(const int& size, const uint32_t& data,
230 std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700231{
Jason M. Billsd1e40602019-05-09 11:43:51 -0700232 // And convert it to a string
233 std::stringstream dataStream;
234 dataStream << "0x" << std::hex << std::setfill('0') << std::setw(size * 2)
235 << data;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300236 res = dataStream.str();
237 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700238}
239
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300240static resCode getVendorName(const int& clientAddr, const int& bus,
241 const int& dev, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700242{
243 static constexpr const int vendorIDOffset = 0x00;
244 static constexpr const int vendorIDSize = 2;
245
246 // Get the header type register from function 0
247 uint32_t vendorID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300248 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, vendorIDOffset,
249 vendorIDSize, vendorID) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700250 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300251 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700252 }
253 // Get the vendor name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300254 res = pciVendors.try_emplace(vendorID, otherVendor).first->second;
255 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700256}
257
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300258static resCode getDeviceClass(const int& clientAddr, const int& bus,
259 const int& dev, const int& func, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700260{
261 static constexpr const int baseClassOffset = 0x0b;
262 static constexpr const int baseClassSize = 1;
263
264 // Get the Device Base Class
265 uint32_t baseClass = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300266 if (getDataFromPCIeConfig(clientAddr, bus, dev, func, baseClassOffset,
267 baseClassSize, baseClass) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700268 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300269 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700270 }
271 // Get the base class name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300272 res = pciDeviceClasses.try_emplace(baseClass, otherClass).first->second;
273 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700274}
275
Spencer Kubb5efe72021-09-02 16:11:14 +0800276static resCode getCapReading(const int& clientAddr, const int& bus,
277 const int& dev, uint32_t& capReading,
278 const int compareCapID, const int offsetAddress,
279 const int offsetLength)
280{
281 resCode error;
282 uint32_t capAddress = 0;
283 uint32_t capabilityID;
284 uint32_t nextCapPointer = peci_pcie::pointToCapStruct;
285
286 do
287 {
288 // Get capability address
289 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, nextCapPointer,
290 1, capAddress);
291 if (error != resCode::resOk)
292 {
293 return error;
294 }
295 // Capability struct address is a pointer which point to next capability
296 // struct, so if capability struct address is 0 means it doesn't have
297 // next capability struct.
298 if (capAddress == 0)
299 {
300 return resCode::resSkip;
301 }
302 // Get capability ID
303 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, capAddress, 1,
304 capabilityID);
305 if (error != resCode::resOk)
306 {
307 return error;
308 }
309 nextCapPointer = capAddress + peci_pcie::capPointerOffset;
310
311 } while (capabilityID != compareCapID);
312 // Get capability reading.
313 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0,
314 capAddress + offsetAddress, offsetLength,
315 capReading);
316 if (error != resCode::resOk)
317 {
318 return error;
319 }
320 return resCode::resOk;
321}
322
323static resCode getGenerationInUse(const int& clientAddr, const int& bus,
324 const int& dev, std::string& generationInUse)
325{
Willy Tu975faf72022-09-23 18:39:16 +0000326 static std::unordered_set<uint32_t> linkSpeedSkipMap;
Spencer Kubb5efe72021-09-02 16:11:14 +0800327 resCode error;
328 std::string res;
329 uint32_t capReading = 0;
330
331 // Capability ID 0x10(16) is PCI Express
332 constexpr int pcieCapID = 16;
333 constexpr int capLength = 2;
334 uint32_t linkStatus;
335
336 error = getCapReading(clientAddr, bus, dev, linkStatus, pcieCapID,
337 peci_pcie::linkStatusOffset, capLength);
338 if (error != resCode::resOk)
339 {
340 return error;
341 }
342
343 uint32_t linkSpeed = linkStatus & peci_pcie::maskOfCLS;
344
345 switch (linkSpeed)
346 {
347 case peci_pcie::pcieGen1:
348 generationInUse = "xyz.openbmc_project.Inventory.Item."
349 "PCIeSlot.Generations.Gen1";
350 error = resCode::resOk;
351 break;
352 case peci_pcie::pcieGen2:
353 generationInUse = "xyz.openbmc_project.Inventory.Item."
354 "PCIeSlot.Generations.Gen2";
355 error = resCode::resOk;
356 break;
357 case peci_pcie::pcieGen3:
358 generationInUse = "xyz.openbmc_project.Inventory.Item."
359 "PCIeSlot.Generations.Gen3";
360 error = resCode::resOk;
361 break;
362 case peci_pcie::pcieGen4:
363 generationInUse = "xyz.openbmc_project.Inventory.Item."
364 "PCIeSlot.Generations.Gen4";
365 error = resCode::resOk;
366 break;
367 case peci_pcie::pcieGen5:
368 generationInUse = "xyz.openbmc_project.Inventory.Item."
369 "PCIeSlot.Generations.Gen5";
370 error = resCode::resOk;
371 break;
372 default:
Willy Tu975faf72022-09-23 18:39:16 +0000373 if (!linkSpeedSkipMap.contains(linkSpeed))
374 {
375 std::cerr << "Link speed : " << linkSpeed
376 << " can not mapping to PCIe type list.\n";
377 linkSpeedSkipMap.emplace(linkSpeed);
378 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800379 error = resCode::resSkip;
380 }
381 return error;
382}
383
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300384static resCode isMultiFunction(const int& clientAddr, const int& bus,
385 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700386{
387 static constexpr const int headerTypeOffset = 0x0e;
388 static constexpr const int headerTypeSize = 1;
389 static constexpr const int multiFuncBit = 1 << 7;
390
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300391 res = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700392 // Get the header type register from function 0
393 uint32_t headerType = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300394 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, headerTypeOffset,
395 headerTypeSize, headerType) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700396 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300397 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700398 }
399 // Check if it's a multifunction device
400 if (headerType & multiFuncBit)
401 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300402 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700403 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300404 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700405}
406
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300407static resCode pcieFunctionExists(const int& clientAddr, const int& bus,
408 const int& dev, const int& func, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700409{
410 constexpr const int pciIDOffset = 0;
411 constexpr const int pciIDSize = 4;
412 uint32_t pciID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300413 res = false;
Paul Fertser541637c2022-12-02 13:42:01 +0000414
415 resCode error = getDataFromPCIeConfig(clientAddr, bus, dev, func,
416 pciIDOffset, pciIDSize, pciID);
417 if (error == resCode::resSkip)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700418 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300419 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700420 }
Paul Fertser541637c2022-12-02 13:42:01 +0000421 else if (error == resCode::resErr)
422 {
423 return resCode::resErr;
424 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700425
426 // if VID and DID are all 0s or 1s, then the device doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300427 if (pciID != 0x00000000 && pciID != 0xFFFFFFFF)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700428 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300429 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700430 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300431 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700432}
433
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300434static resCode pcieDeviceExists(const int& clientAddr, const int& bus,
435 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700436{
437 // Check if this device exists by checking function 0
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300438 return pcieFunctionExists(clientAddr, bus, dev, 0, res);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700439}
440
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300441static resCode setPCIeProperty(const int& clientAddr, const int& bus,
442 const int& dev, const std::string& propertyName,
443 const std::string& propertyValue)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700444{
445 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
446 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
447
448 if (iface->is_initialized())
449 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300450 if (!iface->set_property(propertyName, propertyValue))
451 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700452 }
453 else
454 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300455 if (!iface->register_property(propertyName, propertyValue))
456 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700457 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300458 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700459}
460
461static void setDefaultPCIeFunctionProperties(const int& clientAddr,
462 const int& bus, const int& dev,
463 const int& func)
464{
465 // Set the function-specific properties
Andrei Kartashev6f552032021-05-11 21:25:29 +0300466 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700467 {
468 setPCIeProperty(clientAddr, bus, dev,
469 "Function" + std::to_string(func) + std::string(name),
470 std::string());
471 }
472}
473
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300474static resCode setPCIeFunctionProperties(const int& clientAddr, const int& bus,
475 const int& dev, const int& func)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700476{
Andrei Kartashev6f552032021-05-11 21:25:29 +0300477 uint32_t data = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300478 std::string res;
Andrei Kartashev6f552032021-05-11 21:25:29 +0300479 resCode error;
480
481 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
482 {
483 if (offset < 0)
484 {
485 continue;
486 }
487
488 error = getDataFromPCIeConfig(clientAddr, bus, dev, func, offset, size,
489 data);
490 if (error != resCode::resOk)
491 {
492 return error;
493 }
494 getStringFromData(size, data, res);
495 setPCIeProperty(clientAddr, bus, dev,
496 "Function" + std::to_string(func) + std::string(name),
497 res);
498 }
499
Jason M. Billsd1e40602019-05-09 11:43:51 -0700500 // Set the function type always to physical for now
501 setPCIeProperty(clientAddr, bus, dev,
502 "Function" + std::to_string(func) +
503 std::string(peci_pcie::function::functionTypeName),
504 "Physical");
505
506 // Set the function Device Class
Andrei Kartashev6f552032021-05-11 21:25:29 +0300507 error = getDeviceClass(clientAddr, bus, dev, func, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300508 if (error != resCode::resOk)
509 {
510 return error;
511 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700512 setPCIeProperty(clientAddr, bus, dev,
513 "Function" + std::to_string(func) +
514 std::string(peci_pcie::function::deviceClassName),
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300515 res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300516 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700517}
518
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300519static resCode setPCIeDeviceProperties(const int& clientAddr, const int& bus,
520 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700521{
522 // Set the device manufacturer
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300523 std::string manuf;
524 resCode error = getVendorName(clientAddr, bus, dev, manuf);
525 if (error != resCode::resOk)
526 {
527 return error;
528 }
529 setPCIeProperty(clientAddr, bus, dev, "Manufacturer", manuf);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700530
531 // Set the device type
532 constexpr char const* deviceTypeName = "DeviceType";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300533 bool multiFunc;
534 error = isMultiFunction(clientAddr, bus, dev, multiFunc);
535 if (error != resCode::resOk)
536 {
537 return error;
538 }
539 if (multiFunc)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700540 {
541 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "MultiFunction");
542 }
543 else
544 {
545 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "SingleFunction");
546 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800547
548 // Set PCIe Generation
549 constexpr char const* generationInUseName = "GenerationInUse";
550 std::string generationInUse;
551 error = getGenerationInUse(clientAddr, bus, dev, generationInUse);
552 if (error == resCode::resErr)
553 {
554 return error;
555 }
556 // "resSkip" status means it can't get the capability reading, such like
557 // this device is not PCI Express.
558 if (error == resCode::resSkip)
559 {
560 setPCIeProperty(clientAddr, bus, dev, generationInUseName, "");
561 return resCode::resOk;
562 }
563 setPCIeProperty(clientAddr, bus, dev, generationInUseName, generationInUse);
564
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300565 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700566}
567
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300568static resCode updatePCIeDevice(const int& clientAddr, const int& bus,
569 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700570{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300571 if (setPCIeDeviceProperties(clientAddr, bus, dev) != resCode::resOk)
572 {
573 return resCode::resErr;
574 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700575
576 // Walk through and populate the functions for this device
577 for (int func = 0; func < peci_pcie::maxPCIFunctions; func++)
578 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300579 bool res;
580 resCode error = pcieFunctionExists(clientAddr, bus, dev, func, res);
581 if (error != resCode::resOk)
582 {
583 return error;
584 }
585 if (res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700586 {
587 // Set the properties for this function
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300588 if (setPCIeFunctionProperties(clientAddr, bus, dev, func) !=
589 resCode::resOk)
590 {
591 return resCode::resErr;
592 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700593 }
594 else
595 {
596 // Set default properties for unused functions
597 setDefaultPCIeFunctionProperties(clientAddr, bus, dev, func);
598 }
599 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300600 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700601}
602
603static void removePCIeDevice(sdbusplus::asio::object_server& objServer,
604 const int& clientAddr, const int& bus,
605 const int& dev)
606{
607 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
608 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
609
610 objServer.remove_interface(iface);
611
612 peci_pcie::pcieDeviceDBusMap[clientAddr][bus].erase(dev);
613 if (peci_pcie::pcieDeviceDBusMap[clientAddr][bus].empty())
614 {
615 peci_pcie::pcieDeviceDBusMap[clientAddr].erase(bus);
616 }
617 if (peci_pcie::pcieDeviceDBusMap[clientAddr].empty())
618 {
619 peci_pcie::pcieDeviceDBusMap.erase(clientAddr);
620 }
621}
622
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300623static resCode addPCIeDevice(sdbusplus::asio::object_server& objServer,
624 const int& clientAddr, const int& cpu,
625 const int& bus, const int& dev)
626{
627 std::string pathName = std::string(peci_pcie::peciPCIePath) + "/S" +
628 std::to_string(cpu) + "B" + std::to_string(bus) +
629 "D" + std::to_string(dev);
630 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
631 objServer.add_interface(pathName, peci_pcie::peciPCIeDeviceInterface);
632 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev] = iface;
633
634 // Update the properties for the new device
635 if (updatePCIeDevice(clientAddr, bus, dev) != resCode::resOk)
636 {
637 removePCIeDevice(objServer, clientAddr, bus, dev);
638 return resCode::resErr;
639 }
640
641 iface->initialize();
642 return resCode::resOk;
643}
644
Jason M. Billsd1e40602019-05-09 11:43:51 -0700645static bool pcieDeviceInDBusMap(const int& clientAddr, const int& bus,
646 const int& dev)
647{
648 if (auto clientAddrIt = peci_pcie::pcieDeviceDBusMap.find(clientAddr);
649 clientAddrIt != peci_pcie::pcieDeviceDBusMap.end())
650 {
651 if (auto busIt = clientAddrIt->second.find(bus);
652 busIt != clientAddrIt->second.end())
653 {
654 if (auto devIt = busIt->second.find(dev);
655 devIt != busIt->second.end())
656 {
657 if (devIt->second)
658 {
659 return true;
660 }
661 }
662 }
663 }
664 return false;
665}
666
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300667static resCode probePCIeDevice(boost::asio::io_service& io,
668 sdbusplus::asio::object_server& objServer,
Andrei Kartashev8e966032021-07-02 20:04:30 +0300669 size_t addr, int cpu, int bus, int dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700670{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300671 bool res;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300672 resCode error = pcieDeviceExists(addr, bus, dev, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300673 if (error != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700674 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300675 return error;
Jason M. Bills5d049732019-10-25 15:55:15 -0700676 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300677 if (res)
Jason M. Bills5d049732019-10-25 15:55:15 -0700678 {
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 already in D-Bus, so update it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300682 if (updatePCIeDevice(addr, 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 else
688 {
689 // This device is not in D-Bus, so add it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300690 if (addPCIeDevice(objServer, addr, cpu, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300691 {
692 return resCode::resErr;
693 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700694 }
695 }
696 else
697 {
698 // If PECI is not available, then stop scanning
699 if (!isPECIAvailable())
700 {
Paul Fertser541637c2022-12-02 13:42:01 +0000701 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700702 }
703
Andrei Kartashev8e966032021-07-02 20:04:30 +0300704 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700705 {
706 // This device is in D-Bus, so remove it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300707 removePCIeDevice(objServer, addr, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700708 }
709 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300710 return resCode::resOk;
711}
712
Andrei Kartashev8e966032021-07-02 20:04:30 +0300713static void scanNextPCIeDevice(boost::asio::io_service& io,
714 sdbusplus::asio::object_server& objServer,
715 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
716 int dev);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300717static void scanPCIeDevice(boost::asio::io_service& io,
718 sdbusplus::asio::object_server& objServer,
719 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
720 int dev)
721{
Andrei Kartashev8e966032021-07-02 20:04:30 +0300722 if (cpu >= cpuInfo.size())
723 {
724 std::cerr << "Request to scan CPU" << cpu
725 << " while CPU array has size " << cpuInfo.size() << "\n";
726 return;
727 }
728 auto& info = cpuInfo[cpu];
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300729 // Check if this is a CPU bus that we should skip
Andrei Kartashev8e966032021-07-02 20:04:30 +0300730 if (info.skipCpuBuses && info.cpuBusNums.count(bus))
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300731 {
732 std::cout << "Skipping CPU " << cpu << " Bus Number " << bus << "\n";
733 // Skip all the devices on this bus
734 dev = peci_pcie::maxPCIDevices;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300735 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300736 else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300737 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300738 if (probePCIeDevice(io, objServer, info.addr, cpu, bus, dev) !=
739 resCode::resOk)
740 {
741 std::cerr << "Failed to probe CPU " << cpu << " Bus " << bus
742 << " Device " << dev << "\n";
Paul Fertser541637c2022-12-02 13:42:01 +0000743 peci_pcie::abortScan = true;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300744 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300745 }
746
Jason M. Bills5d049732019-10-25 15:55:15 -0700747 scanNextPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Andrei Kartashev8e966032021-07-02 20:04:30 +0300748 return;
Jason M. Bills5d049732019-10-25 15:55:15 -0700749}
Jason M. Billsd1e40602019-05-09 11:43:51 -0700750
Jason M. Bills5d049732019-10-25 15:55:15 -0700751static void scanNextPCIeDevice(boost::asio::io_service& io,
752 sdbusplus::asio::object_server& objServer,
753 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
754 int dev)
755{
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700756 if (peci_pcie::abortScan)
757 {
Paul Fertser07343142022-12-01 21:04:57 +0000758 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700759 std::cerr << "PCIe scan aborted\n";
760 return;
761 }
762
Jason M. Billsd1e40602019-05-09 11:43:51 -0700763 // PCIe Device scan completed, so move to the next device
764 if (++dev >= peci_pcie::maxPCIDevices)
765 {
766 // All devices scanned, so move to the next bus
767 dev = 0;
768 if (++bus >= peci_pcie::maxPCIBuses)
769 {
770 // All buses scanned, so move to the next CPU
771 bus = 0;
Jason M. Bills5d049732019-10-25 15:55:15 -0700772 if (++cpu >= cpuInfo.size())
Jason M. Billsd1e40602019-05-09 11:43:51 -0700773 {
774 // All CPUs scanned, so we're done
Paul Fertser07343142022-12-01 21:04:57 +0000775 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700776 std::cerr << "PCIe scan completed\n";
Jason M. Billsd1e40602019-05-09 11:43:51 -0700777 return;
778 }
779 }
780 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300781 boost::asio::post(io, [&io, &objServer, &cpuInfo, cpu, bus, dev]() mutable {
Jason M. Bills5d049732019-10-25 15:55:15 -0700782 scanPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700783 });
784}
785
Paul Fertser07343142022-12-01 21:04:57 +0000786static void startPCIeScan(boost::asio::io_service& io,
787 sdbusplus::asio::object_server& objServer,
788 std::vector<CPUInfo>& cpuInfo)
789{
790 if (!peci_pcie::scanInProgress)
791 {
792 // get the PECI client address list
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000793 std::cerr << "Getting map\n";
Paul Fertser07343142022-12-01 21:04:57 +0000794 if (getCPUBusMap(cpuInfo) != resCode::resOk)
795 {
Paul Fertser541637c2022-12-02 13:42:01 +0000796 peci_pcie::abortScan = true;
Paul Fertser07343142022-12-01 21:04:57 +0000797 return;
798 }
799 std::cerr << "PCIe scan started\n";
800 // scan PCIe starting from CPU 0, Bus 0, Device 0
801 peci_pcie::scanInProgress = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000802 peci_pcie::abortScan = false;
Paul Fertser07343142022-12-01 21:04:57 +0000803 scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
804 }
805}
806
Jason M. Billsd1e40602019-05-09 11:43:51 -0700807static void peciAvailableCheck(boost::asio::steady_timer& peciWaitTimer,
808 boost::asio::io_service& io,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300809 sdbusplus::asio::object_server& objServer,
810 std::vector<CPUInfo>& cpuInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700811{
Jason M. Bills5d049732019-10-25 15:55:15 -0700812 static bool lastPECIState = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700813 bool peciAvailable = isPECIAvailable();
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000814 if constexpr (peci_pcie::debug)
815 {
816 std::cerr << "peciAvailableCheck " << peciAvailable << " "
817 << lastPECIState << " " << peci_pcie::abortScan << "\n";
818 }
Paul Fertser541637c2022-12-02 13:42:01 +0000819 if (peciAvailable && (!lastPECIState || peci_pcie::abortScan))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700820 {
821 lastPECIState = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000822 auto pcieTimeout = std::make_shared<boost::asio::steady_timer>(io);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700823 constexpr const int pcieWaitTime = 60;
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000824 if constexpr (peci_pcie::debug)
825 {
826 std::cerr << "Scanning in 60 seconds\n";
827 }
Paul Fertser541637c2022-12-02 13:42:01 +0000828 pcieTimeout->expires_after(std::chrono::seconds(pcieWaitTime));
829 pcieTimeout->async_wait([&io, &objServer, &cpuInfo, pcieTimeout](
830 const boost::system::error_code& ec) {
831 if (ec)
832 {
833 // operation_aborted is expected if timer is canceled
834 // before completion.
835 if (ec != boost::asio::error::operation_aborted)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700836 {
Paul Fertser541637c2022-12-02 13:42:01 +0000837 std::cerr << "PECI PCIe async_wait failed " << ec;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700838 }
Paul Fertser541637c2022-12-02 13:42:01 +0000839 lastPECIState = false;
840 return;
841 }
842 startPCIeScan(io, objServer, cpuInfo);
843 });
Jason M. Billsd1e40602019-05-09 11:43:51 -0700844 }
845 else if (!peciAvailable && lastPECIState)
846 {
847 lastPECIState = false;
848 }
849
850 peciWaitTimer.expires_after(
851 std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300852 peciWaitTimer.async_wait([&peciWaitTimer, &io, &objServer,
853 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700854 if (ec)
855 {
856 // operation_aborted is expected if timer is canceled
857 // before completion.
858 if (ec != boost::asio::error::operation_aborted)
859 {
860 std::cerr << "PECI Available Check async_wait failed " << ec;
861 }
862 return;
863 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300864 peciAvailableCheck(peciWaitTimer, io, objServer, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700865 });
866}
867
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700868static void waitForOSStandbyDelay(boost::asio::io_service& io,
869 sdbusplus::asio::object_server& objServer,
870 boost::asio::steady_timer& osStandbyTimer,
871 std::vector<CPUInfo>& cpuInfo)
872{
873 osStandbyTimer.expires_after(
874 std::chrono::seconds(peci_pcie::osStandbyDelaySeconds));
875
876 osStandbyTimer.async_wait(
877 [&io, &objServer, &cpuInfo](const boost::system::error_code& ec) {
878 if (ec == boost::asio::error::operation_aborted)
879 {
880 return; // we're being canceled
881 }
882 else if (ec)
883 {
884 std::cerr << "OS Standby async_wait failed: " << ec.value()
885 << ": " << ec.message() << "\n";
886 return;
887 }
Paul Fertser07343142022-12-01 21:04:57 +0000888 startPCIeScan(io, objServer, cpuInfo);
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700889 });
890}
891
892static void monitorOSStandby(boost::asio::io_service& io,
893 std::shared_ptr<sdbusplus::asio::connection> conn,
894 sdbusplus::asio::object_server& objServer,
895 boost::asio::steady_timer& osStandbyTimer,
896 std::vector<CPUInfo>& cpuInfo)
897{
898 std::cerr << "Start OperatingSystemState Monitor\n";
899
Patrick Williamsb2517082022-07-22 19:26:57 -0500900 static sdbusplus::bus::match_t osStateMatch(
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700901 *conn,
902 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
903 "PropertiesChanged',arg0='xyz.openbmc_project.State.OperatingSystem."
904 "Status'",
905 [&io, &objServer, &osStandbyTimer,
Patrick Williamsb2517082022-07-22 19:26:57 -0500906 &cpuInfo](sdbusplus::message_t& msg) {
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700907 // Get the OS State from the message
908 std::string osStateInterface;
909 boost::container::flat_map<std::string, std::variant<std::string>>
910 propertiesChanged;
911 msg.read(osStateInterface, propertiesChanged);
912
913 for (const auto& [name, value] : propertiesChanged)
914 {
915 if (name == "OperatingSystemState")
916 {
917 const std::string* state = std::get_if<std::string>(&value);
918 if (state == nullptr)
919 {
920 std::cerr << "Unable to read OS state value\n";
921 return;
922 }
Andrei Kartashev328685e2021-12-27 17:24:18 +0300923 // Note: Short version of OperatingSystemState value is
924 // deprecated and would be removed in the future
925 if ((*state == "Standby") ||
926 (*state == "xyz.openbmc_project.State.OperatingSystem."
927 "Status.OSStatus.Standby"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700928 {
929 peci_pcie::abortScan = false;
930 waitForOSStandbyDelay(io, objServer, osStandbyTimer,
931 cpuInfo);
932 }
Andrei Kartashev328685e2021-12-27 17:24:18 +0300933 else if ((*state == "Inactive") ||
934 (*state ==
935 "xyz.openbmc_project.State.OperatingSystem."
936 "Status.OSStatus.Inactive"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700937 {
938 peci_pcie::abortScan = true;
939 osStandbyTimer.cancel();
940 }
941 }
942 }
943 });
944
945 // Check if the OS state is already available
946 conn->async_method_call(
947 [&io, &objServer, &osStandbyTimer,
948 &cpuInfo](boost::system::error_code ec,
949 const std::variant<std::string>& property) {
950 if (ec)
951 {
952 std::cerr << "error with OS state async_method_call\n";
953 return;
954 }
955
956 const std::string* state = std::get_if<std::string>(&property);
957 if (state == nullptr)
958 {
959 std::cerr << "Unable to read OS state value\n";
960 return;
961 }
962
963 // If the OS state is in Standby, then BIOS is done and we can
964 // continue. Otherwise, we just wait for the match
Andrei Kartashev328685e2021-12-27 17:24:18 +0300965 // Note: Short version of OperatingSystemState value is deprecated
966 // and would be removed in the future
967
968 if ((*state == "Standby") ||
969 (*state == "xyz.openbmc_project.State.OperatingSystem.Status."
970 "OSStatus.Standby"))
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700971 {
972 waitForOSStandbyDelay(io, objServer, osStandbyTimer, cpuInfo);
973 }
974 },
975 "xyz.openbmc_project.State.OperatingSystem",
976 "/xyz/openbmc_project/state/os", "org.freedesktop.DBus.Properties",
977 "Get", "xyz.openbmc_project.State.OperatingSystem.Status",
978 "OperatingSystemState");
979}
980
Jason M. Billsd1e40602019-05-09 11:43:51 -0700981int main(int argc, char* argv[])
982{
983 // setup connection to dbus
984 boost::asio::io_service io;
985 std::shared_ptr<sdbusplus::asio::connection> conn =
986 std::make_shared<sdbusplus::asio::connection>(io);
987
988 // PECI PCIe Object
989 conn->request_name(peci_pcie::peciPCIeObject);
990 sdbusplus::asio::object_server server =
991 sdbusplus::asio::object_server(conn);
992
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300993 // CPU map
994 std::vector<CPUInfo> cpuInfo;
995
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700996#ifdef WAIT_FOR_OS_STANDBY
997 boost::asio::steady_timer osStandbyTimer(io);
998 monitorOSStandby(io, conn, server, osStandbyTimer, cpuInfo);
999#else
Jason M. Billsd1e40602019-05-09 11:43:51 -07001000 // Start the PECI check loop
1001 boost::asio::steady_timer peciWaitTimer(
1002 io, std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001003 peciWaitTimer.async_wait([&peciWaitTimer, &io, &server,
1004 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -07001005 if (ec)
1006 {
1007 // operation_aborted is expected if timer is canceled
1008 // before completion.
1009 if (ec != boost::asio::error::operation_aborted)
1010 {
1011 std::cerr << "PECI Available Check async_wait failed " << ec;
1012 }
1013 return;
1014 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001015 peciAvailableCheck(peciWaitTimer, io, server, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -07001016 });
Jason M. Billsee6d80b2021-06-11 07:37:30 -07001017#endif
Jason M. Billsd1e40602019-05-09 11:43:51 -07001018
1019 io.run();
1020
1021 return 0;
1022}