1 #pragma once 2 3 #include "config.h" 4 5 #include "occ_errors.hpp" 6 #include "occ_events.hpp" 7 #include "occ_presence.hpp" 8 9 #include <org/open_power/OCC/Device/error.hpp> 10 11 #include <experimental/filesystem> 12 #include <fstream> 13 14 namespace open_power 15 { 16 namespace occ 17 { 18 19 class Manager; 20 class Status; 21 namespace fs = std::experimental::filesystem; 22 using namespace sdbusplus::org::open_power::OCC::Device::Error; 23 24 /** @class Device 25 * @brief Binds and unbinds the OCC driver upon request 26 */ 27 class Device 28 { 29 public: 30 Device() = delete; 31 ~Device() = default; 32 Device(const Device&) = delete; 33 Device& operator=(const Device&) = delete; 34 Device(Device&&) = default; 35 Device& operator=(Device&&) = default; 36 37 /** @brief Constructs the Device object 38 * 39 * @param[in] event - Unique ptr reference to sd_event 40 * @param[in] path - Path to the OCC instance 41 * @param[in] manager - OCC manager instance 42 * @param[in] callback - Optional callback on errors 43 */ 44 Device(EventPtr& event, const fs::path& path, const Manager& manager, 45 Status& status, std::function<void(bool)> callBack = nullptr) : 46 config(getPathBack(path)), 47 devPath(path), statusObject(status), 48 error(event, path / "occ_error", callBack), 49 presence(event, path / "occs_present", manager, callBack), 50 throttleProcTemp( 51 event, path / "occ_dvfs_overtemp", 52 std::bind(std::mem_fn(&Device::throttleProcTempCallback), this, 53 std::placeholders::_1)), 54 throttleProcPower( 55 event, path / "occ_dvfs_power", 56 std::bind(std::mem_fn(&Device::throttleProcPowerCallback), this, 57 std::placeholders::_1)), 58 throttleMemTemp(event, path / "occ_mem_throttle", 59 std::bind(std::mem_fn(&Device::throttleMemTempCallback), 60 this, std::placeholders::_1)) 61 { 62 // Nothing to do here 63 } 64 65 /** @brief Binds device to the OCC driver */ 66 inline void bind() 67 { 68 // Bind the device 69 return write(bindPath, config); 70 } 71 72 /** @brief Un-binds device from the OCC driver */ 73 inline void unBind() 74 { 75 // Unbind the device 76 return write(unBindPath, config); 77 } 78 79 /** @brief Returns if device is already bound. 80 * 81 * On device bind, a soft link by the name $config 82 * gets created in OCC_HWMON_PATH and gets removed 83 * on unbind 84 * 85 * @return true if bound, else false 86 */ 87 inline bool bound() const 88 { 89 return fs::exists(OCC_HWMON_PATH + config); 90 } 91 92 /** @brief Starts to monitor for errors 93 * 94 * @param[in] poll - Indicates whether or not the error file should 95 * actually be polled for changes. Disabling polling is 96 * necessary for error files that don't support the poll 97 * file operation. 98 */ 99 inline void addErrorWatch(bool poll = true) 100 { 101 try 102 { 103 throttleProcTemp.addWatch(poll); 104 } 105 catch (const OpenFailure& e) 106 { 107 // try the old kernel version 108 throttleProcTemp.setFile(devPath / "occ_dvfs_ot"); 109 throttleProcTemp.addWatch(poll); 110 } 111 112 throttleProcPower.addWatch(poll); 113 throttleMemTemp.addWatch(poll); 114 error.addWatch(poll); 115 } 116 117 /** @brief stops monitoring for errors */ 118 inline void removeErrorWatch() 119 { 120 // we can always safely remove watch even if we don't add it 121 presence.removeWatch(); 122 error.removeWatch(); 123 throttleMemTemp.removeWatch(); 124 throttleProcPower.removeWatch(); 125 throttleProcTemp.removeWatch(); 126 } 127 128 /** @brief Starts to watch how many OCCs are present on the master */ 129 inline void addPresenceWatchMaster() 130 { 131 if (master()) 132 { 133 presence.addWatch(); 134 } 135 } 136 137 /** @brief helper function to get the last part of the path 138 * 139 * @param[in] path - Path to parse 140 * @return - Last directory name in the path 141 */ 142 static std::string getPathBack(const fs::path& path); 143 144 /** @brief Returns true if device represents the master OCC */ 145 bool master() const; 146 147 private: 148 /** @brief Config value to be used to do bind and unbind */ 149 const std::string config; 150 151 /** @brief This directory contains the error files */ 152 const fs::path devPath; 153 154 /** @brief To bind the device to the OCC driver, do: 155 * 156 * Write occ<#>-dev0 to: /sys/bus/platform/drivers/occ-hwmon/bind 157 */ 158 static fs::path bindPath; 159 160 /** @brief To un-bind the device from the OCC driver, do: 161 * Write occ<#>-dev0 to: /sys/bus/platform/drivers/occ-hwmon/unbind 162 */ 163 static fs::path unBindPath; 164 165 /** Store the associated Status instance */ 166 Status& statusObject; 167 168 /** Abstraction of error monitoring */ 169 Error error; 170 171 /** Abstraction of OCC presence monitoring */ 172 Presence presence; 173 174 /** Error instances for watching for throttling events */ 175 Error throttleProcTemp; 176 Error throttleProcPower; 177 Error throttleMemTemp; 178 179 /** @brief file writer to achieve bind and unbind 180 * 181 * @param[in] filename - Name of file to be written 182 * @param[in] data - Data to be written to 183 * @return - None 184 */ 185 void write(const fs::path& fileName, const std::string& data) 186 { 187 // If there is an error, move the exception all the way up 188 std::ofstream file(fileName, std::ios::out); 189 file << data; 190 file.close(); 191 return; 192 } 193 194 /** @brief callback for the proc temp throttle event 195 * 196 * @param[in] error - True if an error is reported, false otherwise 197 */ 198 void throttleProcTempCallback(bool error); 199 200 /** @brief callback for the proc power throttle event 201 * 202 * @param[in] error - True if an error is reported, false otherwise 203 */ 204 void throttleProcPowerCallback(bool error); 205 206 /** @brief callback for the proc temp throttle event 207 * 208 * @param[in] error - True if an error is reported, false otherwise 209 */ 210 void throttleMemTempCallback(bool error); 211 }; 212 213 } // namespace occ 214 } // namespace open_power 215