Guard against concurrent scan
The current code checks PECI availability every ten seconds and if it
becomes available after being unavailable starts a scan. In addition to
that the scan can be initiated by the code monitoring OS state, but this
is disabled by default by a compile time option.
This becomes problematic when the host OS is mostly idle and thus lets
the CPUs enter low-power states. The code that requests the PCIe data
takes that into account and does up to 5 polls in case of a timeout.
However the PECI availability code fails right away and on the next
iteration (when it doesn't get a timeout) starts the scan again, despite
the one already running. This leads not only to both scans proceeding
slowly but also to incorrect results due to a mix up of the results.
Tested: with a host fully booted to an idle GNU/Linux system the daemon
now provides correct results every time (albeit much slower compared to
a state when the host is staying in UEFI configuration menu or EFI
Shell). The test was performed on a two-socket Tioga Pass server with
Xeon Scalable 1st generation CPUs.
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Change-Id: I34a01c15853dcadd5566d49d8df3b187bda6ae9f
diff --git a/src/peci_pcie.cpp b/src/peci_pcie.cpp
index 34fe1fc..312e339 100644
--- a/src/peci_pcie.cpp
+++ b/src/peci_pcie.cpp
@@ -41,6 +41,7 @@
pcieDeviceDBusMap;
static bool abortScan;
+static bool scanInProgress;
namespace function
{
@@ -735,6 +736,7 @@
{
if (peci_pcie::abortScan)
{
+ peci_pcie::scanInProgress = false;
std::cerr << "PCIe scan aborted\n";
return;
}
@@ -751,6 +753,7 @@
if (++cpu >= cpuInfo.size())
{
// All CPUs scanned, so we're done
+ peci_pcie::scanInProgress = false;
std::cerr << "PCIe scan completed\n";
return;
}
@@ -761,6 +764,24 @@
});
}
+static void startPCIeScan(boost::asio::io_service& io,
+ sdbusplus::asio::object_server& objServer,
+ std::vector<CPUInfo>& cpuInfo)
+{
+ if (!peci_pcie::scanInProgress)
+ {
+ // get the PECI client address list
+ if (getCPUBusMap(cpuInfo) != resCode::resOk)
+ {
+ return;
+ }
+ std::cerr << "PCIe scan started\n";
+ // scan PCIe starting from CPU 0, Bus 0, Device 0
+ peci_pcie::scanInProgress = true;
+ scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
+ }
+}
+
static void peciAvailableCheck(boost::asio::steady_timer& peciWaitTimer,
boost::asio::io_service& io,
sdbusplus::asio::object_server& objServer,
@@ -787,15 +808,7 @@
lastPECIState = false;
return;
}
- // get the PECI client address list
- if (getCPUBusMap(cpuInfo) != resCode::resOk)
- {
- lastPECIState = false;
- return;
- }
- // scan PCIe starting from CPU 0, Bus 0, Device 0
- std::cerr << "PCIe scan started\n";
- scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
+ startPCIeScan(io, objServer, cpuInfo);
});
}
else if (!peciAvailable && lastPECIState)
@@ -841,14 +854,7 @@
<< ": " << ec.message() << "\n";
return;
}
- // get the PECI client address list
- if (getCPUBusMap(cpuInfo) != resCode::resOk)
- {
- return;
- }
- // scan PCIe starting from CPU 0, Bus 0, Device 0
- std::cerr << "PCIe scan started\n";
- scanPCIeDevice(io, objServer, cpuInfo, 0, 0, 0);
+ startPCIeScan(io, objServer, cpuInfo);
});
}