#pragma once #include "config.h" #include "occ_errors.hpp" #include "occ_events.hpp" #include "occ_presence.hpp" #include #include #include namespace open_power { namespace occ { class Manager; class Status; namespace fs = std::experimental::filesystem; using namespace sdbusplus::org::open_power::OCC::Device::Error; /** @class Device * @brief Binds and unbinds the OCC driver upon request */ class Device { public: Device() = delete; ~Device() = default; Device(const Device&) = delete; Device& operator=(const Device&) = delete; Device(Device&&) = default; Device& operator=(Device&&) = default; /** @brief Constructs the Device object * * @param[in] event - Unique ptr reference to sd_event * @param[in] path - Path to the OCC instance * @param[in] manager - OCC manager instance * @param[in] callback - Optional callback on errors */ Device(EventPtr& event, const fs::path& path, const Manager& manager, Status& status, std::function callBack = nullptr) : config(getPathBack(path)), devPath(path), statusObject(status), error(event, path / "occ_error", callBack), presence(event, path / "occs_present", manager, callBack), throttleProcTemp( event, path / "occ_dvfs_overtemp", std::bind(std::mem_fn(&Device::throttleProcTempCallback), this, std::placeholders::_1)), throttleProcPower( event, path / "occ_dvfs_power", std::bind(std::mem_fn(&Device::throttleProcPowerCallback), this, std::placeholders::_1)), throttleMemTemp(event, path / "occ_mem_throttle", std::bind(std::mem_fn(&Device::throttleMemTempCallback), this, std::placeholders::_1)) { // Nothing to do here } /** @brief Binds device to the OCC driver */ inline void bind() { // Bind the device return write(bindPath, config); } /** @brief Un-binds device from the OCC driver */ inline void unBind() { // Unbind the device return write(unBindPath, config); } /** @brief Returns if device is already bound. * * On device bind, a soft link by the name $config * gets created in OCC_HWMON_PATH and gets removed * on unbind * * @return true if bound, else false */ inline bool bound() const { return fs::exists(OCC_HWMON_PATH + config); } /** @brief Starts to monitor for errors * * @param[in] poll - Indicates whether or not the error file should * actually be polled for changes. Disabling polling is * necessary for error files that don't support the poll * file operation. */ inline void addErrorWatch(bool poll = true) { try { throttleProcTemp.addWatch(poll); } catch (const OpenFailure& e) { // try the old kernel version throttleProcTemp.setFile(devPath / "occ_dvfs_ot"); throttleProcTemp.addWatch(poll); } throttleProcPower.addWatch(poll); throttleMemTemp.addWatch(poll); error.addWatch(poll); } /** @brief stops monitoring for errors */ inline void removeErrorWatch() { // we can always safely remove watch even if we don't add it presence.removeWatch(); error.removeWatch(); throttleMemTemp.removeWatch(); throttleProcPower.removeWatch(); throttleProcTemp.removeWatch(); } /** @brief Starts to watch how many OCCs are present on the master */ inline void addPresenceWatchMaster() { if (master()) { presence.addWatch(); } } /** @brief helper function to get the last part of the path * * @param[in] path - Path to parse * @return - Last directory name in the path */ static std::string getPathBack(const fs::path& path); private: /** @brief Config value to be used to do bind and unbind */ const std::string config; /** @brief This directory contains the error files */ const fs::path devPath; /** @brief To bind the device to the OCC driver, do: * * Write occ<#>-dev0 to: /sys/bus/platform/drivers/occ-hwmon/bind */ static fs::path bindPath; /** @brief To un-bind the device from the OCC driver, do: * Write occ<#>-dev0 to: /sys/bus/platform/drivers/occ-hwmon/unbind */ static fs::path unBindPath; /** Store the associated Status instance */ Status& statusObject; /** Abstraction of error monitoring */ Error error; /** Abstraction of OCC presence monitoring */ Presence presence; /** Error instances for watching for throttling events */ Error throttleProcTemp; Error throttleProcPower; Error throttleMemTemp; /** @brief file writer to achieve bind and unbind * * @param[in] filename - Name of file to be written * @param[in] data - Data to be written to * @return - None */ void write(const fs::path& fileName, const std::string& data) { // If there is an error, move the exception all the way up std::ofstream file(fileName, std::ios::out); file << data; file.close(); return; } /** @brief Returns if device represents the master OCC */ bool master() const; /** @brief callback for the proc temp throttle event * * @param[in] error - True if an error is reported, false otherwise */ void throttleProcTempCallback(bool error); /** @brief callback for the proc power throttle event * * @param[in] error - True if an error is reported, false otherwise */ void throttleProcPowerCallback(bool error); /** @brief callback for the proc temp throttle event * * @param[in] error - True if an error is reported, false otherwise */ void throttleMemTempCallback(bool error); }; } // namespace occ } // namespace open_power