Fix rescan logic, and rescan on power changes
Fix rescan by looking for available busses each time. Make
rescan non-blocking. Also don't add duplicates from a muxed
bus.
Change-Id: Ib86bbe7240d5142ebc81a4501656cce80f462d3f
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index 7272327..83b60e2 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -31,6 +31,7 @@
namespace fs = std::experimental::filesystem;
static constexpr bool DEBUG = false;
+static constexpr size_t SLEEP_SECONDS_AFTER_PGOOD = 5;
static size_t UNKNOWN_BUS_OBJECT_COUNT = 0;
const static constexpr char *BASEBOARD_FRU_LOCATION =
@@ -38,7 +39,7 @@
static constexpr std::array<const char *, 5> FRU_AREAS = {
"INTERNAL", "CHASSIS", "BOARD", "PRODUCT", "MULTIRECORD"};
-
+const static constexpr char *POWER_OBJECT_NAME = "/org/openbmc/control/power0";
using DeviceMap = boost::container::flat_map<int, std::vector<char>>;
using BusMap = boost::container::flat_map<int, std::shared_ptr<DeviceMap>>;
@@ -133,7 +134,7 @@
static BusMap FindI2CDevices(const std::vector<fs::path> &i2cBuses)
{
- static std::vector<std::future<void>> futures;
+ std::vector<std::future<void>> futures;
BusMap busMap;
for (auto &i2cBus : i2cBuses)
{
@@ -328,6 +329,12 @@
return true;
}
+static bool isMuxBus(size_t bus)
+{
+ return std::experimental::filesystem::exists(
+ "/sys/bus/i2c/devices/i2c-" + std::to_string(bus) + "/mux_device");
+}
+
void AddFruObjectToDbus(
std::shared_ptr<dbus::connection> dbusConn, std::vector<char> &device,
dbus::DbusObjectServer &objServer,
@@ -361,8 +368,21 @@
UNKNOWN_BUS_OBJECT_COUNT++;
}
- auto object =
- objServer.add_object("/xyz/openbmc_project/FruDevice/" + productName);
+ productName = "/xyz/openbmc_project/FruDevice/" + productName;
+
+ // avoid duplicates by checking to see if on a mux
+ if (bus > 0 && isMuxBus(bus))
+ {
+ for (auto const &busObj : dbusObjectMap)
+ {
+ if ((address == busObj.first.second) &&
+ (busObj.second->object_name == productName))
+ {
+ continue;
+ }
+ }
+ }
+ auto object = objServer.add_object(productName);
dbusObjectMap[std::pair<size_t, size_t>(bus, address)] = object;
auto iface = std::make_shared<dbus::DbusInterface>(
@@ -403,6 +423,48 @@
return true;
}
+void rescanBusses(boost::container::flat_map<std::pair<size_t, size_t>,
+ std::shared_ptr<dbus::DbusObject>>
+ &dbusObjectMap,
+ std::shared_ptr<dbus::connection> systemBus,
+ dbus::DbusObjectServer &objServer)
+{
+ auto devDir = fs::path("/dev/");
+ auto matchString = std::string("i2c*");
+ std::vector<fs::path> i2cBuses;
+
+ if (!find_files(devDir, matchString, i2cBuses, 0))
+ {
+ std::cerr << "unable to find i2c devices\n";
+ return;
+ }
+ BusMap busMap = FindI2CDevices(i2cBuses);
+
+ for (auto &busObj : dbusObjectMap)
+ {
+ objServer.remove_object(busObj.second);
+ }
+
+ dbusObjectMap.clear();
+ UNKNOWN_BUS_OBJECT_COUNT = 0;
+
+ for (auto &devicemap : busMap)
+ {
+ for (auto &device : *devicemap.second)
+ {
+ AddFruObjectToDbus(systemBus, device.second, objServer,
+ dbusObjectMap, devicemap.first, device.first);
+ }
+ }
+ // todo, get this from a more sensable place
+ std::vector<char> baseboardFru;
+ if (readBaseboardFru(baseboardFru))
+ {
+ AddFruObjectToDbus(systemBus, baseboardFru, objServer, dbusObjectMap,
+ -1, -1);
+ }
+}
+
int main(int argc, char **argv)
{
auto devDir = fs::path("/dev/");
@@ -427,21 +489,7 @@
std::shared_ptr<dbus::DbusObject>>
dbusObjectMap;
- for (auto &devicemap : busMap)
- {
- for (auto &device : *devicemap.second)
- {
- AddFruObjectToDbus(systemBus, device.second, objServer,
- dbusObjectMap, devicemap.first, device.first);
- }
- }
-
- std::vector<char> baseboardFru;
- if (readBaseboardFru(baseboardFru))
- {
- AddFruObjectToDbus(systemBus, baseboardFru, objServer, dbusObjectMap,
- -1, -1);
- }
+ rescanBusses(dbusObjectMap, systemBus, objServer);
auto object = std::make_shared<dbus::DbusObject>(
systemBus, "/xyz/openbmc_project/FruDevice");
@@ -450,30 +498,54 @@
"xyz.openbmc_project.FruDeviceManager", systemBus);
object->register_interface(iface);
+ std::atomic_bool threadRunning(false);
+ std::future<void> future;
+
iface->register_method("ReScan", [&]() {
- busMap = FindI2CDevices(i2cBuses);
-
- for (auto &busObj : dbusObjectMap)
+ if (!threadRunning)
{
- objServer.remove_object(busObj.second);
+ threadRunning = true;
+ future = std::async(std::launch::async, [&] {
+ rescanBusses(dbusObjectMap, systemBus, objServer);
+ threadRunning = false;
+ });
}
- dbusObjectMap.clear();
- UNKNOWN_BUS_OBJECT_COUNT = 0;
-
- for (auto &devicemap : busMap)
- {
- for (auto &device : *devicemap.second)
- {
- AddFruObjectToDbus(systemBus, device.second, objServer,
- dbusObjectMap, devicemap.first,
- device.first);
- }
- }
-
return std::tuple<>(); // this is a bug in boost-dbus, needs some sort
// of return
});
+ dbus::match powerChange(systemBus,
+ "type='signal',path_namespace='" +
+ std::string(POWER_OBJECT_NAME) + "'");
+
+ dbus::filter filter(systemBus, [](dbus::message &m) {
+ auto member = m.get_member();
+ return member == "PropertiesChanged";
+ });
+ std::function<void(boost::system::error_code, dbus::message)> eventHandler =
+ [&](boost::system::error_code ec, dbus::message s) {
+ boost::container::flat_map<std::string, dbus::dbus_variant> values;
+ std::string objectName;
+ s.unpack(objectName, values);
+ auto findPgood = values.find("pgood");
+ if (findPgood != values.end())
+ {
+ if (!threadRunning)
+ {
+ threadRunning = true;
+ future = std::async(std::launch::async, [&] {
+ std::this_thread::sleep_for(
+ std::chrono::seconds(SLEEP_SECONDS_AFTER_PGOOD));
+ rescanBusses(dbusObjectMap, systemBus, objServer);
+ threadRunning = false;
+ });
+ }
+ }
+ filter.async_dispatch(eventHandler);
+
+ };
+ filter.async_dispatch(eventHandler);
+
io.run();
return 0;
}