blob: 4f1a7eb058cec0f8c5a38777f576fb84d67d4cf4 [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
Ed Tanous985d9d92023-03-01 10:35:33 -080022#include <boost/asio/io_context.hpp>
Jason M. Billsbce86a62020-10-08 16:03:47 -070023#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{
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -050037
38struct PcieInterfaces
39{
40 std::shared_ptr<sdbusplus::asio::dbus_interface> deviceIface;
41 std::shared_ptr<sdbusplus::asio::dbus_interface> assetIface;
42};
43
Jason M. Billsd1e40602019-05-09 11:43:51 -070044static boost::container::flat_map<
45 int, boost::container::flat_map<
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -050046 int, boost::container::flat_map<int, PcieInterfaces>>>
Jason M. Billsd1e40602019-05-09 11:43:51 -070047 pcieDeviceDBusMap;
48
Jason M. Billsee6d80b2021-06-11 07:37:30 -070049static bool abortScan;
Paul Fertser07343142022-12-01 21:04:57 +000050static bool scanInProgress;
Jason M. Billsee6d80b2021-06-11 07:37:30 -070051
Paul Fertser3b2afcb2022-12-16 12:17:15 +000052constexpr const bool debug = false;
53
Jason M. Billsd1e40602019-05-09 11:43:51 -070054namespace function
55{
Patrick Williams42a9ac82023-05-10 07:51:22 -050056static constexpr const char* functionTypeName = "FunctionType";
57static constexpr const char* deviceClassName = "DeviceClass";
58static constexpr const char* vendorIdName = "VendorId";
59static constexpr const char* deviceIdName = "DeviceId";
60static constexpr const char* classCodeName = "ClassCode";
61static constexpr const char* revisionIdName = "RevisionId";
62static constexpr const char* subsystemIdName = "SubsystemId";
63static constexpr const char* subsystemVendorIdName = "SubsystemVendorId";
Jason M. Billsd1e40602019-05-09 11:43:51 -070064} // namespace function
Andrei Kartashev6f552032021-05-11 21:25:29 +030065
66static constexpr const std::array pciConfigInfo{
67 std::tuple<const char*, int, int>{function::functionTypeName, -1, -1},
68 std::tuple<const char*, int, int>{function::deviceClassName, -1, -1},
69 std::tuple<const char*, int, int>{function::vendorIdName, 0, 2},
70 std::tuple<const char*, int, int>{function::deviceIdName, 2, 2},
71 std::tuple<const char*, int, int>{function::classCodeName, 9, 3},
72 std::tuple<const char*, int, int>{function::revisionIdName, 8, 1},
73 std::tuple<const char*, int, int>{function::subsystemIdName, 0x2e, 2},
74 std::tuple<const char*, int, int>{function::subsystemVendorIdName, 0x2c,
75 2}};
Jason M. Billsd1e40602019-05-09 11:43:51 -070076} // namespace peci_pcie
77
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030078enum class resCode
79{
80 resOk,
Spencer Kubb5efe72021-09-02 16:11:14 +080081 resSkip,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030082 resErr
83};
84
Jason M. Bills5d049732019-10-25 15:55:15 -070085struct CPUInfo
Jason M. Billsd1e40602019-05-09 11:43:51 -070086{
Jason M. Bills5d049732019-10-25 15:55:15 -070087 size_t addr;
88 bool skipCpuBuses;
89 boost::container::flat_set<size_t> cpuBusNums;
90};
91
92// PECI Client Address Map
Andrei Kartashev8e966032021-07-02 20:04:30 +030093static resCode getCPUBusMap(std::vector<CPUInfo>& cpuInfo)
Jason M. Bills5d049732019-10-25 15:55:15 -070094{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +030095 cpuInfo.clear();
Andrei Kartashev8e966032021-07-02 20:04:30 +030096 for (size_t addr = MIN_CLIENT_ADDR; addr <= MAX_CLIENT_ADDR; addr++)
Jason M. Billsd1e40602019-05-09 11:43:51 -070097 {
Andrei Kartashev8e966032021-07-02 20:04:30 +030098 if (peci_Ping(addr) != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -070099 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300100 continue;
Jason M. Bills5d049732019-10-25 15:55:15 -0700101 }
Jason M. Bills5d049732019-10-25 15:55:15 -0700102
Andrei Kartashev8e966032021-07-02 20:04:30 +0300103 auto& cpu = cpuInfo.emplace_back(CPUInfo{addr, false, {}});
Jason M. Bills5d049732019-10-25 15:55:15 -0700104 uint8_t cc = 0;
105 CPUModel model{};
106 uint8_t stepping = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300107 if (peci_GetCPUID(addr, &model, &stepping, &cc) != PECI_CC_SUCCESS)
Jason M. Bills5d049732019-10-25 15:55:15 -0700108 {
109 std::cerr << "Cannot get CPUID!\n";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300110 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700111 }
112
113 switch (model)
114 {
115 case skx:
116 {
117 // Get the assigned CPU bus numbers from CPUBUSNO and CPUBUSNO1
118 // (B(0) D8 F2 offsets CCh and D0h)
119 uint32_t cpuBusNum = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300120 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xCC, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700121 (uint8_t*)&cpuBusNum,
122 &cc) != PECI_CC_SUCCESS)
123 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300124 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700125 }
126 uint32_t cpuBusNum1 = 0;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300127 if (peci_RdPCIConfigLocal(addr, 0, 8, 2, 0xD0, 4,
Jason M. Bills5d049732019-10-25 15:55:15 -0700128 (uint8_t*)&cpuBusNum1,
129 &cc) != PECI_CC_SUCCESS)
130 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300131 return resCode::resErr;
Jason M. Bills5d049732019-10-25 15:55:15 -0700132 }
133
134 // Add the CPU bus numbers to the set for this CPU
135 while (cpuBusNum)
136 {
137 // Get the LSB
138 size_t busNum = cpuBusNum & 0xFF;
139 cpu.cpuBusNums.insert(busNum);
140 // Shift right by one byte
141 cpuBusNum >>= 8;
142 }
143 while (cpuBusNum1)
144 {
145 // Get the LSB
146 size_t busNum = cpuBusNum1 & 0xFF;
147 cpu.cpuBusNums.insert(busNum);
148 // Shift right by one byte
Zev Weiss9fa54b52020-09-02 21:20:33 +0000149 cpuBusNum1 >>= 8;
Jason M. Bills5d049732019-10-25 15:55:15 -0700150 }
151 cpu.skipCpuBuses = true;
152 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700153 }
154 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300155 return cpuInfo.empty() ? resCode::resErr : resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700156}
157
158static bool isPECIAvailable(void)
159{
Jason M. Bills5d049732019-10-25 15:55:15 -0700160 for (size_t i = MIN_CLIENT_ADDR; i <= MAX_CLIENT_ADDR; i++)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700161 {
Jason M. Bills5d049732019-10-25 15:55:15 -0700162 if (peci_Ping(i) == PECI_CC_SUCCESS)
163 {
164 return true;
165 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700166 }
Jason M. Bills5d049732019-10-25 15:55:15 -0700167 return false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700168}
169
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300170static resCode getDataFromPCIeConfig(const int& clientAddr, const int& bus,
171 const int& dev, const int& func,
172 const int& offset, const int& size,
173 uint32_t& pciData)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700174{
175 // PECI RdPCIConfig() currently only supports 4 byte reads, so adjust
176 // the offset and size to get the right data
177 static constexpr const int pciReadSize = 4;
178 int mod = offset % pciReadSize;
179 int pciOffset = offset - mod;
180 if (mod + size > pciReadSize)
181 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300182 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700183 }
184
185 std::array<uint8_t, pciReadSize> data;
186 uint8_t cc;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300187 int ret = PECI_CC_TIMEOUT;
Paul Fertserb08723d2022-12-16 11:49:08 +0000188 for (int index = 0; (index < 15) && (ret == PECI_CC_TIMEOUT); index++)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300189 {
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700190#ifdef USE_RDENDPOINTCFG
191 ret = peci_RdEndPointConfigPci(clientAddr, // CPU Address
192 0, // PCI Seg (use 0 for now)
193 bus, // PCI Bus
194 dev, // PCI Device
195 func, // PCI Function
196 pciOffset, // PCI Offset
197 pciReadSize, // PCI Read Size
198 data.data(), // PCI Read Data
199 &cc); // PECI Completion Code
200#else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300201 ret = peci_RdPCIConfig(clientAddr, // CPU Address
Jason M. Billsd1e40602019-05-09 11:43:51 -0700202 bus, // PCI Bus
203 dev, // PCI Device
204 func, // PCI Function
205 pciOffset, // PCI Offset
206 data.data(), // PCI Read Data
207 &cc); // PECI Completion Code
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700208#endif
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000209 if constexpr (peci_pcie::debug)
210 {
211 std::cerr << "Request: bus " << bus << " dev " << dev << " func "
212 << func << " pciOffset " << pciOffset << " ret: " << ret
213 << " cc: " << static_cast<int>(cc) << "\n";
214 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300215 }
Paul Fertser541637c2022-12-02 13:42:01 +0000216 if (ret != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700217 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300218 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700219 }
Paul Fertser541637c2022-12-02 13:42:01 +0000220 else if (cc != PECI_DEV_CC_SUCCESS)
221 {
222 return resCode::resSkip;
223 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700224
225 // Now build the requested data into a single number
226 pciData = 0;
227 for (int i = mod; i < mod + size; i++)
228 {
Jason M. Billse55832b2021-06-14 16:00:49 -0700229 pciData |= static_cast<uint32_t>(data[i]) << 8 * (i - mod);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700230 }
231
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300232 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700233}
234
Andrei Kartashev6f552032021-05-11 21:25:29 +0300235static resCode getStringFromData(const int& size, const uint32_t& data,
236 std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700237{
Jason M. Billsd1e40602019-05-09 11:43:51 -0700238 // And convert it to a string
239 std::stringstream dataStream;
240 dataStream << "0x" << std::hex << std::setfill('0') << std::setw(size * 2)
241 << data;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300242 res = dataStream.str();
243 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700244}
245
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300246static resCode getVendorName(const int& clientAddr, const int& bus,
247 const int& dev, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700248{
249 static constexpr const int vendorIDOffset = 0x00;
250 static constexpr const int vendorIDSize = 2;
251
252 // Get the header type register from function 0
253 uint32_t vendorID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300254 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, vendorIDOffset,
255 vendorIDSize, vendorID) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700256 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300257 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700258 }
259 // Get the vendor name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300260 res = pciVendors.try_emplace(vendorID, otherVendor).first->second;
261 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700262}
263
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300264static resCode getDeviceClass(const int& clientAddr, const int& bus,
265 const int& dev, const int& func, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700266{
267 static constexpr const int baseClassOffset = 0x0b;
268 static constexpr const int baseClassSize = 1;
269
270 // Get the Device Base Class
271 uint32_t baseClass = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300272 if (getDataFromPCIeConfig(clientAddr, bus, dev, func, baseClassOffset,
273 baseClassSize, baseClass) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700274 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300275 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700276 }
277 // Get the base class name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300278 res = pciDeviceClasses.try_emplace(baseClass, otherClass).first->second;
279 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700280}
281
Spencer Kubb5efe72021-09-02 16:11:14 +0800282static resCode getCapReading(const int& clientAddr, const int& bus,
283 const int& dev, uint32_t& capReading,
284 const int compareCapID, const int offsetAddress,
285 const int offsetLength)
286{
287 resCode error;
288 uint32_t capAddress = 0;
289 uint32_t capabilityID;
290 uint32_t nextCapPointer = peci_pcie::pointToCapStruct;
291
292 do
293 {
294 // Get capability address
295 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, nextCapPointer,
296 1, capAddress);
297 if (error != resCode::resOk)
298 {
299 return error;
300 }
301 // Capability struct address is a pointer which point to next capability
302 // struct, so if capability struct address is 0 means it doesn't have
303 // next capability struct.
304 if (capAddress == 0)
305 {
306 return resCode::resSkip;
307 }
308 // Get capability ID
309 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, capAddress, 1,
310 capabilityID);
311 if (error != resCode::resOk)
312 {
313 return error;
314 }
315 nextCapPointer = capAddress + peci_pcie::capPointerOffset;
316
317 } while (capabilityID != compareCapID);
318 // Get capability reading.
319 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0,
320 capAddress + offsetAddress, offsetLength,
321 capReading);
322 if (error != resCode::resOk)
323 {
324 return error;
325 }
326 return resCode::resOk;
327}
328
329static resCode getGenerationInUse(const int& clientAddr, const int& bus,
330 const int& dev, std::string& generationInUse)
331{
Willy Tu975faf72022-09-23 18:39:16 +0000332 static std::unordered_set<uint32_t> linkSpeedSkipMap;
Spencer Kubb5efe72021-09-02 16:11:14 +0800333 resCode error;
334 std::string res;
335 uint32_t capReading = 0;
336
337 // Capability ID 0x10(16) is PCI Express
338 constexpr int pcieCapID = 16;
339 constexpr int capLength = 2;
340 uint32_t linkStatus;
341
342 error = getCapReading(clientAddr, bus, dev, linkStatus, pcieCapID,
343 peci_pcie::linkStatusOffset, capLength);
344 if (error != resCode::resOk)
345 {
346 return error;
347 }
348
349 uint32_t linkSpeed = linkStatus & peci_pcie::maskOfCLS;
350
351 switch (linkSpeed)
352 {
353 case peci_pcie::pcieGen1:
354 generationInUse = "xyz.openbmc_project.Inventory.Item."
355 "PCIeSlot.Generations.Gen1";
356 error = resCode::resOk;
357 break;
358 case peci_pcie::pcieGen2:
359 generationInUse = "xyz.openbmc_project.Inventory.Item."
360 "PCIeSlot.Generations.Gen2";
361 error = resCode::resOk;
362 break;
363 case peci_pcie::pcieGen3:
364 generationInUse = "xyz.openbmc_project.Inventory.Item."
365 "PCIeSlot.Generations.Gen3";
366 error = resCode::resOk;
367 break;
368 case peci_pcie::pcieGen4:
369 generationInUse = "xyz.openbmc_project.Inventory.Item."
370 "PCIeSlot.Generations.Gen4";
371 error = resCode::resOk;
372 break;
373 case peci_pcie::pcieGen5:
374 generationInUse = "xyz.openbmc_project.Inventory.Item."
375 "PCIeSlot.Generations.Gen5";
376 error = resCode::resOk;
377 break;
378 default:
Willy Tu975faf72022-09-23 18:39:16 +0000379 if (!linkSpeedSkipMap.contains(linkSpeed))
380 {
381 std::cerr << "Link speed : " << linkSpeed
382 << " can not mapping to PCIe type list.\n";
383 linkSpeedSkipMap.emplace(linkSpeed);
384 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800385 error = resCode::resSkip;
386 }
387 return error;
388}
389
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300390static resCode isMultiFunction(const int& clientAddr, const int& bus,
391 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700392{
393 static constexpr const int headerTypeOffset = 0x0e;
394 static constexpr const int headerTypeSize = 1;
395 static constexpr const int multiFuncBit = 1 << 7;
396
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300397 res = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700398 // Get the header type register from function 0
399 uint32_t headerType = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300400 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, headerTypeOffset,
401 headerTypeSize, headerType) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700402 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300403 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700404 }
405 // Check if it's a multifunction device
406 if (headerType & multiFuncBit)
407 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300408 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700409 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300410 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700411}
412
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300413static resCode pcieFunctionExists(const int& clientAddr, const int& bus,
414 const int& dev, const int& func, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700415{
416 constexpr const int pciIDOffset = 0;
417 constexpr const int pciIDSize = 4;
418 uint32_t pciID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300419 res = false;
Paul Fertser541637c2022-12-02 13:42:01 +0000420
421 resCode error = getDataFromPCIeConfig(clientAddr, bus, dev, func,
422 pciIDOffset, pciIDSize, pciID);
423 if (error == resCode::resSkip)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700424 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300425 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700426 }
Paul Fertser541637c2022-12-02 13:42:01 +0000427 else if (error == resCode::resErr)
428 {
429 return resCode::resErr;
430 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700431
432 // if VID and DID are all 0s or 1s, then the device doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300433 if (pciID != 0x00000000 && pciID != 0xFFFFFFFF)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700434 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300435 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700436 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300437 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700438}
439
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300440static resCode pcieDeviceExists(const int& clientAddr, const int& bus,
441 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700442{
443 // Check if this device exists by checking function 0
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300444 return pcieFunctionExists(clientAddr, bus, dev, 0, res);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700445}
446
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300447static resCode setPCIeProperty(const int& clientAddr, const int& bus,
448 const int& dev, const std::string& propertyName,
449 const std::string& propertyValue)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700450{
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500451 peci_pcie::PcieInterfaces pcieIfaces =
Jason M. Billsd1e40602019-05-09 11:43:51 -0700452 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
453
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500454 std::shared_ptr<sdbusplus::asio::dbus_interface> iface;
455 if (propertyName == "Manufacturer")
456 {
457 iface = pcieIfaces.assetIface;
458 }
459 else
460 {
461 iface = pcieIfaces.deviceIface;
462 }
463
Jason M. Billsd1e40602019-05-09 11:43:51 -0700464 if (iface->is_initialized())
465 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300466 if (!iface->set_property(propertyName, propertyValue))
467 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700468 }
469 else
470 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300471 if (!iface->register_property(propertyName, propertyValue))
472 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700473 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300474 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700475}
476
477static void setDefaultPCIeFunctionProperties(const int& clientAddr,
478 const int& bus, const int& dev,
479 const int& func)
480{
481 // Set the function-specific properties
Andrei Kartashev6f552032021-05-11 21:25:29 +0300482 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700483 {
484 setPCIeProperty(clientAddr, bus, dev,
485 "Function" + std::to_string(func) + std::string(name),
486 std::string());
487 }
488}
489
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300490static resCode setPCIeFunctionProperties(const int& clientAddr, const int& bus,
491 const int& dev, const int& func)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700492{
Andrei Kartashev6f552032021-05-11 21:25:29 +0300493 uint32_t data = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300494 std::string res;
Andrei Kartashev6f552032021-05-11 21:25:29 +0300495 resCode error;
496
497 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
498 {
499 if (offset < 0)
500 {
501 continue;
502 }
503
504 error = getDataFromPCIeConfig(clientAddr, bus, dev, func, offset, size,
505 data);
506 if (error != resCode::resOk)
507 {
508 return error;
509 }
510 getStringFromData(size, data, res);
511 setPCIeProperty(clientAddr, bus, dev,
512 "Function" + std::to_string(func) + std::string(name),
513 res);
514 }
515
Jason M. Billsd1e40602019-05-09 11:43:51 -0700516 // Set the function type always to physical for now
517 setPCIeProperty(clientAddr, bus, dev,
518 "Function" + std::to_string(func) +
519 std::string(peci_pcie::function::functionTypeName),
520 "Physical");
521
522 // Set the function Device Class
Andrei Kartashev6f552032021-05-11 21:25:29 +0300523 error = getDeviceClass(clientAddr, bus, dev, func, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300524 if (error != resCode::resOk)
525 {
526 return error;
527 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700528 setPCIeProperty(clientAddr, bus, dev,
529 "Function" + std::to_string(func) +
530 std::string(peci_pcie::function::deviceClassName),
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300531 res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300532 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700533}
534
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300535static resCode setPCIeDeviceProperties(const int& clientAddr, const int& bus,
536 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700537{
538 // Set the device manufacturer
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300539 std::string manuf;
540 resCode error = getVendorName(clientAddr, bus, dev, manuf);
541 if (error != resCode::resOk)
542 {
543 return error;
544 }
545 setPCIeProperty(clientAddr, bus, dev, "Manufacturer", manuf);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700546
547 // Set the device type
Patrick Williams42a9ac82023-05-10 07:51:22 -0500548 constexpr const char* deviceTypeName = "DeviceType";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300549 bool multiFunc;
550 error = isMultiFunction(clientAddr, bus, dev, multiFunc);
551 if (error != resCode::resOk)
552 {
553 return error;
554 }
555 if (multiFunc)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700556 {
557 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "MultiFunction");
558 }
559 else
560 {
561 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "SingleFunction");
562 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800563
564 // Set PCIe Generation
Patrick Williams42a9ac82023-05-10 07:51:22 -0500565 constexpr const char* generationInUseName = "GenerationInUse";
Spencer Kubb5efe72021-09-02 16:11:14 +0800566 std::string generationInUse;
567 error = getGenerationInUse(clientAddr, bus, dev, generationInUse);
568 if (error == resCode::resErr)
569 {
570 return error;
571 }
572 // "resSkip" status means it can't get the capability reading, such like
573 // this device is not PCI Express.
574 if (error == resCode::resSkip)
575 {
576 setPCIeProperty(clientAddr, bus, dev, generationInUseName, "");
577 return resCode::resOk;
578 }
579 setPCIeProperty(clientAddr, bus, dev, generationInUseName, generationInUse);
580
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300581 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700582}
583
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300584static resCode updatePCIeDevice(const int& clientAddr, const int& bus,
585 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700586{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300587 if (setPCIeDeviceProperties(clientAddr, bus, dev) != resCode::resOk)
588 {
589 return resCode::resErr;
590 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700591
Nidhin MS8b18f522023-06-28 10:25:06 +0530592 bool multiFunc = false;
593 resCode error = isMultiFunction(clientAddr, bus, dev, multiFunc);
594 if (error != resCode::resOk)
595 {
596 return error;
597 }
598 // Functions greater than 0 should only be accessed on multi-function
599 // devices
600 int maxPCIFunctions = multiFunc ? peci_pcie::maxPCIFunctions : 1;
601
Jason M. Billsd1e40602019-05-09 11:43:51 -0700602 // Walk through and populate the functions for this device
Nidhin MS8b18f522023-06-28 10:25:06 +0530603 for (int func = 0; func < maxPCIFunctions; func++)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700604 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300605 bool res;
606 resCode error = pcieFunctionExists(clientAddr, bus, dev, func, res);
607 if (error != resCode::resOk)
608 {
609 return error;
610 }
611 if (res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700612 {
613 // Set the properties for this function
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300614 if (setPCIeFunctionProperties(clientAddr, bus, dev, func) !=
615 resCode::resOk)
616 {
617 return resCode::resErr;
618 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700619 }
620 else
621 {
622 // Set default properties for unused functions
623 setDefaultPCIeFunctionProperties(clientAddr, bus, dev, func);
624 }
625 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300626 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700627}
628
629static void removePCIeDevice(sdbusplus::asio::object_server& objServer,
630 const int& clientAddr, const int& bus,
631 const int& dev)
632{
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500633 peci_pcie::PcieInterfaces ifaces =
Jason M. Billsd1e40602019-05-09 11:43:51 -0700634 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
635
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500636 objServer.remove_interface(ifaces.deviceIface);
637 objServer.remove_interface(ifaces.assetIface);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700638
639 peci_pcie::pcieDeviceDBusMap[clientAddr][bus].erase(dev);
640 if (peci_pcie::pcieDeviceDBusMap[clientAddr][bus].empty())
641 {
642 peci_pcie::pcieDeviceDBusMap[clientAddr].erase(bus);
643 }
644 if (peci_pcie::pcieDeviceDBusMap[clientAddr].empty())
645 {
646 peci_pcie::pcieDeviceDBusMap.erase(clientAddr);
647 }
648}
649
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300650static resCode addPCIeDevice(sdbusplus::asio::object_server& objServer,
651 const int& clientAddr, const int& cpu,
652 const int& bus, const int& dev)
653{
654 std::string pathName = std::string(peci_pcie::peciPCIePath) + "/S" +
655 std::to_string(cpu) + "B" + std::to_string(bus) +
656 "D" + std::to_string(dev);
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500657 peci_pcie::PcieInterfaces ifaces;
658 ifaces.deviceIface =
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300659 objServer.add_interface(pathName, peci_pcie::peciPCIeDeviceInterface);
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500660 ifaces.assetIface =
661 objServer.add_interface(pathName, peci_pcie::peciPCIeAssetInterface);
662 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev] = ifaces;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300663
664 // Update the properties for the new device
665 if (updatePCIeDevice(clientAddr, bus, dev) != resCode::resOk)
666 {
667 removePCIeDevice(objServer, clientAddr, bus, dev);
668 return resCode::resErr;
669 }
670
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500671 ifaces.deviceIface->initialize();
672 ifaces.assetIface->initialize();
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300673 return resCode::resOk;
674}
675
Jason M. Billsd1e40602019-05-09 11:43:51 -0700676static bool pcieDeviceInDBusMap(const int& clientAddr, const int& bus,
677 const int& dev)
678{
679 if (auto clientAddrIt = peci_pcie::pcieDeviceDBusMap.find(clientAddr);
680 clientAddrIt != peci_pcie::pcieDeviceDBusMap.end())
681 {
682 if (auto busIt = clientAddrIt->second.find(bus);
683 busIt != clientAddrIt->second.end())
684 {
685 if (auto devIt = busIt->second.find(dev);
686 devIt != busIt->second.end())
687 {
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500688 if (devIt->second.deviceIface != nullptr ||
689 devIt->second.assetIface != nullptr)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700690 {
691 return true;
692 }
693 }
694 }
695 }
696 return false;
697}
698
Ed Tanous985d9d92023-03-01 10:35:33 -0800699static resCode probePCIeDevice(boost::asio::io_context& io,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300700 sdbusplus::asio::object_server& objServer,
Andrei Kartashev8e966032021-07-02 20:04:30 +0300701 size_t addr, int cpu, int bus, int dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700702{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300703 bool res;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300704 resCode error = pcieDeviceExists(addr, bus, dev, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300705 if (error != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700706 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300707 return error;
Jason M. Bills5d049732019-10-25 15:55:15 -0700708 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300709 if (res)
Jason M. Bills5d049732019-10-25 15:55:15 -0700710 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300711 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700712 {
713 // This device is already in D-Bus, so update it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300714 if (updatePCIeDevice(addr, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300715 {
716 return resCode::resErr;
717 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700718 }
719 else
720 {
721 // This device is not in D-Bus, so add it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300722 if (addPCIeDevice(objServer, addr, cpu, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300723 {
724 return resCode::resErr;
725 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700726 }
727 }
728 else
729 {
730 // If PECI is not available, then stop scanning
731 if (!isPECIAvailable())
732 {
Paul Fertser541637c2022-12-02 13:42:01 +0000733 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700734 }
735
Andrei Kartashev8e966032021-07-02 20:04:30 +0300736 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700737 {
738 // This device is in D-Bus, so remove it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300739 removePCIeDevice(objServer, addr, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700740 }
741 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300742 return resCode::resOk;
743}
744
Ed Tanous985d9d92023-03-01 10:35:33 -0800745static void scanNextPCIeDevice(boost::asio::io_context& io,
Andrei Kartashev8e966032021-07-02 20:04:30 +0300746 sdbusplus::asio::object_server& objServer,
747 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
748 int dev);
Ed Tanous985d9d92023-03-01 10:35:33 -0800749static void scanPCIeDevice(boost::asio::io_context& io,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300750 sdbusplus::asio::object_server& objServer,
751 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
752 int dev)
753{
Andrei Kartashev8e966032021-07-02 20:04:30 +0300754 if (cpu >= cpuInfo.size())
755 {
756 std::cerr << "Request to scan CPU" << cpu
757 << " while CPU array has size " << cpuInfo.size() << "\n";
758 return;
759 }
760 auto& info = cpuInfo[cpu];
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300761 // Check if this is a CPU bus that we should skip
Andrei Kartashev8e966032021-07-02 20:04:30 +0300762 if (info.skipCpuBuses && info.cpuBusNums.count(bus))
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300763 {
764 std::cout << "Skipping CPU " << cpu << " Bus Number " << bus << "\n";
765 // Skip all the devices on this bus
766 dev = peci_pcie::maxPCIDevices;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300767 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300768 else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300769 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300770 if (probePCIeDevice(io, objServer, info.addr, cpu, bus, dev) !=
771 resCode::resOk)
772 {
773 std::cerr << "Failed to probe CPU " << cpu << " Bus " << bus
774 << " Device " << dev << "\n";
Paul Fertser541637c2022-12-02 13:42:01 +0000775 peci_pcie::abortScan = true;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300776 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300777 }
778
Jason M. Bills5d049732019-10-25 15:55:15 -0700779 scanNextPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Andrei Kartashev8e966032021-07-02 20:04:30 +0300780 return;
Jason M. Bills5d049732019-10-25 15:55:15 -0700781}
Jason M. Billsd1e40602019-05-09 11:43:51 -0700782
Ed Tanous985d9d92023-03-01 10:35:33 -0800783static void scanNextPCIeDevice(boost::asio::io_context& io,
Jason M. Bills5d049732019-10-25 15:55:15 -0700784 sdbusplus::asio::object_server& objServer,
785 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
786 int dev)
787{
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700788 if (peci_pcie::abortScan)
789 {
Paul Fertser07343142022-12-01 21:04:57 +0000790 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700791 std::cerr << "PCIe scan aborted\n";
792 return;
793 }
794
Jason M. Billsd1e40602019-05-09 11:43:51 -0700795 // PCIe Device scan completed, so move to the next device
796 if (++dev >= peci_pcie::maxPCIDevices)
797 {
798 // All devices scanned, so move to the next bus
799 dev = 0;
800 if (++bus >= peci_pcie::maxPCIBuses)
801 {
802 // All buses scanned, so move to the next CPU
803 bus = 0;
Jason M. Bills5d049732019-10-25 15:55:15 -0700804 if (++cpu >= cpuInfo.size())
Jason M. Billsd1e40602019-05-09 11:43:51 -0700805 {
806 // All CPUs scanned, so we're done
Paul Fertser07343142022-12-01 21:04:57 +0000807 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700808 std::cerr << "PCIe scan completed\n";
Jason M. Billsd1e40602019-05-09 11:43:51 -0700809 return;
810 }
811 }
812 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300813 boost::asio::post(io, [&io, &objServer, &cpuInfo, cpu, bus, dev]() mutable {
Jason M. Bills5d049732019-10-25 15:55:15 -0700814 scanPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700815 });
816}
817
Ed Tanous985d9d92023-03-01 10:35:33 -0800818static void startPCIeScan(boost::asio::io_context& io,
Paul Fertser07343142022-12-01 21:04:57 +0000819 sdbusplus::asio::object_server& objServer,
820 std::vector<CPUInfo>& cpuInfo)
821{
822 if (!peci_pcie::scanInProgress)
823 {
824 // get the PECI client address list
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000825 std::cerr << "Getting map\n";
Paul Fertser07343142022-12-01 21:04:57 +0000826 if (getCPUBusMap(cpuInfo) != resCode::resOk)
827 {
Paul Fertser541637c2022-12-02 13:42:01 +0000828 peci_pcie::abortScan = true;
Paul Fertser07343142022-12-01 21:04:57 +0000829 return;
830 }
831 std::cerr << "PCIe scan started\n";
832 // scan PCIe starting from CPU 0, Bus 0, Device 0
833 peci_pcie::scanInProgress = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000834 peci_pcie::abortScan = false;
Paul Fertser07343142022-12-01 21:04:57 +0000835 scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
836 }
837}
838
Jason M. Billsd1e40602019-05-09 11:43:51 -0700839static void peciAvailableCheck(boost::asio::steady_timer& peciWaitTimer,
Ed Tanous985d9d92023-03-01 10:35:33 -0800840 boost::asio::io_context& io,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300841 sdbusplus::asio::object_server& objServer,
842 std::vector<CPUInfo>& cpuInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700843{
Jason M. Bills5d049732019-10-25 15:55:15 -0700844 static bool lastPECIState = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700845 bool peciAvailable = isPECIAvailable();
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000846 if constexpr (peci_pcie::debug)
847 {
848 std::cerr << "peciAvailableCheck " << peciAvailable << " "
849 << lastPECIState << " " << peci_pcie::abortScan << "\n";
850 }
Paul Fertser541637c2022-12-02 13:42:01 +0000851 if (peciAvailable && (!lastPECIState || peci_pcie::abortScan))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700852 {
853 lastPECIState = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000854 auto pcieTimeout = std::make_shared<boost::asio::steady_timer>(io);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700855 constexpr const int pcieWaitTime = 60;
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000856 if constexpr (peci_pcie::debug)
857 {
858 std::cerr << "Scanning in 60 seconds\n";
859 }
Paul Fertser541637c2022-12-02 13:42:01 +0000860 pcieTimeout->expires_after(std::chrono::seconds(pcieWaitTime));
861 pcieTimeout->async_wait([&io, &objServer, &cpuInfo, pcieTimeout](
862 const boost::system::error_code& ec) {
863 if (ec)
864 {
865 // operation_aborted is expected if timer is canceled
866 // before completion.
867 if (ec != boost::asio::error::operation_aborted)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700868 {
Paul Fertser541637c2022-12-02 13:42:01 +0000869 std::cerr << "PECI PCIe async_wait failed " << ec;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700870 }
Paul Fertser541637c2022-12-02 13:42:01 +0000871 lastPECIState = false;
872 return;
873 }
874 startPCIeScan(io, objServer, cpuInfo);
875 });
Jason M. Billsd1e40602019-05-09 11:43:51 -0700876 }
877 else if (!peciAvailable && lastPECIState)
878 {
879 lastPECIState = false;
880 }
881
882 peciWaitTimer.expires_after(
883 std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300884 peciWaitTimer.async_wait([&peciWaitTimer, &io, &objServer,
885 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700886 if (ec)
887 {
888 // operation_aborted is expected if timer is canceled
889 // before completion.
890 if (ec != boost::asio::error::operation_aborted)
891 {
892 std::cerr << "PECI Available Check async_wait failed " << ec;
893 }
894 return;
895 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300896 peciAvailableCheck(peciWaitTimer, io, objServer, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700897 });
898}
899
Ed Tanous985d9d92023-03-01 10:35:33 -0800900static void waitForOSStandbyDelay(boost::asio::io_context& io,
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700901 sdbusplus::asio::object_server& objServer,
902 boost::asio::steady_timer& osStandbyTimer,
903 std::vector<CPUInfo>& cpuInfo)
904{
905 osStandbyTimer.expires_after(
906 std::chrono::seconds(peci_pcie::osStandbyDelaySeconds));
907
908 osStandbyTimer.async_wait(
909 [&io, &objServer, &cpuInfo](const boost::system::error_code& ec) {
Patrick Williams42a9ac82023-05-10 07:51:22 -0500910 if (ec == boost::asio::error::operation_aborted)
911 {
912 return; // we're being canceled
913 }
914 else if (ec)
915 {
916 std::cerr << "OS Standby async_wait failed: " << ec.value() << ": "
917 << ec.message() << "\n";
918 return;
919 }
920 startPCIeScan(io, objServer, cpuInfo);
921 });
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700922}
923
Ed Tanous985d9d92023-03-01 10:35:33 -0800924static void monitorOSStandby(boost::asio::io_context& io,
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700925 std::shared_ptr<sdbusplus::asio::connection> conn,
926 sdbusplus::asio::object_server& objServer,
927 boost::asio::steady_timer& osStandbyTimer,
928 std::vector<CPUInfo>& cpuInfo)
929{
930 std::cerr << "Start OperatingSystemState Monitor\n";
931
Patrick Williamsb2517082022-07-22 19:26:57 -0500932 static sdbusplus::bus::match_t osStateMatch(
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700933 *conn,
934 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
935 "PropertiesChanged',arg0='xyz.openbmc_project.State.OperatingSystem."
936 "Status'",
937 [&io, &objServer, &osStandbyTimer,
Patrick Williamsb2517082022-07-22 19:26:57 -0500938 &cpuInfo](sdbusplus::message_t& msg) {
Patrick Williams42a9ac82023-05-10 07:51:22 -0500939 // Get the OS State from the message
940 std::string osStateInterface;
941 boost::container::flat_map<std::string, std::variant<std::string>>
942 propertiesChanged;
943 msg.read(osStateInterface, propertiesChanged);
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700944
Patrick Williams42a9ac82023-05-10 07:51:22 -0500945 for (const auto& [name, value] : propertiesChanged)
946 {
947 if (name == "OperatingSystemState")
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700948 {
Patrick Williams42a9ac82023-05-10 07:51:22 -0500949 const std::string* state = std::get_if<std::string>(&value);
950 if (state == nullptr)
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700951 {
Patrick Williams42a9ac82023-05-10 07:51:22 -0500952 std::cerr << "Unable to read OS state value\n";
953 return;
954 }
955 // Note: Short version of OperatingSystemState value is
956 // deprecated and would be removed in the future
957 if ((*state == "Standby") ||
958 (*state == "xyz.openbmc_project.State.OperatingSystem."
959 "Status.OSStatus.Standby"))
960 {
961 peci_pcie::abortScan = false;
962 waitForOSStandbyDelay(io, objServer, osStandbyTimer,
963 cpuInfo);
964 }
965 else if ((*state == "Inactive") ||
966 (*state == "xyz.openbmc_project.State.OperatingSystem."
967 "Status.OSStatus.Inactive"))
968 {
969 peci_pcie::abortScan = true;
970 osStandbyTimer.cancel();
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700971 }
972 }
Patrick Williams42a9ac82023-05-10 07:51:22 -0500973 }
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700974 });
975
976 // Check if the OS state is already available
977 conn->async_method_call(
978 [&io, &objServer, &osStandbyTimer,
979 &cpuInfo](boost::system::error_code ec,
980 const std::variant<std::string>& property) {
Patrick Williams42a9ac82023-05-10 07:51:22 -0500981 if (ec)
982 {
983 std::cerr << "error with OS state async_method_call\n";
984 return;
985 }
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700986
Patrick Williams42a9ac82023-05-10 07:51:22 -0500987 const std::string* state = std::get_if<std::string>(&property);
988 if (state == nullptr)
989 {
990 std::cerr << "Unable to read OS state value\n";
991 return;
992 }
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700993
Patrick Williams42a9ac82023-05-10 07:51:22 -0500994 // If the OS state is in Standby, then BIOS is done and we can
995 // continue. Otherwise, we just wait for the match
996 // Note: Short version of OperatingSystemState value is deprecated
997 // and would be removed in the future
Andrei Kartashev328685e2021-12-27 17:24:18 +0300998
Patrick Williams42a9ac82023-05-10 07:51:22 -0500999 if ((*state == "Standby") ||
1000 (*state == "xyz.openbmc_project.State.OperatingSystem.Status."
1001 "OSStatus.Standby"))
1002 {
1003 waitForOSStandbyDelay(io, objServer, osStandbyTimer, cpuInfo);
1004 }
Jason M. Billsee6d80b2021-06-11 07:37:30 -07001005 },
1006 "xyz.openbmc_project.State.OperatingSystem",
1007 "/xyz/openbmc_project/state/os", "org.freedesktop.DBus.Properties",
1008 "Get", "xyz.openbmc_project.State.OperatingSystem.Status",
1009 "OperatingSystemState");
1010}
1011
Jason M. Billsd1e40602019-05-09 11:43:51 -07001012int main(int argc, char* argv[])
1013{
1014 // setup connection to dbus
Ed Tanous985d9d92023-03-01 10:35:33 -08001015 boost::asio::io_context io;
Jason M. Billsd1e40602019-05-09 11:43:51 -07001016 std::shared_ptr<sdbusplus::asio::connection> conn =
1017 std::make_shared<sdbusplus::asio::connection>(io);
1018
1019 // PECI PCIe Object
1020 conn->request_name(peci_pcie::peciPCIeObject);
1021 sdbusplus::asio::object_server server =
1022 sdbusplus::asio::object_server(conn);
1023
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001024 // CPU map
1025 std::vector<CPUInfo> cpuInfo;
1026
Jason M. Billsee6d80b2021-06-11 07:37:30 -07001027#ifdef WAIT_FOR_OS_STANDBY
1028 boost::asio::steady_timer osStandbyTimer(io);
1029 monitorOSStandby(io, conn, server, osStandbyTimer, cpuInfo);
1030#else
Jason M. Billsd1e40602019-05-09 11:43:51 -07001031 // Start the PECI check loop
1032 boost::asio::steady_timer peciWaitTimer(
1033 io, std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001034 peciWaitTimer.async_wait([&peciWaitTimer, &io, &server,
1035 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -07001036 if (ec)
1037 {
1038 // operation_aborted is expected if timer is canceled
1039 // before completion.
1040 if (ec != boost::asio::error::operation_aborted)
1041 {
1042 std::cerr << "PECI Available Check async_wait failed " << ec;
1043 }
1044 return;
1045 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001046 peciAvailableCheck(peciWaitTimer, io, server, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -07001047 });
Jason M. Billsee6d80b2021-06-11 07:37:30 -07001048#endif
Jason M. Billsd1e40602019-05-09 11:43:51 -07001049
1050 io.run();
1051
1052 return 0;
1053}