Find P10 OCCs by looking in /dev
Find the exact OCCs present in the system by looking for the OCC devices
in /dev. They look like /dev/occ1, /dev/occ2, etc. The /dev/occ1 entry
will translate to Status object /org/open_power/control/occ0.
In order to handle the case where the application starts before all
devices show up, keep checking until at least 10 seconds have gone by
without a new device showing up (with at least one device present).
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I42289d55a6266d710b313af0a49070eeacccd725
diff --git a/occ_manager.cpp b/occ_manager.cpp
index 69f01ea..04276b9 100644
--- a/occ_manager.cpp
+++ b/occ_manager.cpp
@@ -6,6 +6,7 @@
#include "occ_dbus.hpp"
#include "utils.hpp"
+#include <chrono>
#include <cmath>
#include <experimental/filesystem>
#include <phosphor-logging/elog-errors.hpp>
@@ -50,12 +51,62 @@
void Manager::findAndCreateObjects()
{
+#ifndef POWER10
for (auto id = 0; id < MAX_CPUS; ++id)
{
// Create one occ per cpu
auto occ = std::string(OCC_NAME) + std::to_string(id);
createObjects(occ);
}
+#else
+ // Create the OCCs based on on the /dev/occX devices
+ auto occs = findOCCsInDev();
+
+ if (occs.empty() || (prevOCCSearch.size() != occs.size()))
+ {
+ // Something changed or no OCCs yet, try again in 10s.
+ // Note on the first pass prevOCCSearch will be empty,
+ // so there will be at least one delay to give things
+ // a chance to settle.
+ prevOCCSearch = occs;
+
+ using namespace std::literals::chrono_literals;
+ discoverTimer->restartOnce(10s);
+ }
+ else
+ {
+ discoverTimer.reset();
+
+ // createObjects requires OCC0 first.
+ std::sort(occs.begin(), occs.end());
+
+ for (auto id : occs)
+ {
+ createObjects(std::string(OCC_NAME) + std::to_string(id));
+ }
+ }
+#endif
+}
+
+std::vector<int> Manager::findOCCsInDev()
+{
+ std::vector<int> occs;
+ std::regex expr{R"(occ(\d+)$)"};
+
+ for (auto& file : fs::directory_iterator("/dev"))
+ {
+ std::smatch match;
+ std::string path{file.path().string()};
+ if (std::regex_search(path, match, expr))
+ {
+ auto num = std::stoi(match[1].str());
+
+ // /dev numbering starts at 1, ours starts at 0.
+ occs.push_back(num - 1);
+ }
+ }
+
+ return occs;
}
int Manager::cpuCreated(sdbusplus::message::message& msg)
diff --git a/occ_manager.hpp b/occ_manager.hpp
index e6e8cbb..140b14a 100644
--- a/occ_manager.hpp
+++ b/occ_manager.hpp
@@ -71,7 +71,13 @@
std::bind(std::mem_fn(&Manager::updateOCCActive), this,
std::placeholders::_1, std::placeholders::_2)))
#endif
-
+#ifdef POWER10
+ ,
+ discoverTimer(
+ std::make_unique<
+ sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>(
+ sdpEvent, std::bind(&Manager::findAndCreateObjects, this)))
+#endif
{
#ifdef I2C_OCC
// I2C OCC status objects are initialized directly
@@ -88,9 +94,7 @@
}
private:
- /** @brief Checks if the CPU inventory is present and if so, creates
- * the occ D-Bus objects. Else, registers a handler to be
- * called when inventory is created.
+ /** @brief Creates the OCC D-Bus objects.
*/
void findAndCreateObjects();
@@ -186,12 +190,34 @@
std::unique_ptr<pldm::Interface> pldmHandle = nullptr;
#endif
+#ifdef POWER10
+ /**
+ * @brief Timer used when discovering OCCs in /dev.
+ */
+ std::unique_ptr<
+ sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>>
+ discoverTimer;
+
+ /**
+ * @brief Used when discovering /dev/occ objects to know if
+ * any were added since the last check.
+ */
+ std::vector<int> prevOCCSearch;
+#endif
+
/**
* @brief Called when poll timer expires and forces a POLL command to the
* OCC. The poll timer will then be restarted.
* */
void pollerTimerExpired();
+ /**
+ * @brief Finds the OCC devices in /dev
+ *
+ * @return The IDs of the OCCs - 0, 1, etc.
+ */
+ std::vector<int> findOCCsInDev();
+
#ifdef READ_OCC_SENSORS
/**
* @brief Gets the occ sensor values.