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