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