diff options
author | Lei YU <mine260309@gmail.com> | 2017-07-13 17:02:23 +0800 |
---|---|---|
committer | Lei YU <mine260309@gmail.com> | 2017-08-28 10:31:42 +0800 |
commit | 0ab90ca75b825db8e2427ea62ea3ee212c9accbb (patch) | |
tree | 6d7934495cf7233f54f5bd882469056c4f700142 | |
parent | 3ace7576176afed9196fb308c766de6b1252d3ea (diff) | |
download | openpower-occ-control-0ab90ca75b825db8e2427ea62ea3ee212c9accbb.tar.gz openpower-occ-control-0ab90ca75b825db8e2427ea62ea3ee212c9accbb.zip |
Add I2C OCC support for P8 systems
P8 system uses I2C OCC and it uses different driver for occ-hwmon.
Add `--enable-i2c-occ` configure option to enable the support.
It searches i2c device names in sysfs to get all occ-hwmon devices and
use the i2c device name to bind/unbind the driver.
The occ control object path for I2C OCC hwmon becomes something like
/org/open_power/control/3_0050, where 3_0050 is the i2c address.
Change-Id: I8b9d8d4429c563528dc88fb2679b265c53d7a2d5
Signed-off-by: Lei YU <mine260309@gmail.com>
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.ac | 28 | ||||
-rw-r--r-- | i2c_occ.cpp | 73 | ||||
-rw-r--r-- | i2c_occ.hpp | 69 | ||||
-rw-r--r-- | occ_device.hpp | 6 | ||||
-rw-r--r-- | occ_manager.hpp | 31 | ||||
-rw-r--r-- | occ_status.hpp | 6 | ||||
-rw-r--r-- | test/Makefile.am | 1 |
8 files changed, 211 insertions, 4 deletions
diff --git a/Makefile.am b/Makefile.am index aecbebb..d71d6e5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,6 +18,7 @@ openpower_occ_control_SOURCES = \ powercap.cpp \ org/open_power/OCC/Device/error.cpp \ occ_finder.cpp \ + i2c_occ.cpp \ utils.cpp BUILT_SOURCES = org/open_power/OCC/Device/error.hpp \ diff --git a/configure.ac b/configure.ac index 254cc77..b121f55 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,17 @@ AS_IF([test "x$SDBUSPLUSPLUS" == "x"], AC_MSG_ERROR([Cannot find sdbus++])) AX_CXX_COMPILE_STDCXX_14([noext]) AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS]) +AC_ARG_ENABLE([i2c-occ], + AS_HELP_STRING([--enable-i2c-occ], [Enable I2C OCC support]) +) +AS_IF([test "x$enable_i2c_occ" == "xyes"], + AC_MSG_NOTICE([Enabling I2C OCC]) + [ + cpp_flags="-DI2C_OCC" + ] + AC_SUBST([CPPFLAGS], [$cpp_flags]) +) + AC_ARG_VAR(OCC_CONTROL_BUSNAME, [The Dbus busname to own]) AS_IF([test "x$OCC_CONTROL_BUSNAME" == "x"], [OCC_CONTROL_BUSNAME="org.open_power.OCC.Control"]) AC_DEFINE_UNQUOTED([OCC_CONTROL_BUSNAME], ["$OCC_CONTROL_BUSNAME"], [The DBus busname to own]) @@ -86,12 +97,21 @@ AS_IF([test "x$OCC_MASTER_NAME" == "x"], [OCC_MASTER_NAME="occ1-dev0"]) AC_DEFINE_UNQUOTED([OCC_MASTER_NAME], ["$OCC_MASTER_NAME"], [The OCC master object name]) AC_ARG_VAR(OCC_HWMON_PATH, [The OCC hwmon path]) -AS_IF([test "x$OCC_HWMON_PATH" == "x"], [OCC_HWMON_PATH="/sys/bus/platform/drivers/occ-hwmon/"]) -AC_DEFINE_UNQUOTED([OCC_HWMON_PATH], ["$OCC_HWMON_PATH"], [The OCC hwmon path]) - AC_ARG_VAR(DEV_PATH, [The device path]) -AS_IF([test "x$DEV_PATH" == "x"], [DEV_PATH="/sys/bus/platform/devices/"]) +AC_ARG_VAR(I2C_OCC_DEVICE_NAME, [The device name of i2c occ hwmon]) +AS_IF([test "x$enable_i2c_occ" == "xyes"], + # If enable_2c_occ is defined, define occ hwmon path for I2C and its driver's name + AS_IF([test "x$OCC_HWMON_PATH" == "x"], [OCC_HWMON_PATH="/sys/bus/i2c/drivers/occ-hwmon/"]) + AS_IF([test "x$DEV_PATH" == "x"], [DEV_PATH="/sys/bus/i2c/devices"]) + AS_IF([test "x$I2C_OCC_DEVICE_NAME" == "x"], [I2C_OCC_DEVICE_NAME="p8-occ-hwmon"]), + + # Else, define occ hwmon path for FSI + AS_IF([test "x$OCC_HWMON_PATH" == "x"], [OCC_HWMON_PATH="/sys/bus/platform/drivers/occ-hwmon/"]) + AS_IF([test "x$DEV_PATH" == "x"], [DEV_PATH="/sys/bus/platform/devices/"]), +) +AC_DEFINE_UNQUOTED([OCC_HWMON_PATH], ["$OCC_HWMON_PATH"], [The OCC hwmon path]) AC_DEFINE_UNQUOTED([DEV_PATH], ["$DEV_PATH"], [The device path]) +AC_DEFINE_UNQUOTED([I2C_OCC_DEVICE_NAME], ["$I2C_OCC_DEVICE_NAME"], [The device name of i2c occ hwmon]) AC_ARG_VAR(FSI_SCAN_FILE, [The File to write for initiating FSI rescan]) AS_IF([test "x$FSI_SCAN_FILE" == "x"], [FSI_SCAN_FILE="/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/00:00:00:0a/fsi1/rescan"]) diff --git a/i2c_occ.cpp b/i2c_occ.cpp new file mode 100644 index 0000000..ffbb844 --- /dev/null +++ b/i2c_occ.cpp @@ -0,0 +1,73 @@ +#include <algorithm> +#include <fstream> + +#include "config.h" +#include "i2c_occ.hpp" + +#ifdef I2C_OCC + +namespace i2c_occ +{ + +namespace fs = std::experimental::filesystem; + +// The device name's length, e.g. "p8-occ-hwmon" +constexpr auto DEVICE_NAME_LENGTH = 12; + +// static assert to make sure the i2c occ device name is expected +static_assert(sizeof(I2C_OCC_DEVICE_NAME) -1 == DEVICE_NAME_LENGTH); + +std::string getFileContent(const fs::path& f) +{ + std::string ret(DEVICE_NAME_LENGTH, 0); + std::ifstream ifs(f.c_str(), std::ios::binary); + if (ifs.is_open()) + { + ifs.read(&ret[0], DEVICE_NAME_LENGTH); + ret.resize(ifs.gcount()); + } + return ret; +} + +std::vector<std::string> getOccHwmonDevices(const char* path) +{ + std::vector<std::string> result{}; + + if (fs::is_directory(path)) + { + for (auto & p : fs::directory_iterator(path)) + { + // Check if a device's name is "p8-occ-hwmon" + auto f = p / "name"; + auto str = getFileContent(f); + if (str == I2C_OCC_DEVICE_NAME) + { + result.emplace_back(p.path().filename()); + } + } + std::sort(result.begin(), result.end()); + } + return result; +} + +void i2cToDbus(std::string& path) +{ + std::replace(path.begin(), path.end(), '-', '_'); +} + +void dbusToI2c(std::string& path) +{ + std::replace(path.begin(), path.end(), '_', '-'); +} + +std::string getI2cDeviceName(const std::string& dbusPath) +{ + auto name = fs::path(dbusPath).filename().string(); + dbusToI2c(name); + return name; +} + +} // namespace i2c_occ + +#endif + diff --git a/i2c_occ.hpp b/i2c_occ.hpp new file mode 100644 index 0000000..31b6721 --- /dev/null +++ b/i2c_occ.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include <experimental/filesystem> +#include <vector> + +#ifdef I2C_OCC + +namespace i2c_occ +{ + +namespace fs = std::experimental::filesystem; + +/** @brief Get file content + * + * Get at most NAME_LENGTH bytes of content from file. If the file is smaller + * than NAME_LENGTH bytes, return the valid parts. + * + * @param[in] f - The path of file + * + * @return The string of file content + */ +std::string getFileContent(const fs::path& f); + +/** @brief Find all devices of occ hwmon + * + * It iterates in path, finds all occ hwmon devices + * + * E.g. If "path/3-0050/name" exists and its content is "p8-occ-hwmon", + * "3-0050" is returned. + * + * @param[in] path - The path to search + * + * @return A vector of strings containing the occ hwmon device path + */ +std::vector<std::string> getOccHwmonDevices(const char* path); + +/** @brief Convert i2c name to DBus path + * + * It converts '-' to '_' so that it becomes a valid DBus path. + * E.g. 3-0050 converts to 3_0050 + * + * @param[in,out] path - The i2c name to convert + */ +void i2cToDbus(std::string& name); + +/** @brief Convert DBus path to i2c name + * + * It converts '_' to '_' so that it becomes a valid i2c name + * E.g. 3_0050 converts to 3-0050 + * + * @param[in,out] path - The DBus path to convert + */ +void dbusToI2c(std::string& path); + +/** @brief Get i2c name from full DBus path + * + * It extract the i2c name from the full DBus path. + * E.g. /org/open_power/control/3_0050 returns "3-0050" + * + * @param[in] dbusPath - The full DBus path + * + * @return The i2c name + */ +std::string getI2cDeviceName(const std::string& dbusPath); + +} // namespace i2c_occ + +#endif + diff --git a/occ_device.hpp b/occ_device.hpp index 6538597..a2b4e85 100644 --- a/occ_device.hpp +++ b/occ_device.hpp @@ -5,6 +5,8 @@ #include "occ_events.hpp" #include "occ_errors.hpp" #include "config.h" + + namespace open_power { namespace occ @@ -34,7 +36,11 @@ class Device Device(EventPtr& event, const std::string& name, std::function<void()> callBack = nullptr) : +#ifdef I2C_OCC + config(name), +#else config(name + '-' + "dev0"), +#endif errorFile(fs::path(config) / "occ_error"), error(event, errorFile, callBack) { diff --git a/occ_manager.hpp b/occ_manager.hpp index e79ac3c..7bb1042 100644 --- a/occ_manager.hpp +++ b/occ_manager.hpp @@ -12,6 +12,7 @@ #include "occ_status.hpp" #include "occ_finder.hpp" #include "config.h" +#include "i2c_occ.hpp" namespace sdbusRule = sdbusplus::bus::match::rules; namespace open_power @@ -43,6 +44,10 @@ struct Manager bus(bus), event(event) { +#ifdef I2C_OCC + // I2C OCC status objects are initialized directly + initStatusObjects(); +#else // Check if CPU inventory exists already. auto occs = open_power::occ::finder::get(bus); if (occs.empty()) @@ -67,6 +72,7 @@ struct Manager createObjects(occ); } } +#endif } private: @@ -187,6 +193,31 @@ struct Manager /** @brief Number of OCCs that are bound */ uint8_t activeCount = 0; + +#ifdef I2C_OCC + /** @brief Init Status objects for I2C OCC devices + * + * It iterates in /sys/bus/i2c/devices, finds all occ hwmon devices + * and creates status objects. + */ + void initStatusObjects() + { + // Make sure we have a valid path string + static_assert(sizeof(DEV_PATH) != 0); + + auto deviceNames = i2c_occ::getOccHwmonDevices(DEV_PATH); + for (auto& name : deviceNames) + { + i2c_occ::i2cToDbus(name); + auto path = fs::path(OCC_CONTROL_ROOT) / name; + statusObjects.emplace_back( + std::make_unique<Status>( + bus, + event, + path.c_str())); + } + } +#endif }; } // namespace occ diff --git a/occ_status.hpp b/occ_status.hpp index 2e12806..23b2080 100644 --- a/occ_status.hpp +++ b/occ_status.hpp @@ -7,6 +7,8 @@ #include <org/open_power/Control/Host/server.hpp> #include "occ_events.hpp" #include "occ_device.hpp" +#include "i2c_occ.hpp" + namespace open_power { namespace occ @@ -59,7 +61,11 @@ class Status : public Interface callBack(callBack), instance(((this->path.back() - '0'))), device(event, +#ifdef I2C_OCC + i2c_occ::getI2cDeviceName(path), +#else name + std::to_string(instance + 1), +#endif std::bind(&Status::deviceErrorHandler, this)), hostControlSignal( bus, diff --git a/test/Makefile.am b/test/Makefile.am index d644de8..cd879f5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -20,5 +20,6 @@ utest_LDADD = $(top_builddir)/powercap.o \ $(top_builddir)/occ_status.o \ $(top_builddir)/occ_device.o \ $(top_builddir)/occ_errors.o \ + $(top_builddir)/i2c_occ.o \ $(top_builddir)/utils.o \ $(top_builddir)/org/open_power/OCC/Device/error.o |