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