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