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);
         });
 }