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