blob: ad1bbfdc5c22ab39697c90059d14ff7a5913c34e [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 {
Jason M. Bills9af905e2024-04-01 13:16:41 -0700115 case skylake:
Jason M. Bills5d049732019-10-25 15:55:15 -0700116 {
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,
Patrick Williams39c664c2024-08-16 15:21:58 -0400121 (uint8_t*)&cpuBusNum, &cc) !=
122 PECI_CC_SUCCESS)
Jason M. Bills5d049732019-10-25 15:55:15 -0700123 {
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,
Patrick Williams39c664c2024-08-16 15:21:58 -0400128 (uint8_t*)&cpuBusNum1, &cc) !=
129 PECI_CC_SUCCESS)
Jason M. Bills5d049732019-10-25 15:55:15 -0700130 {
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;
Jason M. Billsc076bd72023-07-31 12:25:05 -0700152 break;
153 }
154 default:
155 {
156 std::cerr << "CPU buses not found for CPU Model: 0x" << std::hex
157 << static_cast<int>(model) << std::dec << "\n";
158 break;
Jason M. Bills5d049732019-10-25 15:55:15 -0700159 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700160 }
161 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300162 return cpuInfo.empty() ? resCode::resErr : resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700163}
164
165static bool isPECIAvailable(void)
166{
Jason M. Bills5d049732019-10-25 15:55:15 -0700167 for (size_t i = MIN_CLIENT_ADDR; i <= MAX_CLIENT_ADDR; i++)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700168 {
Jason M. Bills5d049732019-10-25 15:55:15 -0700169 if (peci_Ping(i) == PECI_CC_SUCCESS)
170 {
171 return true;
172 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700173 }
Jason M. Bills5d049732019-10-25 15:55:15 -0700174 return false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700175}
176
Patrick Williams39c664c2024-08-16 15:21:58 -0400177static resCode getDataFromPCIeConfig(
178 const int& clientAddr, const int& bus, const int& dev, const int& func,
179 const int& offset, const int& size, uint32_t& pciData)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700180{
181 // PECI RdPCIConfig() currently only supports 4 byte reads, so adjust
182 // the offset and size to get the right data
183 static constexpr const int pciReadSize = 4;
184 int mod = offset % pciReadSize;
185 int pciOffset = offset - mod;
186 if (mod + size > pciReadSize)
187 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300188 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700189 }
190
191 std::array<uint8_t, pciReadSize> data;
192 uint8_t cc;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300193 int ret = PECI_CC_TIMEOUT;
Paul Fertserb08723d2022-12-16 11:49:08 +0000194 for (int index = 0; (index < 15) && (ret == PECI_CC_TIMEOUT); index++)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300195 {
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700196#ifdef USE_RDENDPOINTCFG
Patrick Williams39c664c2024-08-16 15:21:58 -0400197 ret = peci_RdEndPointConfigPci(
198 clientAddr, // CPU Address
199 0, // PCI Seg (use 0 for now)
200 bus, // PCI Bus
201 dev, // PCI Device
202 func, // PCI Function
203 pciOffset, // PCI Offset
204 pciReadSize, // PCI Read Size
205 data.data(), // PCI Read Data
206 &cc); // PECI Completion Code
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700207#else
Patrick Williams39c664c2024-08-16 15:21:58 -0400208 ret = peci_RdPCIConfig(
209 clientAddr, // CPU Address
210 bus, // PCI Bus
211 dev, // PCI Device
212 func, // PCI Function
213 pciOffset, // PCI Offset
214 data.data(), // PCI Read Data
215 &cc); // PECI Completion Code
Jason M. Bills3b1665a2021-06-11 13:35:04 -0700216#endif
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000217 if constexpr (peci_pcie::debug)
218 {
219 std::cerr << "Request: bus " << bus << " dev " << dev << " func "
220 << func << " pciOffset " << pciOffset << " ret: " << ret
221 << " cc: " << static_cast<int>(cc) << "\n";
222 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300223 }
Paul Fertser541637c2022-12-02 13:42:01 +0000224 if (ret != PECI_CC_SUCCESS)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700225 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300226 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700227 }
Paul Fertser541637c2022-12-02 13:42:01 +0000228 else if (cc != PECI_DEV_CC_SUCCESS)
229 {
230 return resCode::resSkip;
231 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700232
233 // Now build the requested data into a single number
234 pciData = 0;
235 for (int i = mod; i < mod + size; i++)
236 {
Jason M. Billse55832b2021-06-14 16:00:49 -0700237 pciData |= static_cast<uint32_t>(data[i]) << 8 * (i - mod);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700238 }
239
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300240 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700241}
242
Andrei Kartashev6f552032021-05-11 21:25:29 +0300243static resCode getStringFromData(const int& size, const uint32_t& data,
244 std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700245{
Jason M. Billsd1e40602019-05-09 11:43:51 -0700246 // And convert it to a string
247 std::stringstream dataStream;
248 dataStream << "0x" << std::hex << std::setfill('0') << std::setw(size * 2)
249 << data;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300250 res = dataStream.str();
251 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700252}
253
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300254static resCode getVendorName(const int& clientAddr, const int& bus,
255 const int& dev, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700256{
257 static constexpr const int vendorIDOffset = 0x00;
258 static constexpr const int vendorIDSize = 2;
259
260 // Get the header type register from function 0
261 uint32_t vendorID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300262 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, vendorIDOffset,
263 vendorIDSize, vendorID) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700264 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300265 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700266 }
267 // Get the vendor name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300268 res = pciVendors.try_emplace(vendorID, otherVendor).first->second;
269 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700270}
271
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300272static resCode getDeviceClass(const int& clientAddr, const int& bus,
273 const int& dev, const int& func, std::string& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700274{
275 static constexpr const int baseClassOffset = 0x0b;
276 static constexpr const int baseClassSize = 1;
277
278 // Get the Device Base Class
279 uint32_t baseClass = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300280 if (getDataFromPCIeConfig(clientAddr, bus, dev, func, baseClassOffset,
281 baseClassSize, baseClass) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700282 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300283 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700284 }
285 // Get the base class name or use Other if it doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300286 res = pciDeviceClasses.try_emplace(baseClass, otherClass).first->second;
287 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700288}
289
Patrick Williams39c664c2024-08-16 15:21:58 -0400290static resCode getCapReading(
291 const int& clientAddr, const int& bus, const int& dev, uint32_t& capReading,
292 const int compareCapID, const int offsetAddress, const int offsetLength)
Spencer Kubb5efe72021-09-02 16:11:14 +0800293{
294 resCode error;
295 uint32_t capAddress = 0;
296 uint32_t capabilityID;
297 uint32_t nextCapPointer = peci_pcie::pointToCapStruct;
298
299 do
300 {
301 // Get capability address
302 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, nextCapPointer,
303 1, capAddress);
304 if (error != resCode::resOk)
305 {
306 return error;
307 }
308 // Capability struct address is a pointer which point to next capability
309 // struct, so if capability struct address is 0 means it doesn't have
310 // next capability struct.
311 if (capAddress == 0)
312 {
313 return resCode::resSkip;
314 }
315 // Get capability ID
316 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0, capAddress, 1,
317 capabilityID);
318 if (error != resCode::resOk)
319 {
320 return error;
321 }
322 nextCapPointer = capAddress + peci_pcie::capPointerOffset;
323
Jason M. Billsc076bd72023-07-31 12:25:05 -0700324 } while (capabilityID != static_cast<uint32_t>(compareCapID));
Spencer Kubb5efe72021-09-02 16:11:14 +0800325 // Get capability reading.
326 error = getDataFromPCIeConfig(clientAddr, bus, dev, 0,
327 capAddress + offsetAddress, offsetLength,
328 capReading);
329 if (error != resCode::resOk)
330 {
331 return error;
332 }
333 return resCode::resOk;
334}
335
336static resCode getGenerationInUse(const int& clientAddr, const int& bus,
337 const int& dev, std::string& generationInUse)
338{
Willy Tu975faf72022-09-23 18:39:16 +0000339 static std::unordered_set<uint32_t> linkSpeedSkipMap;
Spencer Kubb5efe72021-09-02 16:11:14 +0800340 resCode error;
341 std::string res;
Spencer Kubb5efe72021-09-02 16:11:14 +0800342
343 // Capability ID 0x10(16) is PCI Express
344 constexpr int pcieCapID = 16;
345 constexpr int capLength = 2;
346 uint32_t linkStatus;
347
348 error = getCapReading(clientAddr, bus, dev, linkStatus, pcieCapID,
349 peci_pcie::linkStatusOffset, capLength);
350 if (error != resCode::resOk)
351 {
352 return error;
353 }
354
355 uint32_t linkSpeed = linkStatus & peci_pcie::maskOfCLS;
356
357 switch (linkSpeed)
358 {
359 case peci_pcie::pcieGen1:
360 generationInUse = "xyz.openbmc_project.Inventory.Item."
361 "PCIeSlot.Generations.Gen1";
362 error = resCode::resOk;
363 break;
364 case peci_pcie::pcieGen2:
365 generationInUse = "xyz.openbmc_project.Inventory.Item."
366 "PCIeSlot.Generations.Gen2";
367 error = resCode::resOk;
368 break;
369 case peci_pcie::pcieGen3:
370 generationInUse = "xyz.openbmc_project.Inventory.Item."
371 "PCIeSlot.Generations.Gen3";
372 error = resCode::resOk;
373 break;
374 case peci_pcie::pcieGen4:
375 generationInUse = "xyz.openbmc_project.Inventory.Item."
376 "PCIeSlot.Generations.Gen4";
377 error = resCode::resOk;
378 break;
379 case peci_pcie::pcieGen5:
380 generationInUse = "xyz.openbmc_project.Inventory.Item."
381 "PCIeSlot.Generations.Gen5";
382 error = resCode::resOk;
383 break;
384 default:
Willy Tu975faf72022-09-23 18:39:16 +0000385 if (!linkSpeedSkipMap.contains(linkSpeed))
386 {
387 std::cerr << "Link speed : " << linkSpeed
388 << " can not mapping to PCIe type list.\n";
389 linkSpeedSkipMap.emplace(linkSpeed);
390 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800391 error = resCode::resSkip;
392 }
393 return error;
394}
395
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300396static resCode isMultiFunction(const int& clientAddr, const int& bus,
397 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700398{
399 static constexpr const int headerTypeOffset = 0x0e;
400 static constexpr const int headerTypeSize = 1;
401 static constexpr const int multiFuncBit = 1 << 7;
402
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300403 res = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700404 // Get the header type register from function 0
405 uint32_t headerType = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300406 if (getDataFromPCIeConfig(clientAddr, bus, dev, 0, headerTypeOffset,
407 headerTypeSize, headerType) != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700408 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300409 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700410 }
411 // Check if it's a multifunction device
412 if (headerType & multiFuncBit)
413 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300414 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700415 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300416 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700417}
418
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300419static resCode pcieFunctionExists(const int& clientAddr, const int& bus,
420 const int& dev, const int& func, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700421{
422 constexpr const int pciIDOffset = 0;
423 constexpr const int pciIDSize = 4;
424 uint32_t pciID = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300425 res = false;
Paul Fertser541637c2022-12-02 13:42:01 +0000426
427 resCode error = getDataFromPCIeConfig(clientAddr, bus, dev, func,
428 pciIDOffset, pciIDSize, pciID);
429 if (error == resCode::resSkip)
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 }
Paul Fertser541637c2022-12-02 13:42:01 +0000433 else if (error == resCode::resErr)
434 {
435 return resCode::resErr;
436 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700437
438 // if VID and DID are all 0s or 1s, then the device doesn't exist
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300439 if (pciID != 0x00000000 && pciID != 0xFFFFFFFF)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700440 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300441 res = true;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700442 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300443 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700444}
445
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300446static resCode pcieDeviceExists(const int& clientAddr, const int& bus,
447 const int& dev, bool& res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700448{
449 // Check if this device exists by checking function 0
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300450 return pcieFunctionExists(clientAddr, bus, dev, 0, res);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700451}
452
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300453static resCode setPCIeProperty(const int& clientAddr, const int& bus,
454 const int& dev, const std::string& propertyName,
455 const std::string& propertyValue)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700456{
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500457 peci_pcie::PcieInterfaces pcieIfaces =
Jason M. Billsd1e40602019-05-09 11:43:51 -0700458 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
459
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500460 std::shared_ptr<sdbusplus::asio::dbus_interface> iface;
461 if (propertyName == "Manufacturer")
462 {
463 iface = pcieIfaces.assetIface;
464 }
465 else
466 {
467 iface = pcieIfaces.deviceIface;
468 }
469
Jason M. Billsd1e40602019-05-09 11:43:51 -0700470 if (iface->is_initialized())
471 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300472 if (!iface->set_property(propertyName, propertyValue))
473 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700474 }
475 else
476 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300477 if (!iface->register_property(propertyName, propertyValue))
478 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700479 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300480 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700481}
482
Patrick Williams39c664c2024-08-16 15:21:58 -0400483static void setDefaultPCIeFunctionProperties(
484 const int& clientAddr, const int& bus, const int& dev, const int& func)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700485{
486 // Set the function-specific properties
Andrei Kartashev6f552032021-05-11 21:25:29 +0300487 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700488 {
489 setPCIeProperty(clientAddr, bus, dev,
490 "Function" + std::to_string(func) + std::string(name),
491 std::string());
492 }
493}
494
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300495static resCode setPCIeFunctionProperties(const int& clientAddr, const int& bus,
496 const int& dev, const int& func)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700497{
Andrei Kartashev6f552032021-05-11 21:25:29 +0300498 uint32_t data = 0;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300499 std::string res;
Andrei Kartashev6f552032021-05-11 21:25:29 +0300500 resCode error;
501
502 for (const auto& [name, offset, size] : peci_pcie::pciConfigInfo)
503 {
504 if (offset < 0)
505 {
506 continue;
507 }
508
509 error = getDataFromPCIeConfig(clientAddr, bus, dev, func, offset, size,
510 data);
511 if (error != resCode::resOk)
512 {
513 return error;
514 }
515 getStringFromData(size, data, res);
516 setPCIeProperty(clientAddr, bus, dev,
517 "Function" + std::to_string(func) + std::string(name),
518 res);
519 }
520
Jason M. Billsd1e40602019-05-09 11:43:51 -0700521 // Set the function type always to physical for now
522 setPCIeProperty(clientAddr, bus, dev,
523 "Function" + std::to_string(func) +
524 std::string(peci_pcie::function::functionTypeName),
525 "Physical");
526
527 // Set the function Device Class
Andrei Kartashev6f552032021-05-11 21:25:29 +0300528 error = getDeviceClass(clientAddr, bus, dev, func, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300529 if (error != resCode::resOk)
530 {
531 return error;
532 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700533 setPCIeProperty(clientAddr, bus, dev,
534 "Function" + std::to_string(func) +
535 std::string(peci_pcie::function::deviceClassName),
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300536 res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300537 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700538}
539
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300540static resCode setPCIeDeviceProperties(const int& clientAddr, const int& bus,
541 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700542{
543 // Set the device manufacturer
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300544 std::string manuf;
545 resCode error = getVendorName(clientAddr, bus, dev, manuf);
546 if (error != resCode::resOk)
547 {
548 return error;
549 }
550 setPCIeProperty(clientAddr, bus, dev, "Manufacturer", manuf);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700551
552 // Set the device type
Patrick Williams42a9ac82023-05-10 07:51:22 -0500553 constexpr const char* deviceTypeName = "DeviceType";
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300554 bool multiFunc;
555 error = isMultiFunction(clientAddr, bus, dev, multiFunc);
556 if (error != resCode::resOk)
557 {
558 return error;
559 }
560 if (multiFunc)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700561 {
562 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "MultiFunction");
563 }
564 else
565 {
566 setPCIeProperty(clientAddr, bus, dev, deviceTypeName, "SingleFunction");
567 }
Spencer Kubb5efe72021-09-02 16:11:14 +0800568
569 // Set PCIe Generation
Patrick Williams42a9ac82023-05-10 07:51:22 -0500570 constexpr const char* generationInUseName = "GenerationInUse";
Spencer Kubb5efe72021-09-02 16:11:14 +0800571 std::string generationInUse;
572 error = getGenerationInUse(clientAddr, bus, dev, generationInUse);
573 if (error == resCode::resErr)
574 {
575 return error;
576 }
577 // "resSkip" status means it can't get the capability reading, such like
578 // this device is not PCI Express.
579 if (error == resCode::resSkip)
580 {
581 setPCIeProperty(clientAddr, bus, dev, generationInUseName, "");
582 return resCode::resOk;
583 }
584 setPCIeProperty(clientAddr, bus, dev, generationInUseName, generationInUse);
585
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300586 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700587}
588
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300589static resCode updatePCIeDevice(const int& clientAddr, const int& bus,
590 const int& dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700591{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300592 if (setPCIeDeviceProperties(clientAddr, bus, dev) != resCode::resOk)
593 {
594 return resCode::resErr;
595 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700596
Nidhin MS8b18f522023-06-28 10:25:06 +0530597 bool multiFunc = false;
598 resCode error = isMultiFunction(clientAddr, bus, dev, multiFunc);
599 if (error != resCode::resOk)
600 {
601 return error;
602 }
603 // Functions greater than 0 should only be accessed on multi-function
604 // devices
605 int maxPCIFunctions = multiFunc ? peci_pcie::maxPCIFunctions : 1;
606
Jason M. Billsd1e40602019-05-09 11:43:51 -0700607 // Walk through and populate the functions for this device
Nidhin MS8b18f522023-06-28 10:25:06 +0530608 for (int func = 0; func < maxPCIFunctions; func++)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700609 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300610 bool res;
611 resCode error = pcieFunctionExists(clientAddr, bus, dev, func, res);
612 if (error != resCode::resOk)
613 {
614 return error;
615 }
616 if (res)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700617 {
618 // Set the properties for this function
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300619 if (setPCIeFunctionProperties(clientAddr, bus, dev, func) !=
620 resCode::resOk)
621 {
622 return resCode::resErr;
623 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700624 }
625 else
626 {
627 // Set default properties for unused functions
628 setDefaultPCIeFunctionProperties(clientAddr, bus, dev, func);
629 }
630 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300631 return resCode::resOk;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700632}
633
634static void removePCIeDevice(sdbusplus::asio::object_server& objServer,
635 const int& clientAddr, const int& bus,
636 const int& dev)
637{
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500638 peci_pcie::PcieInterfaces ifaces =
Jason M. Billsd1e40602019-05-09 11:43:51 -0700639 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev];
640
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500641 objServer.remove_interface(ifaces.deviceIface);
642 objServer.remove_interface(ifaces.assetIface);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700643
644 peci_pcie::pcieDeviceDBusMap[clientAddr][bus].erase(dev);
645 if (peci_pcie::pcieDeviceDBusMap[clientAddr][bus].empty())
646 {
647 peci_pcie::pcieDeviceDBusMap[clientAddr].erase(bus);
648 }
649 if (peci_pcie::pcieDeviceDBusMap[clientAddr].empty())
650 {
651 peci_pcie::pcieDeviceDBusMap.erase(clientAddr);
652 }
653}
654
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300655static resCode addPCIeDevice(sdbusplus::asio::object_server& objServer,
656 const int& clientAddr, const int& cpu,
657 const int& bus, const int& dev)
658{
Patrick Williams39c664c2024-08-16 15:21:58 -0400659 std::string pathName =
660 std::string(peci_pcie::peciPCIePath) + "/S" + std::to_string(cpu) +
661 "B" + std::to_string(bus) + "D" + std::to_string(dev);
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500662 peci_pcie::PcieInterfaces ifaces;
663 ifaces.deviceIface =
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300664 objServer.add_interface(pathName, peci_pcie::peciPCIeDeviceInterface);
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500665 ifaces.assetIface =
666 objServer.add_interface(pathName, peci_pcie::peciPCIeAssetInterface);
667 peci_pcie::pcieDeviceDBusMap[clientAddr][bus][dev] = ifaces;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300668
669 // Update the properties for the new device
670 if (updatePCIeDevice(clientAddr, bus, dev) != resCode::resOk)
671 {
672 removePCIeDevice(objServer, clientAddr, bus, dev);
673 return resCode::resErr;
674 }
675
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500676 ifaces.deviceIface->initialize();
677 ifaces.assetIface->initialize();
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300678 return resCode::resOk;
679}
680
Jason M. Billsd1e40602019-05-09 11:43:51 -0700681static bool pcieDeviceInDBusMap(const int& clientAddr, const int& bus,
682 const int& dev)
683{
684 if (auto clientAddrIt = peci_pcie::pcieDeviceDBusMap.find(clientAddr);
685 clientAddrIt != peci_pcie::pcieDeviceDBusMap.end())
686 {
687 if (auto busIt = clientAddrIt->second.find(bus);
688 busIt != clientAddrIt->second.end())
689 {
690 if (auto devIt = busIt->second.find(dev);
691 devIt != busIt->second.end())
692 {
Lakshmi Yadlapati4fe704c2023-04-07 08:23:04 -0500693 if (devIt->second.deviceIface != nullptr ||
694 devIt->second.assetIface != nullptr)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700695 {
696 return true;
697 }
698 }
699 }
700 }
701 return false;
702}
703
Jason M. Billsc076bd72023-07-31 12:25:05 -0700704static resCode probePCIeDevice(sdbusplus::asio::object_server& objServer,
Andrei Kartashev8e966032021-07-02 20:04:30 +0300705 size_t addr, int cpu, int bus, int dev)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700706{
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300707 bool res;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300708 resCode error = pcieDeviceExists(addr, bus, dev, res);
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300709 if (error != resCode::resOk)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700710 {
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300711 return error;
Jason M. Bills5d049732019-10-25 15:55:15 -0700712 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300713 if (res)
Jason M. Bills5d049732019-10-25 15:55:15 -0700714 {
Andrei Kartashev8e966032021-07-02 20:04:30 +0300715 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700716 {
717 // This device is already in D-Bus, so update it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300718 if (updatePCIeDevice(addr, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300719 {
720 return resCode::resErr;
721 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700722 }
723 else
724 {
725 // This device is not in D-Bus, so add it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300726 if (addPCIeDevice(objServer, addr, cpu, bus, dev) != resCode::resOk)
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300727 {
728 return resCode::resErr;
729 }
Jason M. Billsd1e40602019-05-09 11:43:51 -0700730 }
731 }
732 else
733 {
734 // If PECI is not available, then stop scanning
735 if (!isPECIAvailable())
736 {
Paul Fertser541637c2022-12-02 13:42:01 +0000737 return resCode::resErr;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700738 }
739
Andrei Kartashev8e966032021-07-02 20:04:30 +0300740 if (pcieDeviceInDBusMap(addr, bus, dev))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700741 {
742 // This device is in D-Bus, so remove it
Andrei Kartashev8e966032021-07-02 20:04:30 +0300743 removePCIeDevice(objServer, addr, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700744 }
745 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300746 return resCode::resOk;
747}
748
Patrick Williams39c664c2024-08-16 15:21:58 -0400749static void scanNextPCIeDevice(
750 boost::asio::io_context& io, sdbusplus::asio::object_server& objServer,
751 std::vector<CPUInfo>& cpuInfo, int cpu, int bus, int dev);
Ed Tanous985d9d92023-03-01 10:35:33 -0800752static void scanPCIeDevice(boost::asio::io_context& io,
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300753 sdbusplus::asio::object_server& objServer,
754 std::vector<CPUInfo>& cpuInfo, int cpu, int bus,
755 int dev)
756{
Jason M. Billsc076bd72023-07-31 12:25:05 -0700757 if (cpu >= static_cast<int>(cpuInfo.size()))
Andrei Kartashev8e966032021-07-02 20:04:30 +0300758 {
759 std::cerr << "Request to scan CPU" << cpu
760 << " while CPU array has size " << cpuInfo.size() << "\n";
761 return;
762 }
763 auto& info = cpuInfo[cpu];
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300764 // Check if this is a CPU bus that we should skip
Andrei Kartashev8e966032021-07-02 20:04:30 +0300765 if (info.skipCpuBuses && info.cpuBusNums.count(bus))
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300766 {
767 std::cout << "Skipping CPU " << cpu << " Bus Number " << bus << "\n";
768 // Skip all the devices on this bus
769 dev = peci_pcie::maxPCIDevices;
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300770 }
Andrei Kartashev8e966032021-07-02 20:04:30 +0300771 else
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300772 {
Jason M. Billsc076bd72023-07-31 12:25:05 -0700773 if (probePCIeDevice(objServer, info.addr, cpu, bus, dev) !=
Andrei Kartashev8e966032021-07-02 20:04:30 +0300774 resCode::resOk)
775 {
776 std::cerr << "Failed to probe CPU " << cpu << " Bus " << bus
777 << " Device " << dev << "\n";
Paul Fertser541637c2022-12-02 13:42:01 +0000778 peci_pcie::abortScan = true;
Andrei Kartashev8e966032021-07-02 20:04:30 +0300779 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300780 }
781
Jason M. Bills5d049732019-10-25 15:55:15 -0700782 scanNextPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Andrei Kartashev8e966032021-07-02 20:04:30 +0300783 return;
Jason M. Bills5d049732019-10-25 15:55:15 -0700784}
Jason M. Billsd1e40602019-05-09 11:43:51 -0700785
Patrick Williams39c664c2024-08-16 15:21:58 -0400786static void scanNextPCIeDevice(
787 boost::asio::io_context& io, sdbusplus::asio::object_server& objServer,
788 std::vector<CPUInfo>& cpuInfo, int cpu, int bus, int dev)
Jason M. Bills5d049732019-10-25 15:55:15 -0700789{
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700790 if (peci_pcie::abortScan)
791 {
Paul Fertser07343142022-12-01 21:04:57 +0000792 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700793 std::cerr << "PCIe scan aborted\n";
794 return;
795 }
796
Jason M. Billsd1e40602019-05-09 11:43:51 -0700797 // PCIe Device scan completed, so move to the next device
798 if (++dev >= peci_pcie::maxPCIDevices)
799 {
800 // All devices scanned, so move to the next bus
801 dev = 0;
802 if (++bus >= peci_pcie::maxPCIBuses)
803 {
804 // All buses scanned, so move to the next CPU
805 bus = 0;
Jason M. Billsc076bd72023-07-31 12:25:05 -0700806 if (++cpu >= static_cast<int>(cpuInfo.size()))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700807 {
808 // All CPUs scanned, so we're done
Paul Fertser07343142022-12-01 21:04:57 +0000809 peci_pcie::scanInProgress = false;
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700810 std::cerr << "PCIe scan completed\n";
Jason M. Billsd1e40602019-05-09 11:43:51 -0700811 return;
812 }
813 }
814 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300815 boost::asio::post(io, [&io, &objServer, &cpuInfo, cpu, bus, dev]() mutable {
Jason M. Bills5d049732019-10-25 15:55:15 -0700816 scanPCIeDevice(io, objServer, cpuInfo, cpu, bus, dev);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700817 });
818}
819
Ed Tanous985d9d92023-03-01 10:35:33 -0800820static void startPCIeScan(boost::asio::io_context& io,
Paul Fertser07343142022-12-01 21:04:57 +0000821 sdbusplus::asio::object_server& objServer,
822 std::vector<CPUInfo>& cpuInfo)
823{
824 if (!peci_pcie::scanInProgress)
825 {
826 // get the PECI client address list
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000827 std::cerr << "Getting map\n";
Paul Fertser07343142022-12-01 21:04:57 +0000828 if (getCPUBusMap(cpuInfo) != resCode::resOk)
829 {
Paul Fertser541637c2022-12-02 13:42:01 +0000830 peci_pcie::abortScan = true;
Paul Fertser07343142022-12-01 21:04:57 +0000831 return;
832 }
833 std::cerr << "PCIe scan started\n";
834 // scan PCIe starting from CPU 0, Bus 0, Device 0
835 peci_pcie::scanInProgress = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000836 peci_pcie::abortScan = false;
Paul Fertser07343142022-12-01 21:04:57 +0000837 scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
838 }
839}
840
Patrick Williams39c664c2024-08-16 15:21:58 -0400841static void peciAvailableCheck(
842 boost::asio::steady_timer& peciWaitTimer, boost::asio::io_context& io,
843 sdbusplus::asio::object_server& objServer, std::vector<CPUInfo>& cpuInfo)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700844{
Jason M. Bills5d049732019-10-25 15:55:15 -0700845 static bool lastPECIState = false;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700846 bool peciAvailable = isPECIAvailable();
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000847 if constexpr (peci_pcie::debug)
848 {
849 std::cerr << "peciAvailableCheck " << peciAvailable << " "
850 << lastPECIState << " " << peci_pcie::abortScan << "\n";
851 }
Paul Fertser541637c2022-12-02 13:42:01 +0000852 if (peciAvailable && (!lastPECIState || peci_pcie::abortScan))
Jason M. Billsd1e40602019-05-09 11:43:51 -0700853 {
854 lastPECIState = true;
Paul Fertser541637c2022-12-02 13:42:01 +0000855 auto pcieTimeout = std::make_shared<boost::asio::steady_timer>(io);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700856 constexpr const int pcieWaitTime = 60;
Paul Fertser3b2afcb2022-12-16 12:17:15 +0000857 if constexpr (peci_pcie::debug)
858 {
859 std::cerr << "Scanning in 60 seconds\n";
860 }
Paul Fertser541637c2022-12-02 13:42:01 +0000861 pcieTimeout->expires_after(std::chrono::seconds(pcieWaitTime));
862 pcieTimeout->async_wait([&io, &objServer, &cpuInfo, pcieTimeout](
863 const boost::system::error_code& ec) {
864 if (ec)
865 {
866 // operation_aborted is expected if timer is canceled
867 // before completion.
868 if (ec != boost::asio::error::operation_aborted)
Jason M. Billsd1e40602019-05-09 11:43:51 -0700869 {
Paul Fertser541637c2022-12-02 13:42:01 +0000870 std::cerr << "PECI PCIe async_wait failed " << ec;
Jason M. Billsd1e40602019-05-09 11:43:51 -0700871 }
Paul Fertser541637c2022-12-02 13:42:01 +0000872 lastPECIState = false;
873 return;
874 }
875 startPCIeScan(io, objServer, cpuInfo);
876 });
Jason M. Billsd1e40602019-05-09 11:43:51 -0700877 }
878 else if (!peciAvailable && lastPECIState)
879 {
880 lastPECIState = false;
881 }
882
883 peciWaitTimer.expires_after(
884 std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300885 peciWaitTimer.async_wait([&peciWaitTimer, &io, &objServer,
886 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -0700887 if (ec)
888 {
889 // operation_aborted is expected if timer is canceled
890 // before completion.
891 if (ec != boost::asio::error::operation_aborted)
892 {
893 std::cerr << "PECI Available Check async_wait failed " << ec;
894 }
895 return;
896 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +0300897 peciAvailableCheck(peciWaitTimer, io, objServer, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -0700898 });
899}
900
Patrick Williams39c664c2024-08-16 15:21:58 -0400901static void waitForOSStandbyDelay(
902 boost::asio::io_context& io, sdbusplus::asio::object_server& objServer,
903 boost::asio::steady_timer& osStandbyTimer, std::vector<CPUInfo>& cpuInfo)
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700904{
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 Williams39c664c2024-08-16 15:21:58 -0400910 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
Patrick Williams39c664c2024-08-16 15:21:58 -0400924[[maybe_unused]] static void monitorOSStandby(
925 boost::asio::io_context& io,
926 std::shared_ptr<sdbusplus::asio::connection> conn,
927 sdbusplus::asio::object_server& objServer,
928 boost::asio::steady_timer& osStandbyTimer, std::vector<CPUInfo>& cpuInfo)
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700929{
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 Williams39c664c2024-08-16 15:21:58 -0400939 // 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 Williams39c664c2024-08-16 15:21:58 -0400945 for (const auto& [name, value] : propertiesChanged)
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700946 {
Patrick Williams39c664c2024-08-16 15:21:58 -0400947 if (name == "OperatingSystemState")
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700948 {
Patrick Williams39c664c2024-08-16 15:21:58 -0400949 const std::string* state = std::get_if<std::string>(&value);
950 if (state == nullptr)
951 {
952 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 ==
967 "xyz.openbmc_project.State.OperatingSystem."
968 "Status.OSStatus.Inactive"))
969 {
970 peci_pcie::abortScan = true;
971 osStandbyTimer.cancel();
972 }
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700973 }
974 }
Patrick Williams39c664c2024-08-16 15:21:58 -0400975 });
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700976
977 // Check if the OS state is already available
978 conn->async_method_call(
979 [&io, &objServer, &osStandbyTimer,
980 &cpuInfo](boost::system::error_code ec,
981 const std::variant<std::string>& property) {
Patrick Williams39c664c2024-08-16 15:21:58 -0400982 if (ec)
983 {
984 std::cerr << "error with OS state async_method_call\n";
985 return;
986 }
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700987
Patrick Williams39c664c2024-08-16 15:21:58 -0400988 const std::string* state = std::get_if<std::string>(&property);
989 if (state == nullptr)
990 {
991 std::cerr << "Unable to read OS state value\n";
992 return;
993 }
Jason M. Billsee6d80b2021-06-11 07:37:30 -0700994
Patrick Williams39c664c2024-08-16 15:21:58 -0400995 // If the OS state is in Standby, then BIOS is done and we can
996 // continue. Otherwise, we just wait for the match
997 // Note: Short version of OperatingSystemState value is deprecated
998 // and would be removed in the future
Andrei Kartashev328685e2021-12-27 17:24:18 +0300999
Patrick Williams39c664c2024-08-16 15:21:58 -04001000 if ((*state == "Standby") ||
1001 (*state == "xyz.openbmc_project.State.OperatingSystem.Status."
1002 "OSStatus.Standby"))
1003 {
1004 waitForOSStandbyDelay(io, objServer, osStandbyTimer, cpuInfo);
1005 }
1006 },
Potin Laif3f9deb2024-02-26 14:34:38 +08001007 "xyz.openbmc_project.State.Host0", "/xyz/openbmc_project/state/host0",
1008 "org.freedesktop.DBus.Properties", "Get",
1009 "xyz.openbmc_project.State.OperatingSystem.Status",
Jason M. Billsee6d80b2021-06-11 07:37:30 -07001010 "OperatingSystemState");
1011}
1012
Jason M. Bills3570b9e2023-07-31 12:26:30 -07001013int main(int /*argc*/, char* /*argv*/[])
Jason M. Billsd1e40602019-05-09 11:43:51 -07001014{
1015 // setup connection to dbus
Ed Tanous985d9d92023-03-01 10:35:33 -08001016 boost::asio::io_context io;
Jason M. Billsd1e40602019-05-09 11:43:51 -07001017 std::shared_ptr<sdbusplus::asio::connection> conn =
1018 std::make_shared<sdbusplus::asio::connection>(io);
1019
1020 // PECI PCIe Object
1021 conn->request_name(peci_pcie::peciPCIeObject);
1022 sdbusplus::asio::object_server server =
1023 sdbusplus::asio::object_server(conn);
1024
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001025 // CPU map
1026 std::vector<CPUInfo> cpuInfo;
1027
Jason M. Billsee6d80b2021-06-11 07:37:30 -07001028#ifdef WAIT_FOR_OS_STANDBY
1029 boost::asio::steady_timer osStandbyTimer(io);
1030 monitorOSStandby(io, conn, server, osStandbyTimer, cpuInfo);
1031#else
Jason M. Billsd1e40602019-05-09 11:43:51 -07001032 // Start the PECI check loop
1033 boost::asio::steady_timer peciWaitTimer(
1034 io, std::chrono::seconds(peci_pcie::peciCheckInterval));
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001035 peciWaitTimer.async_wait([&peciWaitTimer, &io, &server,
1036 &cpuInfo](const boost::system::error_code& ec) {
Jason M. Billsd1e40602019-05-09 11:43:51 -07001037 if (ec)
1038 {
1039 // operation_aborted is expected if timer is canceled
1040 // before completion.
1041 if (ec != boost::asio::error::operation_aborted)
1042 {
1043 std::cerr << "PECI Available Check async_wait failed " << ec;
1044 }
1045 return;
1046 }
Andrei Kartashevd570dfd2020-12-16 17:33:16 +03001047 peciAvailableCheck(peciWaitTimer, io, server, cpuInfo);
Jason M. Billsd1e40602019-05-09 11:43:51 -07001048 });
Jason M. Billsee6d80b2021-06-11 07:37:30 -07001049#endif
Jason M. Billsd1e40602019-05-09 11:43:51 -07001050
1051 io.run();
1052
1053 return 0;
1054}