Add HSBP Manager Daemon
This is the initial commit for the hsbp-manager
daemon. Currently it reads a json configuration
and detects whether the cpld is available. More
feaures will be added in small patches.
Tested:
busctl introspect --no-pager xyz.openbmc_project.HsbpManager /xyz/openbmc_project/inventory/item/hsbp/J85894_HSBP_1
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.Peer interface - - -
.GetMachineId method - s -
.Ping method - - -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -
xyz.openbmc_project.Inventory.Item interface - - -
.Present property b true emits-change
.PrettyName property s "J85894 HSBP 1" emits-change
Change-Id: Ibbce272e045f8643af74b778f273168442623919
Signed-off-by: Feist, James <james.feist@linux.intel.com>
diff --git a/hsbp-manager/src/hsbp_manager.cpp b/hsbp-manager/src/hsbp_manager.cpp
new file mode 100644
index 0000000..110d32d
--- /dev/null
+++ b/hsbp-manager/src/hsbp_manager.cpp
@@ -0,0 +1,201 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include "utils.hpp"
+
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/asio/steady_timer.hpp>
+#include <iostream>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <string>
+
+extern "C" {
+#include <i2c/smbus.h>
+#include <linux/i2c-dev.h>
+}
+
+constexpr const char* configType =
+ "xyz.openbmc_project.Configuration.Intel_HSBP_CPLD";
+
+boost::asio::io_context io;
+auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+sdbusplus::asio::object_server objServer(conn);
+
+struct Backplane
+{
+
+ Backplane(size_t busIn, size_t addressIn, const std::string& nameIn) :
+ bus(busIn), address(addressIn), name(nameIn)
+ {
+ }
+
+ void run()
+ {
+ file = open(("/dev/i2c-" + std::to_string(bus)).c_str(), O_RDWR);
+ if (file < 0)
+ {
+ std::cerr << "unable to open bus " << bus << "\n";
+ return;
+ }
+
+ if (ioctl(file, I2C_SLAVE_FORCE, address) < 0)
+ {
+ std::cerr << "unable to set address to " << address << "\n";
+ return;
+ }
+
+ hsbpItemIface = objServer.add_interface(
+ "/xyz/openbmc_project/inventory/item/hsbp/" +
+ boost::replace_all_copy(name, " ", "_"),
+ inventory::interface);
+ hsbpItemIface->register_property("Present", present(true));
+ hsbpItemIface->register_property("PrettyName", name);
+ hsbpItemIface->initialize();
+
+ if (!present())
+ {
+ // backplane isn't there
+ return;
+ }
+ }
+
+ bool present(bool update = false)
+ {
+ static bool present = false;
+ if (update)
+ {
+ present = i2c_smbus_read_byte(file) >= 0;
+ }
+ return present;
+ }
+ ~Backplane()
+ {
+ objServer.remove_interface(hsbpItemIface);
+ if (file >= 0)
+ {
+ close(file);
+ }
+ }
+
+ size_t bus;
+ size_t address;
+ int file = -1;
+ std::string name;
+ std::string type;
+
+ std::shared_ptr<sdbusplus::asio::dbus_interface> hsbpItemIface;
+ std::vector<std::shared_ptr<sdbusplus::asio::dbus_interface>>
+ driveItemIfaces;
+};
+
+std::unordered_map<std::string, Backplane> backplanes;
+
+void populate()
+{
+ conn->async_method_call(
+ [](const boost::system::error_code ec, const GetSubTreeType& subtree) {
+ if (ec)
+ {
+ std::cerr << "Error contacting mapper " << ec.message() << "\n";
+ return;
+ }
+ for (const auto& [path, objDict] : subtree)
+ {
+ if (objDict.empty())
+ {
+ continue;
+ }
+
+ const std::string& owner = objDict.begin()->first;
+ conn->async_method_call(
+ [path](const boost::system::error_code ec2,
+ const boost::container::flat_map<
+ std::string, BasicVariantType>& resp) {
+ if (ec2)
+ {
+ std::cerr << "Error Getting Config "
+ << ec2.message() << "\n";
+ return;
+ }
+ backplanes.clear();
+ std::optional<size_t> bus;
+ std::optional<size_t> address;
+ std::optional<std::string> name;
+ for (const auto& [key, value] : resp)
+ {
+ if (key == "Bus")
+ {
+ bus = std::get<uint64_t>(value);
+ }
+ else if (key == "Address")
+ {
+ address = std::get<uint64_t>(value);
+ }
+ else if (key == "Name")
+ {
+ name = std::get<std::string>(value);
+ }
+ }
+ if (!bus || !address || !name)
+ {
+ std::cerr << "Illegal configuration at " << path
+ << "\n";
+ return;
+ }
+ const auto& [backplane, status] = backplanes.emplace(
+ *name, Backplane(*bus, *address, *name));
+ backplane->second.run();
+ },
+ owner, path, "org.freedesktop.DBus.Properties", "GetAll",
+ configType);
+ }
+ },
+ mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/",
+ 0, std::array<const char*, 1>{configType});
+}
+
+int main()
+{
+ boost::asio::steady_timer callbackTimer(io);
+
+ conn->request_name("xyz.openbmc_project.HsbpManager");
+
+ sdbusplus::bus::match::match match(
+ *conn,
+ "type='signal',member='PropertiesChanged',arg0='" +
+ std::string(configType) + "'",
+ [&callbackTimer](sdbusplus::message::message&) {
+ callbackTimer.expires_after(std::chrono::seconds(2));
+ callbackTimer.async_wait([](const boost::system::error_code ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ // timer was restarted
+ return;
+ }
+ else if (ec)
+ {
+ std::cerr << "Timer error" << ec.message() << "\n";
+ return;
+ }
+ populate();
+ });
+ });
+
+ io.post([]() { populate(); });
+ io.run();
+}